国际化
• 服务器按照用户浏览器上选择的语言给出提示
• 国际化 [ Internationalization ] -- 缩写为 I18N -- 取开头和结尾两个字母,中间有 18 个字母
• 种类:
○ 硬编码国际化 [ 静态国际化 ] -- 程序中不变的代码 [ jsp 页面中的静态代码 ]
§ 硬编码国际化实例 -- 依据 locale 信息
§ 硬编码国际化实例 -- 自动切换
○ 动态信息国际化 -- 程序中动态生成的代码 -- 提示信息 / 异常信息
§ 动态信息国际化
§ 动态信息国际化 -- 编程式异常
• 国际化文件组成:
○ baseName +[ 基名 + _语言名_国家名.properties ]
如:MessageResources_en_US.properties 语言小写,国家大写
○ baseName [ 基名.properties ]
§ 如:MessageResources.properties -- 默认国际化资源文件,一般默认为英文
○ 项目中没有对应语言的国际化资源文件就使用默认国际化资源文件
○ 默认国际化资源文件:
• 配置:
§ 如果浏览器使用的是法文,在项目下没有找到法文国际化资源文件 -- 看系统用的语言 -- 寻找系统语言的国际化资源文件
§ 如果用户系统下所用的语言在项目中也没有对应的国际化资源文件 -- 使用默认国际化资源文件 [ 一般为英文 ]
§ 如果浏览器使用的是法文,在项目下没有找到法文国际化资源文件 -- 看系统用的语言 -- 寻找系统语言的国际化资源文件
§ 如果用户系统下所用的语言在项目中也没有对应的国际化资源文件 -- 使用默认国际化资源文件 [ 一般为英文 ]
○ 在 struts-config.xml 主配文件中加 <message-resources> 标签配置信息
<message-resources parameter="res.MessageResources"/>
§ 该标签中指定了国际化文件的基名和位置,位置默认在 src 下
§ res -- src 下的一个子目录
○ 将国际化文件放在指定目录下
• 国际化资源文件格式:
○ 作为 properties 文件,为 Map 格式 -- 有 key 和 value
§ 一个项目中各个国际化资源文件的 key 都是一致的,value 根据各国语言进行相应的更改
○ 中文国际化资源文件:
§ properties 文件中中文字符为 ASCII 码 -- struts 框架无法识别中文字符
§ 将汉字变为 ASCII 码:
□ native2ascii 指令:

在文件所在目录下进行指令
□ 将源文件直接转换成中文的国际化资源文件:

