SpringMVC对资源国际化的支持

1、资源国际化开发

1.1 什么是资源国际化?

       软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据。国际化(internationalization)又称为 i18n(读法为i 18 n,据说是因为internationalization(国际化)这个单词从i到n之间有18个英文字母,i18n的名字由此而来)

1.2 国际化的基本规则

       国际化信息”也称为“本地化信息”,一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是“语言类型”“国家/地区的类型”。如中文本地化信息既有中国大陆地区的中文,又有中国台湾、中国香港地区的中文,还有新加坡地区的中文。Java通过java.util.Locale类表示一个本地化对象,它允许通过语言参数和国家/地区参数创建一个确定的本地化对象。

       语言参数使用ISO标准语言代码表示,这些代码是由ISO-639标准定义的,每一种语言由两个小写字母表示。在许多网站上都可以找到这些代码的完整列表,下面的网址是提供了标准语言代码的信息:http://www.loc.gov/standards/iso639-2/php/English_list.php。

       国家/地区参数也由标准的ISO国家/地区代码表示,这些代码是由ISO-3166标准定义的,每个国家/地区由两个大写字母表示。用户可以从以下网址查看ISO-3166的标准代码:
http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html。下面是常用的国家/地区语言参数:

2、资源国际化简单示例

编写国际化资源文件:国际化资源文件就是用一种key-value的形式把要显示的信息的不同语言的翻译版本写到properties资源文件中。
(1)英文的资源文件

login_en_US.properties:
welcomeInfo=Welcome to my personal blog LoveITer
username=USERNAME
password=PASSWORD
loginbtn=LOGIN
placeholder_username=please input username
placeholder_password=please input password

(2)简体中文的资源文件

login_zh_CN.properties
welcomeInfo=欢迎访问我的个人博客LoveITer
username=用户名
password=密码
loginbtn=登录
placeholder_username=请输入用户名
placeholder_password=请输入密码

注意:一般情况下我们用*._zh_CN.properties表示中文资源文件,*.properties表示默认的资源文件。

在springmvc配置文件中简单的配置一下,把我们的资源文件交给SpringMVC管理

  <!--配置国际化资源文件-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename" value="login"/>
</bean>

编写一个用户登录表单

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>

<h3><fmt:message key="welcomeInfo"/></h3>
<form action="checkLogin" method="post" >
    <table>
        <tr><th><fmt:message key="username"/></th><td><input type="text" placeholder="<fmt:message key='placeholder_username'/>"/></td></tr>
        <tr><th><fmt:message key="password"/></th><td><input type="password" placeholder="<fmt:message key='placeholder_password'/>"/></td></tr>
        <tr><th><input type="submit" value="<fmt:message key="loginbtn"/>"/></th></tr>
    </table>
</form>

</body>
</html>

上面的代码中用到了JSTL中的fmt标签<fmt:message>,因此需要导入对应的jar包。

测试结果
我的浏览器默认就是中文,因此显示的就是中文的欢迎信息:

在火狐浏览器中手动更改语言为英文

英文环境下就显示的是英文信息:

3、资源文件的编码问题

       一般我们采用properties文件来保存资源文件。properties文件是以key-value的形式来保存文件的。login_zh_CN.properties中保存的是经过utf-8编码字后的ASCII字符,Unicode字符中不允许出现中文、日文等其他字符的文字。但是Unicode编码后的文字阅读起来比较困难,在IDEA中,可以在File->Settings->Editor->File Encodings设置中勾选Transparent native-to-ascii conversion,如下图,设置好后点击Apply,然后回到刚才编写的中文资源文件发现中文字符全部乱码了,这时可以在编辑器中直接重新输入中文。虽然我们输入的是中文,但是IDEA已经帮我们做了中文转码。

4、在程序中获取国际化信息

在程序中我们可以通过ResourceBundleMessageSource来获取资源文件的信息:

package com.xust.iot.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Locale;

@Controller
public class UserController {

@Autowired
private MessageSource messageSource;

/**
 * SpringMVC会自动把locale信息注入
 * @param locale
 * @return
 */
@RequestMapping("/toLogin")
public String logIn(Locale locale) {

	System.out.println(locale);
	String welcomeInfo=messageSource.getMessage("welcomeInfo",null,locale);
	String userName=messageSource.getMessage("username",null,locale);
	String password=messageSource.getMessage("password",null,locale);
	System.out.println(welcomeInfo+"----"+userName+"----"+password);
	return "login";
}

}

执行结果:
可以看到在不同对语言环境下使用了不同的资源文件。

5、自定义区域信息解析器

