国际化、本地化及Spring MVC 的设计
本文不讲述具体使用配置过程。。请先google了解需要配置的三个地方。。
一、概述:
各个框架对于国际化和本地化的支持方式都类似,从用户使用角度大致分为以下两步:
1、准备资源文件,比如:message.xml,message_zh_CN.xml,message_zh_TW.xml,当然properties 文件也是一样了,里面核心的内容是key1=value1,
2、在页面使用宏、标签等展示内容;比如:#springMessage("key");然后通过不同环境加载不同的文件获取不同value,实现本地化;
框架要做的事情:
1、判断应该使用哪一个资源文件,
2、提供宏,从对应的资源文件中获取对应的value;
先说怎么判断使用哪一个资源文件;判断的根本来源是什么?是客户,不同地区的客户使用不同的资源,或者客户主动要求使用哪一种资源(手动切换语言)。接下去客户怎么告诉我?
最简单的方式是每一次请求,客户都告诉我需要什么类型的语言,显然这是最简单的方式,也意味这是最不可取的方式;为什么呢?一是繁琐,二是一旦某一次忘了就不知所措了;
第二种:第一次来,你告诉我,以后除非你明确改变,我都用第一次的;明确改变以后使用改变后的;这里根据第一次适用的范围不同又分为两种,一是从浏览器打开到关闭作为一个生命周期,下一次打开作为新的第一次;二是第一次进入网站后,后面都算第二次,当然这个“永远”是相对的,比如cookie清理,永远就失效了。
第三种,第一次来,你也不用告诉我,我可以根据你的区域默认给你,如果不满意,你在替换;第一次怎么来默认?那就是 httpServletRequest.getLocale()这个方法了,看一下定义:
getLocale Locale getLocale() Returns the preferred Locale that the client will accept content in, based on the Accept-Language header. If the client request doesn't provide an Accept-Language header, this method returns the default locale for the server. Returns: the preferred Locale for the client
很明显这个是优先使用HTTP请求中的 Accept-Language这个头信息来设置的,chrome看一下内容如下:
如果想进一步这个参数的意义,是怎么来的,怎么修改参考下面资源:
http://www.ietf.org/rfc/rfc1766.txt
http://man.chinaunix.net/newsoft/Apache2.2_chinese_manual/content-negotiation.html
http://blogs.msdn.com/b/ie/archive/2006/10/17/accept-language-header-for-internet-explorer-7.aspx
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_08tg.asp
能区分之后,怎么和文件关联,自然就是文件名了,zh_CN、zh_TW 这样的,为什么是这样的,其他的可不可以,请看下面:
二、从Locale类说起:
查看代码这个类做了很多事情,核心是依赖sun的BaseLocale类,我们只关注前面一长窜的常量定义:
/** Useful constant for language. */ static public final Locale ENGLISH = createConstant("en", ""); /** Useful constant for language. */ static public final Locale FRENCH = createConstant("fr", ""); /** Useful constant for language. */ static public final Locale CHINESE = createConstant("zh", ""); /** Useful constant for language. */ static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN"); /** Useful constant for language. */ static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW"); /** Useful constant for country. */ static public final Locale FRANCE = createConstant("fr", "FR"); /** Useful constant for country. */ static public final Locale CHINA = SIMPLIFIED_CHINESE; /** Useful constant for country. */ static public final Locale PRC = SIMPLIFIED_CHINESE; /** Useful constant for country. */ static public final Locale * = TRADITIONAL_CHINESE;
看到这里应该明白了,这里定义了主要的常用的语言和国家,而zh,CN,TW 也都能一一对应;
纵观上面,一言蔽之,就是在请求来的时候,通过参数也好、httpServletRequest.getLocale()也好获取当次请求的Locale,其后定位文件,获取对应的文案;不同的是Locale的值怎么存放的问题;
三、springMVC的实现:
先看一下核心类:
由于大部分请求都需要设置locale,很自然想到filter实现,在springmvc中是使用LocaleChangeInterceptor 类来实现的,该类只有一个方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException { String newLocale = request.getParameter(this.paramName); if (newLocale != null) { LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request); if (localeResolver == null) { throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?"); } LocaleEditor localeEditor = new LocaleEditor(); localeEditor.setAsText(newLocale); localeResolver.setLocale(request, response, (Locale) localeEditor.getValue()); } // Proceed in any case. return true; }
逻辑也很简单从request中获取 locale 参数,设置到当前的LocaleResolver中。
在springmvc 一种提供四种LocaleResolver,分别是SessionLocaleResolver、CookieLocaleResolver、AcceptHeaderLocaleResolver、 FixedLocaleResolver ,都实现了LocaleResolver接口;
Locale resolveLocale(HttpServletRequest request); void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale);
提供设置locale、和读取locale的方法,在set方法中根据策略不同设置到不同的位置,比如session,就放到session中,cookie就放到cookie中,但是AcceptHeaderLocaleResolver、FixedLocaleResolver 这两个类的set方法是直接跑出异常“Cannot change fixed locale - use a different locale resolution strategy”,如果使用他们,一定要重写该方法
读取的方法逻辑相对复杂一点,比如session策略,会先读取session,没有读取默认值、没有再从request中获取。cookie也类似,而AcceptHeaderLocaleResolver只从request中获取,FixedLocaleResolver 则只获取默认值。可以根据不同的应用场景使用不同的方案;
另外LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request); 这句可能比较困惑,这里只是获取,那里放进去的呢?在DispatcherServlet 这个类的doService()方法中可以看到 request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver),同样localeResolver是在initLocaleResolver() 方法中设置的,这里如果用户没有配置,会设置默认值;
涉及类图如下:
最后再来看页面的使用,以常用的模板语言velocity为例。事实上支持很多,ftl等,先看对应的类
以vm为例,在使用时,需要只需要使用spring.vm中提供的宏,以最简单的宏为例
#macro( springMessageText $code $text )$springMacroRequestContext.getMessage($code, $text)#end
springMacroRequestContext 这个变量在类 AbstractTemplateView 能找到放入content的地方 model.put(SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE, new RequestContext(request, model));也就是说实际上就是RequestContext类,看这个的getMessage方法:
public String getMessage(String code, Object[] args, String defaultMessage, boolean htmlEscape) { String msg = this.webApplicationContext.getMessage(code, args, defaultMessage, this.locale); return (htmlEscape ? HtmlUtils.htmlEscape(msg) : msg); }
可以看到实际上是使用webApplicationContext去获取资源了;而我们在具体使用的时候需要配置messagesource,如:
- <!-- 资源文件绑定器 -->
- <bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">
- <property name="basename" value="message-info" />
- <property name="useCodeAsDefaultMessage" value="true" />
- </bean>
其中,message-info是你的properties文件的通用名。如:message-info.properties,message-info_zh_CN.properties等等。
我们知道webApplicationContext是实现了message相关接口的。至于这里面怎么去获取文件的。。待下会分解。。
本站支持 pay for your wishes
推荐阅读
-
spring boot与spring mvc的区别及功能介绍
-
spring boot与spring mvc的区别及功能介绍
-
网站国际化实现(2)—Spring MVC国际化实现及原理
-
Spring MVC配置及拦截器的实现
-
我是如何进行Spring MVC文档翻译项目的环境搭建、项目管理及自动化构建工作的 七牛自动化jenkinsSpring MVCgithub
-
国际化、本地化及Spring MVC 的设计
-
Spring技术内幕——深入解析Spring架构与设计原理(四)Web MVC的实现
-
网站国际化实现(2)—Spring MVC国际化实现及原理
-
Spring MVC拦截器(Interceptor)的配置及使用
-
Spring技术内幕——深入解析Spring架构与设计原理(四)Web MVC的实现