1. 国际化与本地化
程序国际化已成为Web应用的基本要求。随着网络的发展,大部分的Web站点面对的已经不再是本地或者本国的浏览者,而是来自全世界各国各地区的浏览者,因此国际化成为了Web应用不可或缺的一部分。
国际化Internationalization是使程序在不做任何修改的情况下,就可以在不同的国家或地区和不同的语言环境下,按照当地的语言和格式习惯显示字符。例如,一个数字123456.78,在法国它的书写格式是123 456,78,在德国是123.456,78,而在美国则是123,456.78。
国际化又被称为I18N,因为国际化的英文是Internationalization,它以I开头,以N结尾,中间有18个字母。
一个国际化的程序,当它运行在本地机器时,需要根据本地机器的语言和地区设置显示相应的字符,这个过程就叫做本地化(Localization),通常简称为:L10N。
2. java国际化
在JAVA中编写国际化程序主要通过两个类来完成:java.util.Locale类和java.util.ResourceBundle抽象类。
1) Locale类用于提供本地信息,通常称它为语言环境。不同的语言,不同的国家和地区采用不同的Locale对象来表示。
2) ResourceBundle类称为资源包,包含了特定于语言环境的资源对象。当程序需要一个特定于语言环境的资源时(如字符串资源),程序可以从适合当前用户语言环境的资源包中加载它。采用这种方式,可以编写独立于用户语言环境的程序代码,而与特定语言环境相关的信息则通过资源包来提供。
Java.util.Locale类的常用构造方法如下:
1) public Locale(String language)
2) public Locale(Stringlanguage,String country)
其中language表示语言,它的取值是由ISO-639定义的小写的、两个字母组成的语言代码。
其中country表示国家或地区,它的取值由ISO-639定义的大写的、两个字母组成的代码
左表列出了常用的ISO-639语言代码。右表列出了常用的ISO-3166国家和地区
最理想的实现国际化的方法是将要显示的字符内容从程序中分离,然后统一存储到一个资源包中,当显示时,从资源包中取出和Locale对象相一致的字符内容。在Java中,这种资源包是由类来实现的,这个类必须要扩展java.util.ResourceBundle.
在编写国际化程序时,要为不同的国家地区和语言编写不同的资源类,这些资源类同属一个资源系列,共享同一个基名(base name).不同语言所对应的资源类的名称为基名加上ISO-639标准的语言代码,而应用于某个特定国家或地区的资源类的名称,则是在基名和语言代码后加上ISO-3166标准的同家或地区代码。
资源文件的命名规则是非常重要的,其分为如下三种形式:
• 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编码格式字符,直接编写中文会出现乱码。
方法:
• 使用native2ascii.exe命令;
• 安装专门的属性编辑插件:
• PropertiesEditor插件
• JInto插件
• jp.gr.java_conf.ussiy.app.propedit插件
在资源文件中的消息文本可以带有参数,例如:
greeting={0},欢迎学习struts2.
花括号中的数字是一个占位符,可以被动态的数据替换。在消息文本中的占位符可以使用0到9的数字,也就是说,消息文本的参数最多可以有10个。例如:
greeting={0},欢迎学习struts2,今天是星期{1}.
要替换消息文本中的占位符,可以使用java.text.MessageFormat类,该类提供了一个静态方法format(),用来格式化带参数的文本,format()方法定义如下:
public staticString format(String pattern,Object …arguments)
示例
greeting={0},欢迎学习struts2,今天是星期{1}.
我们编写代码:
Locale loc = Locale.getDefault(); ResourceBundle bundle = ResourceBundle.getBundle(“MyResource”,loc); String greeting = bundle.getString(“greeting”); Object[] obj = {"张三",new java.util.Date()}; String msg = MessageFormat.format(greeting,obj); |
消息文本中的数字占位符将按照MessageFormat.format()方法参数的顺序(从第二个参数开始)而被替换,在上例中,占位符{0}被“张三”替换,{1}被newjava.util.Date()所替换。此外format()方法参数的顺序是与占位符的数字顺序对应的,而不是与占位符出现在消息文本中的顺序对应。
3. Struts2对国际化的支持
Struts2的国际化是建立在Java国际化的基础之上的,是使用资源包的方式,通过getBundle()方法来寻找指定Locale相关联的资源包,再从资源包文件中查找指定Key所对应的国际化资源信息。
Struts2框架的底层国际化与Java国际化是一致的,作为一个良好的MVC框架,Struts2将Java的国际化功能进行了封装和简化,开发者使用起来会更加简单快捷。
3.1. 资源文件
资源文件分为以下几种:
1) Action范围资源文件:在Action类文件所在的路径建立名为ActionName_language_country.properties的文件
2) 包范围资源文件:在包的根路径下建立文件名为package_language_country.properties的属性文件,一旦建立,处于该包下的所有Action都可以访问该资源文件。注意:包范围资源文件的 baseName就是package,不是Action所在的包名。
3) 全局资源文件
i. 命名方式如下:basename_语言_国家.properties,保存目录为src目录下。
ii. 当准备好资源文件之后,我们可以在struts.xml中通过struts.custom.i18n.resources常量把资源文件定义为全局资源文件,如下:
<constantname=“struts.custom.i18n.resources” value=“app” />,其中app为资源文件的基本名
4) 临时指定资源文件:<s:i18n.../>标签的 name 属性指定临时的国际化资源文件
3.2. Action中访问国际化资源文件
Struts2中的Action可以通过三种方式来加载资源文件,包括指指定全局资源文件、包范围资源文件、Action范围资源文件。并且对于不同范围的资源文件有不同的加载顺序。
3.3. 国际化信息的输出
1) 在JSP页面中:
使用<s:text name=“”/>标签输出国际化信息:
<s:text name=“user”/>,name为资源文件中的key
2) 在Action类中:
可以继承ActionSupport,使用getText()方法,该方法的第一个参数用于指定资源文件中的key。
3) 在表单标签中:
通过key属性指定资源文件中的key,如:<s:textfield name="realname" key="user"/>
或者<s:textfieldname=“realname”label=“%{getText(‘user’)}” />
3.4. 实例 使用超链接实现语言切换
1) 用eclipse新建一个dynamic web project,命名为i18nDemo
2) 引入struts2的基本jar包
3) 编辑资源描述符文件web.xml文件,添加如下代码:
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
4) 在src目录下创建struts.xml文件,具体代码如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.custom.i18n.resources" value="i18n"></constant> <package name="default" namespace="/" extends="struts-default"> <action name="i18n" class="com.morris.action.LoginAction" method="change"> <result name="login">/login.jsp</result> </action> </package> </struts> |
5) 在src目录下创建i18n_zh_CN.properties文件,具体代码如下:
loginTitle=\u767B\u5F55 \u9875\u9762 userId=\u8D26\u53F7 userPassword=\u5BC6\u7801 submit=\u63D0\u4EA4 |
6) 在src目录下创建i18n_en_US.properties文件,具体代码如下:
loginTitle=Login Page userId=UserName userPassword=Password submit=Submit |
7) 编写login.jsp页面
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-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> <h4> <s:text name="loginTitle"></s:text> </h4> <a href="i18n.action?language=zh">中文</a> <a href="i18n.action?language=en">English</a> <s:form action="*"> <s:textfield name="userId" key="userId" /> <s:textfield name="userPassword" key="userPassword" /> <s:submit key="submit"></s:submit> </s:form> </body> </html> |
8) 编写LoginAction.java文件
package com.morris.action; import java.util.Locale; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private static final long serialVersionUID = 1L; public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } private String language;
public String change() {
Locale locale = Locale.getDefault(); if ("zh".equalsIgnoreCase(language)) { locale = new Locale("zh", "CN"); ActionContext.getContext().setLocale(locale); } else { locale = new Locale("en", "US"); ActionContext.getContext().setLocale(locale); }
return LOGIN; }
} |
工程目录如下: