欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

国际化、本地化及Spring MVC 的设计

程序员文章站 2022-05-09 14:24:20
...

本文不讲述具体使用配置过程。。请先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看一下内容如下:

Accept-Language:
zh-CN,zh;q=0.8
 

如果想进一步这个参数的意义,是怎么来的,怎么修改参考下面资源:

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的实现:

 

先看一下核心类:


国际化、本地化及Spring MVC 的设计
            
    
    博客分类: Spring 国际化本地化Spring MVC

由于大部分请求都需要设置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() 方法中设置的,这里如果用户没有配置,会设置默认值;

 

 涉及类图如下:


国际化、本地化及Spring MVC 的设计
            
    
    博客分类: Spring 国际化本地化Spring MVC

 

最后再来看页面的使用,以常用的模板语言velocity为例。事实上支持很多,ftl等,先看对应的类

 


国际化、本地化及Spring MVC 的设计
            
    
    博客分类: Spring 国际化本地化Spring MVC

以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,如:

 

  1. <!-- 资源文件绑定器 -->           
  2. <bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">                   
  3. <property name="basename" value="message-info" />                 
  4. <property name="useCodeAsDefaultMessage" value="true" />         
  5. </bean>   

其中,message-info是你的properties文件的通用名。如:message-info.properties,message-info_zh_CN.properties等等。

我们知道webApplicationContext是实现了message相关接口的。至于这里面怎么去获取文件的。。待下会分解。。

 

 

本站支持 pay for your wishes

  • 国际化、本地化及Spring MVC 的设计
            
    
    博客分类: Spring 国际化本地化Spring MVC
  • 大小: 24.3 KB
  • 国际化、本地化及Spring MVC 的设计
            
    
    博客分类: Spring 国际化本地化Spring MVC
  • 大小: 37.8 KB
  • 国际化、本地化及Spring MVC 的设计
            
    
    博客分类: Spring 国际化本地化Spring MVC
  • 大小: 50.3 KB

上一篇: bug2

下一篇: bug2