# 国际化
# 基本概念
国际化 是开发支持多语言和数据格式的应用程序的技术,无需重新编写编程逻辑。国际化单词 internationlization 常缩写为 i18n
。
本地化 这是将国际化应用程序改成支持特定 语言区域 (locale)的技术。语言区域是指一个特定的地理、政治或文化区域。会影响到文字、时间日期格式等的形式。
在 Java 中,java.util.Locale
类表示一个语言区域。一个 Locale 对象主要包含 2 个主要概念:language
(语言) 和 country
(国家)。为此 国家化标准组织 专门制定了 ISO 639
标准(用于标识语言)和 ISO 3166
标准(用于标识国家)。
SpringMVC 的国际化问题,就是回答两个问题:
- 提供资源文件在哪里?(以及如何加载?)
- 如何获得 Locale 对象?(以决定使用哪个资源文件)
- 如何加载某个地方的资源文件,常见有两种途径。
- 如何获得 Locale 对象,有三种途径。
使用国际化功能,再次强调,不要直接访问 JSP 页面,而是通过 Controller “转到” JSP 页面,因为 JSP 页面的显示,需要 Spring MVC 做一些准备工作,一旦“绕过”Controller,导致“准备工作”不充分会造成 JSP 页面无法正常显示。
# 指明(并加载)资源文件
资源文件有固定的命名规则:有一个任意的基准名,后面再接下划线、语言码,还可以选择加一条下划线和国家码。如:
- messages_zh_CN.properties
- messages_en_US.properties
- messages_de_DE.properties
这里 基准名 是代表这一系列文件的标志,后续所使用的“文件名”或“文件路径名”的概念,通常都只算到 基准名 部分位置。
在 Spring MVC 中,通过配置 ReloadableResourceBundleMessageSource
类,或 ResourceBundleMessageSource
类来查找/加载上述资源文件。
<bean id="messageSource" class="
org.springframework.context.support .ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:message</value> <!-- 需要使用 classpath 关键字 -->
</list>
</property>
</bean>
<bean id="messageSource" class="
org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>message</value> <!-- 不需要使用 classpath 关键字 -->
</list>
</property>
</bean>
以上两个类二选一,让 Spring 容器去创建其中一个的单例对象即可。对它们两个的配置,就相当于实现了国际化的第一步:告诉 Spring MVC 资源文件在哪 。
# 获得 Locale 对象
在第一步工作告知 Spring MVC 资源文件在什么地方后,Spring MVC 需要考虑的就是如果获取 Locale 对象,以决定使用“一堆”资源文件中的哪一个。
Spring MVC 有三种方式获得 Locale 对象:
- AcceptHeaderLocaleResolver,从 Http 请求头中获取
- SessionLocaleResolver,从 Session 对象中获取
- CookieLocaleResolver,从 Cookie 对象中获取
注意
,以上三种途径是互斥的,期望采用那种途径,就让 Spring 去创建/维护这个类的一个单例对象。且名字必须为 localeResolver
。
# AcceptHeaderLocaleResolver
AcceptHeaderLocaleResolver 是 Spring MVC 默认的区域解析器,它会在 HTTP 请求的 accept-language 头部查找 Locale 信息,并以此决定使用哪个资源文件。
这个头部是由用户的web浏览器根据底层操作系统的区域设置进行设定。
# SessionLocaleResolver
AcceptHeaderLocaleResolver 它会从当前请求的 Session 中查找Locale信息,如果 Session 中没有,那么它会根据 accept-language 头部信息确定区域信息。
<bean id="localeResolver" class="org.springframewrok.web.servlet
.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
# CookieLocaleResolver
CookieLocaleResolver 它会从请求的 cookie 中查找 Locale 信息,如果 cookie 中没有,那么它会根据 accept-language 头部信息确定区域信息。
这个区域解析器所采用的 Cookie 可以通过 cookieName 和 cookieMaxAge 属性进行定制。cookieMaxAge 属性表示这个 Cookie 应该持续多少秒,-1表示这个 Cookie 在浏览器关闭之后就失效。
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="cookieName" value="language"/>
<property name="cookieMaxAge" value="3600"/>
<property name="defaultLocale" value="en"/>
</bean>
# 修改 Locale 信息
# 非常规办法
如果使用的是 AcceptHeaderLocaleResolver
,那么需要修改用户的浏览器设置,以实现locale信息的修改。
如果使用的是 SessionLocaleResolver
或 CookieLocaleResolver
,可以在代码中通过显示调用 LocaleResolver.setLocale()
来修改客户端的 locale 信息,并且该信息会存储于 Session,或 Cookie 中。但这不是首选方案。
# 常规办法: LocaleChangeInterceptor 拦截器
Spring MVC 提供了 LocaleChangeInterceptor
拦截器,该拦截器会发现当前 HTTP 请求中出现的 特殊参数 。如果这种参数出现在当前请求中,拦截器就会根据参数值来改变用户的区域。
<mvc:interceptors>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang"/>
</bean>
</mvc:interceptors>
http://localhost:8080/court/welcome.do?lang=en_US
http://localhost:8080/court/welcome.do?lang=zh_CN