• 缺点:代码可读性差
在文件所在目录下进行指令
native2ascii*ex.e** o.properties MessageResources_zh_CN.properties 将源文件的 properties 转换为中文的符合要求的国际化资源文件
硬编码国际化实例 -- 依据 locale 信息
• 使用中文显示:
○ 客户端发出请求:
§ http 协议头上会自动带有 locale 信息 [ 客户端所在的浏览器的语言信息 ]
§ Tomcat 创建 request 接收请求字符串 / 请求参数 / cookie / locale / IP 地址
§ Tomcat 取得该用户对应的 session -- 如果是第一次访问,会自动创建 session / 不是第
一次访问,已有 session
§ 从 request 内置对象中取得 locale 信息
§ 将从 request 内置对象中取得的 locale 信息设到 session 中,属性名为
Globals.LOCALE_KEY session.setAttribute(Globals.LOCALE_KEY, locale);
○ 使用国际化资源文件:
§ 针对国际化产生的一个 struts 标签:[ 动态代码,服务器执行 ]
□ <a href="login1.do"><bean:message key="user.button.login"/></a><br>浏览器显示【登录】
® 先到该用户对应的 session 中取得封装的 locale 信息session.getAttribute( Globals.LOCALE_KEY ); -- 封装了语言名_国家名
® 到 struts-config.xml 中去找 <message-resources> 标签,从而取得国际化资源文件的基名和位置
◊ 通过 struts 的 Bean-message 标签可以找到国际化资源文件
® 通过标签中的 key,找到国际化资源文件中的 value -- user.button.login=\u767B\u5F55 [ 登录 ]
• 使用英文显示:[ 浏览器的语言设置为英文 ]
○ 客户端发出请求:
§ http 协议头上会带有 locale 信息 -- 此时 locale 信息中为英文
§ Tomcat 创建 request 对象接收 locale 信息
§ Tomcat 将从 request 中取得的 locale 信息设到与该用户对应的 session 中
○ 执行 index.jsp 页面:
§ 处理标签:
<a href="login1.do"><bean:message key="user.button.login"/></a><br>浏览器显示【Login】
□ 此时为英文国际化资源文件
□ 通过标签中的 key,找到国际化资源文件中的 value -- user.button.login=Login
○ 用户通过超链接发出请求,Tomcat 将 locale 信息设到 session 中后将请求提交给 struts: 请求字符串:http://127.0.0.1:8080/test/login1.do
<action path="/login1" forward="/login.jsp" > </action>
○ struts 在截取到 path="/login1" 字符串后立即进行 locale 信息的处理: String path = processPath(request, response); processLocale(request, response);
------------------------- processLocale(request, response)
protected void processLocale( HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); // 取得 session
// 判断 session 中是否有 locale 信息,有就不再设置,没有就从 request 中取得信息并设置到 session 中,属性名为 Globals.LOCALE_KEY if (session.getAttribute(Globals.LOCALE_KEY) != null) { return; }
Locale locale = request.getLocale();
if (locale != null) { session.setAttribute(Globals.LOCALE_KEY, locale); }
}
§ 在浏览器上改完语言要重启浏览器 -- 产生一个新的 session,不然原来的 session 里有原来为中文的 locale 信息,无法更改成功
○ 由于 session 中设置的国际化资源文件为英文 -- 该用户发出任何请求,静态 jsp 页面文字都为英文 -- 英文国际化资源文件
硬编码国际化实例 -- 自动切换
• 进入首页:
------------------------- index.jsp
<a href="changelang.do?lang=zh">中文</a><br>
<a href="changelang.do?lang=en">英文</a>
• 用户点击超链接发出请求,请求字符串:http://127.0.0.1:8080/test/changelang.do?lang=zh
• struts 截取到 path="/changelang":
• struts 处理 locale 信息 -- processLocale():
○ 拿到当前用户对应的 session
○ 看 session 中是否有属性名为 Globals.LOCALE_KEY 的属性值
§ 如果有值就使用原值
§ 如果没有,从 request 中拿到 locale 信息并将取得的 locale 信息设置到 session 中,属
性名为 Globals.LOCALE_KEY
• 在 struts-config.xml 中寻找 path="/changelang" 的 <action> 标签:
<action path="/changelang" type="com.bjsxt.struts.ChangeLanguageAction" > <forward name="index" path="/index.jsp"/> </action>
• 通过 type 创建出 Action 对象,并执行 Action 中的 execute() 方法:
------------------------- ChangeLanguageAction.java
String lang = request.getParameter("lang"); // 从用户发出的请求中获取参数名为lang 的参数值Locale currentLocale = Locale.getDefault(); // 给 Locale 一个默认值 -- 默认值为系统语言
if ("zh".equals(lang)) {
currentLocale = new Locale("zh", "CN"); // 如果用户请求中参数名为 lang 的参数值为中文 -- 给 Locale 对象重新赋值为中文国际化资源文件
}else if("en".equals(lang)) {
currentLocale = new Locale("en", "US"); // 如果用户请求中参数名为 lang 的参数值为英文 -- 创建一个对应英文国际化资源文件的 locale 对象
}
this.setLocale(request, currentLocale); // this 代表 ChangeLanguageAction,将自己创建好的locale 信息设置到 session 中
return mapping.findForward("index");
------------------------- setLocale(request, currentLocale)
protected void setLocale(HttpServletRequest request, Locale locale) { HttpSession session = request.getSession();
if (locale == null) { locale = Locale.getDefault(); } session.setAttribute(Globals.LOCALE_KEY, locale);
}
• 国际化资源文件的动态切换
○ 通过 execute() 方法根据用户超链接选择的参数,重新创建相应的locale 对象并设置到 session 中属性名为 Globals.LOCALE_KEY 的属性值中 -- 可以人为改变先前根据浏览器系统语言而设置的locale 信息
动态信息国际化
• 特点:
○ 国际化资源文件中有动态信息的动态填充位置
• 实例:
§ 如:user.login.success = {0},登录成功
§ {0} -- 动态填充位置
○ 登录界面:

