Windows 8引入的新的language tag导致的本地化问题

问题:

Struts2的应用,本地化字符串在Windows 8+IE11时显示错误,为resource key。

 

在以下组合均测试正常:

Windows 8.1 + Chrome

Windows 7 + IE11

分析:

页面上使用Struts的<s:text name="login.message.userNameValidate" />获取本地化字符串,而Struts是根据客户端的locale信息匹配资源文件的。应用配置了两个资源文件:

message_en_US.properties -> 没有配置上面的resource key

message_zh_CN.properties -> 配置了上面的resource key


查看浏览器的Request Header:

Windows 8.1 + Chrome  31.0.1650.57 :

 


Windows 8.1 + IE 11.09600.16476:

 


Windows 7 + IE

 

由此可以判断是Windows 8 引入了新的locale符号:zh_Hans-CN, zh-Hans,而Linux服务器端没有对应的资源文件,使用了默认的message_en_US.properties,造成读取资源失败。(当使用Windows8本地的Tomcat时,默认资源文件是message_zh_cn.properties,也不能重现这个问题)

解决:

根据Struts2关于i18n拦截器的描述:http://struts.apache.org/release/2.0.x/docs/i18n-interceptor.html

按照文中的说明,增加URL参数是可以临时解决问题的:http://devtest.ahzti.com:8080/spinerp/admin/loginAction?request_locale=zh_CN

但不可能总是在运行时手动更新locale。因此更好的办法是建立拦截器,通过配置将特定的language tag转换成系统支持的的language tag。通过查看I18nInterceptor的源码,发现其获取locale值的优先级为:

  1. 默认的URL参数:request_locale;
  2. 默认的URL参数:request_only_locale; //通过这个参数设置的locale不会被放入session中
  3. 默认的session变量:WW_TRANS_I18N_LOCALE;
  4. 浏览器的locale值:invocation.getInvocationContext().getLocale()

因此,通过新建LanguageTagAliasInterceptor 继承I18nInterceptor,从配置文件中读取需要匹配的language tag及需要映射的language alias,在session(WW_TRANS_I18N_LOCALE)中查找并替换,即可完成locale的修改。注意不能覆盖I18nInterceptor的默认行为,即通过URL参数设置的locale仍然具有最高的优先级。


代码:


public String intercept(ActionInvocation invocation) throws Exception {
	if (languageTag != null && !languageTag.isEmpty() && languageAlias != null && !languageAlias.isEmpty()) {
	    Locale currentLocale = invocation.getInvocationContext().getLocale();
		boolean needReplace = currentLocale == null || !languageAlias.equalsIgnoreCase(currentLocale.toString());
	    if (needReplace) {
	    	String[] languageTags = languageTag.split(",");
	   		for (String languageTag : languageTags) {
				if (languageTag.equalsIgnoreCase(currentLocale.toString())) {
		    		// Override default session named WW_TRANS_I18N_LOCALE,defined in parent class.
			    	Map<String, Object> session = invocation.getInvocationContext().getSession();
			    	session.put(attributeName, LocalizedTextUtil.localeFromString(languageAlias, null));
			    	break;
			}
		    }
		}	
	}
	return super.intercept(invocation);
}


Strtus.xml


<interceptor-ref name="languageTagAlias">
	<param name="languageTag">zh_hans_cn,zh_hans</param>
	<param name="languageAlias">zh_cn</param>
</interceptor-ref>


总结

这个问题出现几率很低,最终发现只在Windows8的机器上才能重现,原因是使用了新的language tag。修复这个问题可以有以下几种方法:

  1. 在客户端定义Language tag,覆盖浏览器默认值;
  2. 在WebApp中为zh-Hans-CN,zh-Hans等tag增加新的资源文件;
  3. 编写拦截器,通过配置修改需要取代的language tag。

综合来看,第3个方案是最好的。当然也有一些可以增强的地方,如:I18nIntercepter执行了两次;考虑如何支持多个language tag的替代条件。


参考资料:

Mozzila项目中同样问题的讨论:

https://github.com/mozilla/persona/issues/3044


W3C关于Language Tag的定义:

http://www.w3.org/International/articles/bcp47/


Struts2加载资源的顺序:

http://struts.apache.org/release/2.0.x/docs/localization.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值