Mestar 国际化方案和整改指导
1 Java 国际化方案
1.1. 原理介绍
Java 程序的国际化思路是将程序中的标签、提示信息等放在资源文件中,程序需要支持国家 / 语言环境,则必须提供对应的资源文件。资源文件是 key-value 对,每个资源文件中的 key 不变,但 value 随不同的国家 / 语言变化。
Java 程序的国际化主要通过如下 3 个类完成
Java.util.ResourceBundle: 用于加载资源包,即对应的资源文件
Java.util.Locale: 本地化对象,对应一个特定的语言环境、国家 / 地区,包含“语言类型”和“国家 / 地区的类型。
Java.text.MessageFormat: 用于将消息格式化,用户动态消息传入。
资源文件: 为了实现程序的国际化,必须先提供程序所需要的资源文件。资源文件的内容是很多的 key-value 对,其中 key 是程序使用的部分,而 value 是程序的显示部分。资源文件的命名可以是如下 3 种形式:
baseName_language_country.properties
baseName_language.properties
baseName.properties
其中 baseName 是资源文件的基本名称,用户可以自由定义,而 language 和 country 都不可随意变化,必须是 Java 所支持的语言和国家。事实上,Java 不可能支持所有的国家和语言,可以通过 Locale 类的 getAvailableLocale 方法获取支持的,该方法返回一个 Locale 数组,该数组中包含了所有支持的国家和语言。
Locale [] locales = Locale.getAvailableLocales();
小知识:
i18N ,现在才知道原来 i18N 就是 Internationalization,因为以 i 开头,以 N 结尾,共 18 个字母,也就是国际化的意思。
1.2. 操作过程及代码示例:
(1)、首先编写两个资源文件,例如:
resource_zh_CN.properties
title= 标题
resource_en_US.properties
title=title
(2)、中文的可以使用 jdk 的 native2ascii 命令进行转码 Unicode 编码。
命令格式:native2ascii [-reverse] [-encoding encoding] [inputfile [outputfile]]
示例: native2ascii resource_zh_CN.properties teme.properties,然后在将转好的编码拷贝替换到 resource_zh_CN.properties, 替换后是:
title=\u6807\u9898
(3)、java 代码实现
Locale locale = Locale.getDefault();
// 可以使用 Local 的常量设置具体的语言环境
//Locale locale = Locale.US;
// 根据地区不同加载不同的资源文件
ResourceBundle rb = ResourceBundle.getBundle(“resource”, locale);
// 根据 key 获得 value 值
String title = rb.getString(“title”);
注意:由于 ResourceBundle**** 内部的缓存机制,修改资源文件需要重启进程。
(4)、占位符实现
以上在资源文件配置的消息都是简单的消息,假如消息中含有参数,即有参数占位,我们需要使用 MessageFormat 类的 format 方法, 用后面多个参数值填充前面 pattern 字符串,其中 pattern 字符串就是一个带占位符的字符串:
format(String pattern,Object… values)
例如下面消息:
英文:hello=Hello,{0}!Today is {1}.
中文:hello= 你好,{0}! 今天是 {1}.
Locale locale = Locale.getDefault();
ResourceBundle rb = ResourceBundle.getBundle(“resource”, locale);
String hello = rb.getString(“hello”);
String result = MessageFormat.format(hello, “Bob”,new Date());
- Struts 2 标签化的国际化方案
====================
2.1. JSP 方案
2.1.1. fmt 标签库原理
JSP 使用 JSTL 辅助标签库 (fmt) 支持国际化功能,这些标记利用在 java.util 和 java.text 包中实现的 Java 语言的国际化 API。
JSP 将文件中的字符串信息提取出来,放置到 properties 文件中。我们可以为不同语言环境定义不同的属性文件,如 welcome.properties(英语 / 默认)、welcome_zh_CN.properties(简体中文) 等。
HTTP 协议通过 Accept-Language 请求头将本地化信息从浏览器传递至服务器。Servlet 规范通过 javax.servlet.ServletRequest 类的 getLocale()和 getLocales() 方法自动地利用 HTTP 协议的这一功能。JSTL fmt 库中的定制标记又会利用这些方法来自动地确定用户的语言环境,从而相应地调整它们的输出。另外,我们也可以显式的定义页面的语言环境。
2.1.2. fmt 使用的要点说明:
(a) 引入 fmt 库:<%@ taglib prefix=“fmt” uri=“http://java.sun.com/jstl/fmt” %>
(b) 设置语言环境:<fmt:setLocale value=“zh_CN” scope=“application” /> 。可以使用 Accept-Language 请求头的语言环境,也可以通过显式设置供用户手动切换语言环境
(c) 绑定资源文件:<fmt:bundle basename=“resources.welcome”> 。注意:资源文件一定要放置在 WEB-INF/classes 目录下
(d) 从资源文件中获取指定 key 的信息:<fmt:message key=“gobs”/>
2.1.3. fmt 标签示例
<%@taglib prefix=“fmt” uri=“http://java.sun.com/jstl/fmt” %>
<%@page contentType=“text/html” pageEncoding=“UTF-8”%>
**
fmt:setLocale** value="en_US" scope="application" **/
fmt:bundle** basename="resources.welcome"**
<meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8”>
<a href="fmt:message** key="title"**/">fmt:message** key="title"**/</a>
<body >
<Span style=“font-size:16px”>
** fmt:message** key="description"**/**
** **
** </fmt:bundle>**
2.2. Struts 2 方案
Struts 2 国际化也是建立在 Java 国际化的基础之上,一样也是通过提供不同国家 / 语言环境的消息资源,然后通过 ResourceBundle 加载指定 Locale 对应的资源文件,再取得该资源文件中指定 key 对应的消息,整个过程与 Java 程序的国际化完全相同,只是 Struts2 框架对 Java 程序国际化进行了进一步封装,从而简化了应用程序的国际化。
2.2.1. Struts 2 中加载全局资源文件
Struts 2 提供了很多加载国际化资源文件的方式,最简单. 最常用的就是加载全局的国际化资源文件,加载全局的国际化资源文件的方式通过配置常量来实现。不管在 struts.xml 文件中配置常量,还是在在 struts.properties 文件中配置常量,只需要配置 struts.custom.i18n.resources 常量即可。
2.3. Struts 2 中语言及编码设置
同样,struts 中的语言设置也只需要配置 struts 常量:struts.locale,当此常量未配置时读取操作系统默认语言。但是 Struts 在每一个 action 中会按照如下顺序读取 local
url 中 request_locale 查询参数 -> session 中 WW_TRANS_I18N_LOCALE 变量 -> Accept-Language 请求头 ->struts 配置文件中 struts.locale 变量
代码详解:
I18nInterceptor.java line:119
public String intercept(ActionInvocation invocation)
ActionContext.java line:225
public Locale getLocale()
2.4. Struts 2 访问国际化资源
Struts2 即可以在 JSP 页面中通过标签输出国际化消息,也可以在 Action 类中输出国际化消息。
1) 为了在 JSP 页面中输出国际化消息,可以使用 Struts2 标签, 在标签中指定了国际化资源文件中的 key.
示例:
<s:text name=“login.title”></s:text>
<s:textfield name=“username” key=“login.username”></s:textfield>
还可以输出带占位符的信息。如,有一个 login.welcome = 你好 {0},那么可以用下面这种方式来显示:
<s:text name=“login.welcome”><s:param><s:property value=“username”/></s:param></s:text>
2) 为了在 Action 类中访问国际化消息, 可以使用 ActionSupport 类的 getText 方法, 该方法可以接受一个 name 参数, 该参数指定了国际化资源文件中的 key,该方法有多个重载版本可以使用,适用于不同输出要求。
注意:默认所有的 action类继承自ActionSupport**,可以直接使用该方法。**
示例:
getText(“login.username”);
还可以使用带占位符的信息。如,有一个 login.welcome = 你好 {0},那么可以用下面这种方式来显示:
String params[] = {“张三”};
String welcome = getText(“login.welcome”, params);
- MESTAR 国际化方案扩展
================
3.1. 语言配置参数
当前语言获取的优先级:request parameter > cookie/session > application default
详细说明:
request 参数 request_lang:表示语言切换。
cookie 参数 lang:表示当前正在使用的语言,是真正使用的语言参数。
为什么使用 cookie? cookie 具有延续性,只依赖浏览器环境,不依赖后台,即使用户退出或 session 超时依然有效。
application 参数 lang:系统默认语言,非 http 请求环境下使用。
代码详解
3.2. 资源文件存储
平台自动加载 resources\i18n 目录下所有文件.properties 文件,文件名可自定义,平台和产品分析。包含两类文件,一:普通 key=value 资源文件,中英文分开保存,中文需使用 Unicode 编码;二:菜单翻译映射文件,保存内容格式为 中文 = 英文,用于菜单名直接翻译成英文。
代码详解
3.3. 资源解析过程及 java api
3.3.1. java 代码资源获取 API
方式一:
Action 里面使用 ActionSupport 类的 getText 实例方法:
getText(resourceKey)
方式二:
使用 I18nHelper 类的 i18nMessage 静态方法:
I18nHelper.i18nMessage(resourceKey)
I18nHelper.i18nMessage(resourceKey, Object…)
代码详解
注意:语言参数全部自动获取,不对接口体现。
3.3.2. JSP EL 自定义解析器原理
http 请求过程:
http 请求 -> Tomcat connector 接受连接请求 -> 请求任务池 -> 各种 standard pipeline -> standard wrapper -> filter -> action -> ModleAndView -> forward -> jsp servlet -> 编译生成 *_jsp.java -> _jspService -> 标签解析 -> out.write ()
自定义 EL 解析器:
代码详解
注意:资源字符串必须以 i8n_ 开头
3.3.3. EL 表达式和 ajax 方法使用
a)jsp 文件直接在对应字符显示位置填入 ${i18n_****} 即可。
b) js 文件不经过后台解析,需要由 jsp 传递传递国际化字符串,可以使用全局变量,也可以通过函数参数传递。
window.i18nMsg= window.i18nMsg|| {};
c) 无 jsp 环境的页面,使用 sysutil.js 的 getI18nResource 方法获取资源,该方法使用 AJAX 从后台获取资源。
var messageKesy=new Array(“logged_out”,“expired_message”,“login_again”)
var resobj = $.su.getI18nResource(messageKesy);
document.title = resobj.logged_out;