<form action="login.do" method="post"> <bean:message key="user.username"/>:<input type="text" name="username"><br> <bean:message key="user.password"/>:<input type="password" name="password"><br> <input type="submit" value="<bean:message key="user.button.login"/>"> </form>
○ 通过Bean-message 标签可以拿到国际化资源文件 -- 浏览器显示【User Name】【Password】
○ 用户输入用户名和密码,提交请求,请求字符串:http://127.0.0.1:8080/test/login.do
○ struts 截取到 path="/login":
○ struts 处理 locale 信息 -- processLocale():
○ 拿到当前用户对应的 session
○ 看 session 中是否有属性名为 Globals.LOCALE_KEY 的属性值
□ 如果有值就使用原值
□ 如果没有,从 request 中拿到 locale 信息并将取得的 locale 信息设置到 session 中,属性名为 Globals.LOCALE_KEY
○ 在 struts-config.xml 中寻找 path="/login" 的 <action> 标签:
<form-beans>
<form-bean name="loginForm" type="com.bjsxt.struts.LoginActionForm"/> </form-beans> <action path="/login" type="com.bjsxt.struts.LoginAction" name="loginForm" scope="request" validate="false" > <forward name="success" path="/login_success.jsp"/> <forward name="error" path="/login.jsp"/> </action>
○ 通过 name 找 ActionForm -- 创建出 ActionForm 对象后将表单数据收集到 LoginActionForm: private String username; -- "admin"
private String password; -- "admin"
○ 通过 type 创建出 Action 对象,并执行 Action 中的 execute() 方法:
------------------------- LoginAction.java LoginActionForm laf = (LoginActionForm)form; String username = laf.getUsername();
String password = laf.getPassword();
ActionMessages messages = new ActionMessages(); // 定义一个 ActionMessages
UserManager.getInstance().login(username, password); // 执行业务对象的 login() 方法,顺利执行完后进行以下代码
ActionMessage message = new ActionMessage( "user.login.success", username ); messages.add("loginSuccess1", message);
ActionMessage message1 = new ActionMessage("user.login.success", username); // 虽然存放的信息一样,但不是同一个对象
messages.add("loginSuccess2", message1); this.saveMessages(request, messages); return mapping.findForward("success");
□ 即 -- ActionMessage message = new ActionMessage( "user.login.success", new Object[]{username} );
□ 创建国际化消息文本对象 -- new ActionMessage( "国际化资源文件中的 key", 要填入到对应的 value 中的填充符中的信息 )
® ActionMessage 的 key 就是国际化资源文件中的 key,value 是一个 Object 数组对象
® Object 数组对象中的数据作为国际化资源文件中的动态填充符
□ 通过 key 找到国际化资源文件中对应的 value -- user.login.success={0},Login Success
□ 用 username 的值去填充国际化资源文件中对应的 value 中的填充符 -- {0}
□ 如果有多个填充位置,使用 Object 数组对象来进行填充 -- 数组中第一个元素填充到 {0},第二个元素填充到 {1} …
® 如:user.login.success={0} login success {1}{2}
® ActionMessage message = new ActionMessage( "user.login.success", new Object[]{ username, username, username} )
□ 必须将国际化消息文本对象 ActionMessage 放进 ActionMessages 对象中的一个 Map 集合 messages 中
® protected HashMap messages = new HashMap(); -- 专门用来存放国际化消息文本对象
□ ActionMessages 内部有一个 Map 集合,ActionMessages 不是集合
□ 此时 messages 里有两个元素:
® key="loginSuccess1",value 为第一个国际化消息文本对象 message
® key="loginSuccess2",value 为第二个国际化消息文本对象 message1
------------------------- saveMessages(request, messages)
request.setAttribute(Globals.MESSAGE_KEY, messages);
® 传递国际化消息文本
® 将存放了消息文本对象的ActionMessages 对象放进 request 内置对象中,属性名为 Globals.MESSAGE_KEY
□ 将 ActionMessages 对象设入 request 内置对象中之后,Action 返回给 struts 一个封装了转向路径的 ActionForward 对象
○ struts 解析 ActionForward 对象后转向相应的 jsp 页面 -- login_success.jsp:
<html:messages id="msg" message="true" property="loginSuccess1"> <bean:write name="msg"/> </html:messages> ○ html-messages 标签只能取得 ActionMessages,不能取 ActionMessage ○ <html:messages id="msg" message="true" property="loginSuccess1">
□ 先从该用户对应的 session 里找属性名为 Globals.LOCALE_KEY 的属性值 -- 取得国际化资源文件的 locale 信息
□ 到 struts-config.xml 配置文件中找 <message-resources> 标签中找 parameter 属性 -- 取得国际化资源文件的基名和位置
□ 根据 locale 信息和国际化资源文件的基名和位置找到相应的国际化资源文件
□ 从该请求对应的 request 内置对象中取得属性名为 Globals.MESSAGE_KEY 的属性值 -- 取得 ActionMessages 对象
□ 取得 ActionMessages 对象后,到对象中的 messages 集合中找 key 为 loginSuccess1 的 value -- 取得国际化消息文本对象 ActionMessage
□ 将 ActionMessage 对象放到 page 内置对象中,属性名为 msg
○ <bean:write name="msg"/>
□ 从 scope 中找 key 为 msg 的属性值 -- 取得 ActionMessage 对象
□ 通过解析 ActionMessage -- 调用 getkey() 方法 -- 取得 ActionMessage 中的 key="user.login.success"
□ 通过取得的 key,到国际化资源文件中找具有相同的 key 的 value -- user.login.success={0},Login Success
□ 通过解析 ActionMessage -- 调用 getValue() 方法 -- 取得 username,并将 username 的值填充到国际化资源文件中的填充位置上
□ 将填充后的信息作为 Bean-write 的标签值返回浏览器显示【admin,Login Success】
--------------------------------------------------------------------------------------------------------------------------------------
<html:messages id="msg" message="true">
<bean:write name="msg"/>
</html:messages>
○ 省略了 property 属性后,处理所有的 ActionMessage
○ <html:messages id="msg" message="true">
□ 取得国际化资源文件
□ 从该请求对应的 request 内置对象中取得属性名为 Globals.MESSAGE_KEY 的属性值 -- 取得 ActionMessages 对象
□ 将 ActionMessages 对象内部 Map 集合 messages 下的所有 value 值都取出 -- 取得 message / message1 两个 ActionMessage 对象
□ 依次将 message / message1 交给 page 内置对象,属性名为 msg
○ <bean:write name="msg"/>
□ 从 scope 中找 key 为 msg 的属性值 -- 取得 ActionMessage 对象 message
□ 通过解析 ActionMessage -- 调用 getkey() 方法 -- 取得 message 中的 key="user.login.success"
□ 通过取得的 key,到国际化资源文件中找具有相同的 key 的 value -- user.login.success={0},Login Success
□ 通过解析 message -- 调用 getValue() 方法 -- 取得 username,并将 username 的值填充到国际化资源文件中的填充位置上
□ 再次取得 key 为 msg 的属性值 -- 取得 ActionMessage 对象 message1
□ 通过解析 ActionMessage -- 调用 getkey() 方法 -- 取得 message1 中的 key="user.login.success"
□ 通过取得的 key,到国际化资源文件中找具有相同的 key 的 value -- user.login.success={0},Login Success
□ 通过解析 message1 -- 调用 getValue() 方法 -- 取得 username,并将 username 的值填充到国际化资源文件中的填充位置上
□ 将填充后的信息作为 Bean-write 的标签值返回浏览器显示【admin,Login Success admin,Login Success】
--------------------------------------------------------------------------------------------------------------------------------------
<html:messages id="msg">
<bean:write name="msg"/>浏览器没有任何显示
</html:messages>
□ message 属性:
® message="true":告诉标签,从 request 中的 Globals.MESSAGE_KEY 中取值
® 不写 message 属性则默认为 false,从 request 中的 Globals.ERROR_KEY 中取值