3个步骤

1、写一个类实现LocaleResolver接口或他的子接口或继承他的实现类,最主要是要实现它的resolveLocale方法
2、在springmvc的配置文件中注册自定义的区域信息解析器
3、启动测试

(1)写一个类实现LocalResolver接口

package com.xust.iot.LocaleResolver;

import net.sf.cglib.core.Local;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

public class MyLocaleResolver implements LocaleResolver {

/**
 * 解析locale信息
 * @param request
 * @return
 */
@Override
public Locale resolveLocale(HttpServletRequest request) {

	Locale locale=null;
	//通过请求解析请求参数中的locale来让用户可以根据自己的习惯选择语言
	String localeStr=null!=request.getParameter("locale")?request.getParameter("locale"):"";
	if(!"".equals(localeStr)){
		locale=new Locale(localeStr.split("_")[0],localeStr.split("_")[1]);
	}else{
		locale=request.getLocale();
	}
	return locale;
}

@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

}
}

(2.1)在springmvc的配置文件中注册自定义的区域信息解析器

<!--自定义区域信息解析器-->
<bean id="localeResolver" class="com.xust.iot.LocaleResolver.MyLocaleResolver"/>

注意:解析器的id必须是localeResolver,如果写错了就没有效果了。至于为啥非要这么写请参考SpringMVC源码中的DispatcherServlet这个类。

(2.2)在页面中加入可以切换语言的链接

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>

<h3><fmt:message key="welcomeInfo"/></h3>
<form action="checkLogin" method="post" >
    <table>
        <tr><th><fmt:message key="username"/></th><td><input type="text" placeholder="<fmt:message key='placeholder_username'/>"/></td></tr>
        <tr><th><fmt:message key="password"/></th><td><input type="password" placeholder="<fmt:message key='placeholder_password'/>"/></td></tr>
        <tr><th><input type="submit" value="<fmt:message key="loginbtn"/>"/></th></tr>
    </table>
</form>
<a href="toLogin?locale=zh_CN"><fmt:message key="Chinese"/></a>|
<a href="toLogin?locale=en_US"><fmt:message key="English"/></a>
</body>
</html>

(3)测试

6、SessionLocaleResolver

从SpringMVC的区域信息的继承图中我么看到了几个特别的区域信息解析器:
1. AcceptHeaderLocaleResolver:它是SpringMVC默认装配的区域信息解析器,他会默认从 accept-language请求头信息进行解析处理,通常这个头信息包含客户端操作信息的本地标示。它不支持通过链接的方式改变locale信息。
2. FixedLocaleResolver:从字面意思就可以知道,这也是一个不支持通过链接的方式改变locale信息的一个解析器,它默认会从操作系统拿locale信息。
3. SessionocaleResolver:从session中拿locale信息,允许设置区域信息。
4. CookieLocaleResolver:从Cookie中拿locale信息,允许设置区域信息。

下面我们借助SessionLocaleResolver来实现我们上面自定义区域信息解析器的功能:

package com.xust.iot.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import javax.servlet.http.HttpSession;
import java.util.Locale;

@Controller
public class UserController {

@Autowired
private MessageSource messageSource;

@RequestMapping("/toLogin")
public String logIn(
		@RequestParam(value = "locale",defaultValue = "zh_CN") String localeStr,
		Model model,
		Locale locale,
		HttpSession session) {

	Locale l=null;
	if(null!=localeStr&&!"".equals(localeStr)){
	   l=new Locale(localeStr.split("_")[0],localeStr.split("_")[1]);
	}else{
		l=locale;
	}

	session.setAttribute(SessionLocaleResolver.class.getName() + ".LOCALE",l);
	return "login";
}

}

测试结果:

7、使用LocaleChangeInterceptor

通过配置LocaleChangeInterceptor,我们可以动态改变本地语言。它会检测请求中的参数并且改变地区信息。它调用LoacalResolver.setLocal()进行配置。

既然是拦截器,要使用他就需要在springmvc配置文件中配置它,配置也很简单:

<mvc:interceptors>
   <bean id="localeChangeInterceptor"  class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>

然后在配合SessionLocaleResovler,实现动态的改变本地信息

<!--SessionLocaleResolver-->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>

<!--资源国际化拦截器-->
<mvc:interceptors>
	<bean id="localeChangeInterceptor"  class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>

控制器层的代码瞬间变得极其简单,就一个跳转页面对返回语句


@Controller
public class UserController {

@RequestMapping("/toLogin")
public String logIn() {
	return "login";
}

}

测试结果:

留言区

还能输入500个字符