target
了解国际化的意义
了解Java程序实现国际化的过程
了解如何使用SpringMVC实现国际化
1. 概述
国际化是商业软件系统的一个基本要求,因为当今的软件系统需要面对全球的浏览者。国际化的目的就是根据用户的语言环境的不同向用户输出与之相应的页面,以示友好。
程序国际化已成为 Web 应用的基本要求。随着网络的发展,大部分 Web 站点面对的已经不再是本地或者本国的浏览者,而是来自全世界各国、各地区的浏览者,因此国际化成为了 Web 应用不可或缺的一部分。
Java国际化的思想是将程序中的信息放在资源文件中,程序根据支持的国家及语言环境读取相应的资源文件。资源文件是 key-value 对,每个资源文件中的 key 是不变的,但 value 随不同国家/语言变化。
Java 程序的国际化主要通过两个类来完成。
1.1 java.util.Locale
用于提供本地信息,通常称它为语言环境。不同的语言、不同的国家和地区采用不同的 Locale 对象来表示。
1.2 java.util.ResourceBundle
该类称为资源包,包含了特定于语言环境的资源对象。当程序需要一个特定于语言环境的资源时(例如字符串资源),程序可以从适合当前用户语言环境的资源包中加载它。采用这种方式可以编写独立于用户语言环境的程序代码,而与特定语言环境相关的信息则通过资源包来提供。
为了实现 Java 程序的国际化,必须事先提供程序所需要的资源文件。资源文件的内容由很多 key-value 对组成,其中 key 是程序使用的部分,而 value 是程序界面的显示。
资源文件的命名可以有如下 3 种形式:
- baseName.properties
- baseName_language.properties
- baseName_language_country.properties
baseName 是资源文件的基本名称,由用户自由定义,但是 language 和 country 必须为 Java 所支持的语言和国家/地区代码。例如:
- 中国大陆:baseName_zh_CN.properties
- 美国:baseName_en_US.properties
Java 中的资源文件只支持 ISO-8859-1 编码格式字符,直接编写中文会出现乱码。用户可以使用 Java 命令 native2ascii.exe
解决资源文件的中文乱码问题,使用 Eclipse 编写资源属性文件,在保存资源文件时 Eclipse 自动执行 native2ascii.exe
命令,因此在 Eclipse 中资源文件不会出现中文乱码问题。
2. Java 支持的语言和国家
java.util.Locale类的常用构造方法如下:
public Locale(String language);
public Locale(String language, String country)
其中,language 表示语言,它的取值是由小写的两个字母组成的语言代码。country 表示国家或地区,它的取值是由大写的两个字母组成的国家或地区代码。
实际上,Java 并不能支持所有国家和语言,如果需要获取 Java 所支持的语言和国家,开发者可以通过调用 Locale 类的 getAvailableLocales 方法获取,该方法返回一个 Locale 数组,该数组中包含了 Java 所支持的语言和国家。
下面的 Java 程序简单示范了如何获取 Java 所支持的国家和语言:
public class Test {
public static void main(String[] args) {
// 返回Java所支持的语言和国家的数组
Locale locales[] = Locale.getAvailableLocales();
// 遍历数组元素,依次获取所支持的国家和语言
for (int i = 0; i < locales.length; i++) {
// 打印出所支持的国家和语言
System.out.println(locales[i].getDisplayCountry() + "="
+ locales[i].getCountry() + ""
+ locales[i].getDisplayLanguage() + "="
+ locales[i].getLanguage());
}
}
}
3. Java 程序的国际化
假设有如下简单 Java 程序:
public class TestI18N {
public static void main(String[] args) {
System.out.println("我要向把不同国家的人民问好:您好!");
}
}
为了让该程序支持国际化,需要将“我要向不同国家的人民问好:您好!”对应不同语言环境的字符串,定义在不同的资源文件中。
在 Web 应用的 src 目录下新建文件 messageResource_zh_CN.properties
和 messageResource_ en_US.properties
。然后给资源文件 messageResource_zh_CN.properties 添加“hello=我要向不同国家的人民问好:您好!”内容,保存后可看到如图所示的效果。
图中显示的内容看似是很多乱码,实际上是 Unicode 编码文件内容。至此,资源文件 messageResource_zh_CN.properties 创建完成。
最后给资源文件 messageResource_en_US.properties 添加“hello=I want to say hello to all world!”内容。
现在将 TestI18N.java 程序修改成如下形式:
public class TestI18N {
public static void main(String[] args) {
// 取得系统默认的国家语言环境
Locale lc = Locale.getDefault();
// 根据国家语言环境加载资源文件
ResourceBundle rb = ResourceBundle.getBundle("messageResource", lc);
// 打印出从资源文件中取得的信息
System.out.println(rb.getString("hello"));
}
}
上面程序中的打印语句打印的内容是从资源文件中读取的信息。如果在中文环境下运行程序,将打印“我要向不同国家的人民问好:您好!”。
如果在“控制面板”中将计算机的语言环境设置成美国,然后再次运行该程序,将打印“I want to say hello to all world!”。需要注意的是,如果程序找不到对应国家/语言的资源文件,系统该怎么办?
假设以简体中文环境为例,先搜索如下文件:messageResource_zh_CN.properties
如果没有找到国家/语言都匹配的资源文件,再搜索语言匹配文件,即搜索如下文件:messageResource_zh.properties
如果上面的文件还没有搜索到,则搜索 baseName 匹配的文件,即搜索如下文件:messageResource.properties
如果上面 3 个文件都找不到,则系统将出现异常。
4. 带占位符的国际化信息
在资源文件中消息文本可以带有参数,例如:
welcome={0},欢迎学习 Spring MVC。
花括号中的数字是一个占位符,可以被动态的数据替换。在消息文本中占位符可以使用 0~9 的数字,也就是说消息文本的参数最多可以有 10 个。例如:
welcome={0},欢迎学习 Spring MVC,今天是星期{1}。
如果要替换消息文本中的占位符,可以使用 java.text.MessageFormat 类,该类提供了一个静态方法 format,用来格式化带参数的文本。format 方法的定义如下:
public static String format(String pattern,Object ...arguments)
其中,pattern 字符串就是一个带占位符的字符串,消息文本中的数字占位符将按照方法参数的顺序(从第二个参数开始)被替换。
替换占位符的示例代码如下:
public class TestFormat {
public static void main(String[] args) {
// 取得系统默认的国家语言环境
Locale lc = Locale.getDefault();
// 根据国家语言环境加载资源文件
ResourceBundle rb = ResourceBundle.getBundle("messageResource", lc);
// 从资源文件中取得的信息
String msg = rb.getString("welcome");
// 替换消息文本中的占位符,消息文本中的数字占位符将按照参数的顺序
// (从第二个参数开始)被替换,即“我”替换{0}、“5”替换{1}
String msgFor = MessageFormat.format(msg, "我", "5");
System.out.println(msgFor);
}
}
Spring MVC 的国际化是建立在 Java 国际化的基础之上的,Spring MVC 框架的底层国际化与 Java 国际化是一致的,作为一个良好的 MVC 框架,Spring MVC 将 Java 国际化的功能进行了封装和简化,开发者使用起来会更加简单、快捷。
国际化和本地化应用程序时需要具备以下两个条件:
- 将文本信息放到资源属性文件中。
- 选择和读取正确位置的资源属性文件。
下面讲解第二个条件的实现。
5. Spring MVC加载资源属性文件
在 Spring MVC 中不能直接使用 ResourceBundle 加载资源属性文件,而是利用 bean(messageSource)告知 Spring MVC 框架要将资源属性文件放到哪里。示例代码如下:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleM essageSource">
<property name="basenames">
<list>
<value>/WEB-INF/resource/messages</value>
<value>/WEB-INF/resource/labels</value>
</list>
</property>
</bean>
6. 语言区域的选择
在 Spring MVC 中可以使用语言区域解析器 bean 选择语言区域,该 bean 有 3 个常见实现,即 AcceptHeaderLocaleResolver、SessionLocaleResolver 和 CookieLocaleResolver。
6.1 AcceptHeaderLocaleResolver
根据浏览器 Http Header 中的 accept-language 域设定(accept-language 域中一般包含了当前操作系统的语言设定,可通过 HttpServletRequest.getLocale 方法获得此域的内容)。
改变 Locale 是不支持的,即不能调用 LocaleResolver 接口的 setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale)方法设置 Locale。
6.2 SessionLocaleResolver
根据用户本次会话过程中的语言设定决定语言区域(例如用户进入首页时选择语言种类,则此次会话周期内统一使用该语言设定)。
6.3 CookieLocaleResolver
根据 Cookie 判定用户的语言设定(Cookie 中保存着用户前一次的语言设定参数)。
由上述分析可知,SessionLocaleResolver 实现比较方便用户选择喜欢的语言种类,教程中使用该方法进行国际化实现。
下面是使用 SessionLocaleResolver 实现的 bean 定义:
<bean id="localeResolver" class="org.springframework.web.servlet.il8n.SessionLocaleResolver">
<property name="defaultLocale" value="zh_CN"></property>
</bean>
如果采用基于 SessionLocaleResolver 和 CookieLocaleResolver 的国际化实现,必须配置 LocaleChangeInterceptor 拦截器,示例代码如下:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.il8n.LocaleChangeInterceptor"/>
</mvc:interceptors>
7. 使用 message 标签显示国际化信息
在 Spring MVC 框架中可以使用 Spring 的 message 标签在 JSP 页面中显示国际化消息。在使用 message 标签时需要在 JSP 页面的最前面使用 taglib 指令声明 spring 标签,代码如下:
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
message 标签有以下常用属性。
- code:获得国际化消息的 key。
- arguments:代表该标签的参数。如果替换消息中的占位符,示例代码为
<spring:message code="third" arguments="888,999" />
,third 对应的消息有两个占位符 {0} 和 {1}。 - argumentSeparator:用来分隔该标签参数的字符,默认为逗号。
- text:code 属性不存在,或指定的 key 无法获取消息时所显示的默认文本信息。
8. 实例
Spring MVC也可以允许用户自行选择程序语言。通过 Web 应用 SpringMVC-13 演示用户自定义切换语言,在该应用中使用 SessionLocaleResolver 实现国际化,具体步骤如下:
8.1 创建应用
创建应用 SpringMVC-13,并导入 SpringMVC 相关的 JAR 包。
8.2 创建国际化资源文件
在 WEB-INF/resource 目录下创建中英文资源文件 messages_en_US.properties 和 messages_zh_CN.properties。
messages_en_US.properties 的内容如下:
first=first
second=second
third={0} third{1}
language.en=English
language.cn=Chinese
messages_zh_CN.properties 的内容如下:
first=\u7B2C\u4E00\u9875
second=\u7B2C\u4E8C\u9875
third={0} \u7B2C\u4E09\u9875 {1}
language.cn=\u4E2D\u6587
language.en=\u82F1\u6587
8.3 创建视图 JSP 文件
在 WEB-INF/views 目录下创建 3 个 JSP 文件,即 first.jsp、second.jsp 和 third.jsp。
first.jsp 的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="${pageContext.request.contextPath }/my/first?locale=zh_ CN">
<spring:message code="language.cn" /> </a>
<a href="${pageContext.request.contextPath }/my/first?locale=en_US">
<spring:message code="language.en" /> </a>
<br>
<spring:message code="first" />
<br>
<a href="${pageContext.request.contextPath }/my/second">
<spring:message code="second" />
</a>
</body>
</html>
second.jsp 的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<spring:message code="second"/><br><br>
<a href="${pageContext.request.contextPath }/my/third">
<spring:message code="third" arguments="888,999"/>
</a>
</body>
</html>
third.jsp 的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="${pageContext.request.contextPath }/my/first">
<spring:message code="first" />
</a>
<br>
<spring:message code="third" arguments="888,999" />
</body>
</html>
8.4 创建控制器类
MyController 的代码如下:
@Controller
@RequestMapping("/my")
public class MyController {
@RequestMapping("/first")
public String first() {
return "first";
}
@RequestMapping("/second")
public String second() {
return "second";
}
@RequestMapping("/third")
public String third() {
return "third";
}
}
8.5 创建配置文件
在 src 目录下创建配置文件 springmvc.xml, 在 WEB-INF 目录下创建 web.xml。web.xml 的代码与 Spring MVC 简单应用的相同,这里不再赘述。springmvc.xml 的代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 使用扫描机制扫描包 -->
<context:component-scan base-package="com.lee.controller" />
<!-- 配置视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 国际化操作拦截器,如果采用基于Session/Cookie则必须配置 -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>
<!-- 存储区域设置信息 -->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="zh_CN"></property>
</bean>
<!-- 加载国际化资源文件 -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- <property name="basename" value="classpath:messages" /> -->
<property name="basename" value="/WEB-INF/resource/messages" />
</bean>
</beans>
8.6 发布应用并测试
首先将 springMVCDemo09 应用发布到 Tomcat 服务器并启动 Tomcat 服务器,然后访问:http://localhost:8080/springMVC-13/my/first