很多网站的用户分布在世界各地,因此网站需要针对不同国家的用户展示不同语言的内容,因此就有了国际化实现的需求,大多数网站都会在网站的头部或尾部设置语言切换链接,这样就可以直接切换成相应的内容。
国际化实现步骤
1.基于不同的语言定义多个properties文件,用于后面根据本地化信息从相应的properties文件中获取数据。
这里我实现的是简体中文和英文的切换,所以定义了两个properties文件,这两个文件均在根目录下
language_en_US.properties
language.cn = \u4e2d\u6587 language.en = English internationalisation = \u0020Internationalisation welcome = This is the English environment introduce= This is I18N Demo
language_zh_CN.properties
language.cn = \u4e2d\u6587 language.en = English internationalisation = \u56fd\u9645\u5316 welcome = \u8fd9\u662f\u4e2d\u6587\u73af\u5883 introduce= \u8fd9\u662f\u56fd\u9645\u5316\u7684\u4e8b\u4f8b
2.编辑Spring配置文件,在原有基础上添加国际化资源文件和本地化信息
<!-- 获取数据 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- 表示多语言配置文件在根路径下,以language开头的文件 --> <property name="basename" value="classpath:language" /> <property name="useCodeAsDefaultMessage" value="true" /> </bean> <!-- 获取本地化信息 --> <mvc:interceptors> <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> <property name="paramName" value="lang" /> </bean> </mvc:interceptors> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />
3.测试
(1)新建一个controller,用于跳转到指定的国际化测试页面
@Controller public class Test1 { @RequestMapping("/hello.action") public String index() { System.out.println("进入hello.action"); return "content/hello.jsp"; } }
(2)新建hello.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@taglib prefix="spring" uri="http://www.springframework.org/tags" %> <html> <head> <title>SpringMVC<spring:message code="internationalisation"/></title> </head> <body> Language: <a href="?lang=zh_CN"><spring:message code="language.cn"/></a> <a href="?lang=en_US"><spring:message code="language.en"/></a> <h1> <spring:message code="welcome"/> </h1> 当前语言: ${pageContext.response.locale } </body> </html>
访问hello.action地址,跳转到hello.jsp页面
案例参考至:https://blog.csdn.net/u013360850/article/details/70860144/
国际化实现原理
分为三大步
(1)本地化信息获取
(2)数据获取
(3)格式化
下面分别来解释下这三步分别实现的功能。
(1)本地化信息获取
Spring MVC的DispatcherServlet类会在initLocaleResolver方法中查找一个locale resolver,如果没有找到就会用默认的AcceptHeaderLocaleResolver类。locale resolver会去根据请求Request设置当前的locale信息。除了resolver类,还可以定义拦截器去设置locale信息。
AcceptHeaderLocaleResolver
解析request的header中的accept-language值,这个值通常包含客户端支持的本地化信息,通过这个值可以获取本地化信息。
CookieLocaleResolver
通过cookie去存取本地化信息,客户端可以在cookie中存储一个指定名字的值代表本地化信息,然后这个类获取后做相应的解析即可。SessionLocaleResolver
通过request获取本地化信息,然后存在HttpSession中,由此可以看出本地化信息存取依赖于session的生命周期。LocaleChangeInterceptor
这个拦截器会拦截请求中的参数,然后根据参数去调用LocaleResolver的setLocale()方法,改变当前的locale值。
在案例中,使用的就是这种方式来获取本地化信息,那为什么我们要配置localeResolver这个bean呢?
因为LocaleChangeInterceptor需要调用LocaleResolver的setLocale()方法,这里面用到了CookieLocaleResolver,当然也可以用其他的LocaleResolver实现类。
LocaleChangeInterceptor类中的preHandler()方法
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException { String newLocale = request.getParameter(getParamName()); if (newLocale != null) { if (checkHttpMethod(request.getMethod())) { LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request); if (localeResolver == null) { throw new IllegalStateException( "No LocaleResolver found: not in a DispatcherServlet request?"); } try { localeResolver.setLocale(request, response, parseLocaleValue(newLocale)); } catch (IllegalArgumentException ex) { if (isIgnoreInvalidLocale()) { logger.debug("Ignoring invalid locale value [" + newLocale + "]: " + ex.getMessage()); } else { throw ex; } } } }(2)数据获取
得到本地化信息后,就可以从相应的properties文件中获取Spring MVC的数据处理定义了一个接口MessageSource,该接口定义了数据获取的方法。方法如下:
■ String getMessage(String code, Object[] args, String defaultMessage, Locale locale)
这里code为属性文件中的key值,args是文件中需要替换的参数值,defaultMessage是找不到内容时的默认内容,locale为本地化信息。
■ String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
这个方法与上面的方法类似,只是没有了默认内容,而是找不到内容时抛出异常。
■ String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
这里参数中有个新接口MessageSourceResolvable,对前面的参数进行了封装,locale为本地化信息。
(3)格式化
第(2)步已经获取到了数据,有些时候数据获取到之后可以直接展示,但是如果涉及到时间、数字、金额、动态文本等数据时,又需要额外做下处理了,因为本身这些数据就是本地化敏感的,这时就需要对相应的数据进行格式化操作。
第(2)步已经获取到了数据,有些时候数据获取到之后可以直接展示,但是如果涉及到时间、数字、金额、动态文本等数据时,又需要额外做下处理了,因为本身这些数据就是本地化敏感的,这时就需要对相应的数据进行格式化操作。
数字与金额:使用DataFormate类进行处理;DecimalFormatele类,小数的格式化处理
时间与日期:SimpleDateFormate类和DateTimeFormatter类
文本:MessageFormate类