实战程序化处理Struts1针对zh_HANS_CN国际化问题

最近为了解决Windows 8中对中文locale的变化,引入了zh_HANS_CN的支持,原来已经支持中文的站点无法正常工作。

当然你可以增加一种资源文件来支持着新的locale,但是涉及到不同浏览器的不同,其实这种支持只能针对IE10 or IE11生效。

为了解决这一问题我采用的是一种程序化的思路,保持原来的资源文件,在程序中对locale进行转换。由于站点由多种技术框架交叉在一起,解决之前需要了解多种框架的技术方案。

国际化是什么?

国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式。它要求从产品中抽离所有地域语言,国家/地区和文化相关的元素。换言之,应用程序的功能和代码设计考虑在不同地区运行的需要,其代码简化了不同本地版本的生产。开发这样程序的过程,就称为国际化。

通俗一点,就是你在一些网站上只需要改变浏览器的语言设置就能看到不同语言版本的界面,不需要修改一行代码的程序。

1, jstl国际化

在没有各种框架之前,j2EE国际化项目通常做法:

1.1 jsp环境

首先写一个messages.zh_CN.properties文件,放在class-path也就是/WEB-INF/classes里      welcome=欢迎     然后用native2ascii.exe把它转为 welcome=\欢\迎

在web.xml中定义messages文件

<context-param>

<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>

<param-value>messages</param-value>

</context-param>

最后在jsp里使用

<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>

<fmt:message key="welcome"/>

如果有多个Resource Bundle文件, 就要在jsp里用<ftm:bundle>定义了.

1.2 pure Java环境

ResourceBundle rb = ResourceBundle.getBundle("messages");

String welcome = rb.getString("welcome");

2)Spring的增强做法

Spring增加了MessageSource的概念,一是ApplicationContext将充当一个单例的角色,不再需要每次使用i18时都初始化一次ResourceBundle,二是可以代表多个Resource Bundle.

在ApplicationContext的定义文件中,增加如下节点:

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">

<property name="basename" value="messages"/>

</bean>

则在pure java环境中。   context.getMessage("welcome", null, Locale.CHINA)

而在jsp环境中,Controller调用JSTL viewResolver再调用Jsp时,<fmt:message>将继续发挥它的功效。

因此,appfuse等sample都是在appfuse-servlet.xml 中定义一个<messageSource>。

3)Struts的做法

3.1.Struts1和Struts2在配置文件中的配置。

  Struts1 Struts2
struts-config.xml <message-resources parameter="xxx.xx.xxx.ApplicationResources" />  
struts.xml   <constant name="struts.custom.i18n.resources" value="message"></constant>

3.2.Struts1和Struts2在页面中的显示

  Struts1 Struts2
index.jsp <bean:message key="USERNAME"/>  
index.jsp   <s:text name="USERNAME"></s:text>

3.3.Struts1和Struts2用Java代码控制国际化

思路:首先获取到相关的语言信息,然后设置到环境中,最后通过ResourceBundle来获取相关的资源文件信息。

A:Struts1的相关代码

String currentLocale = request.getLocale().toString(); //浏览器默认的语言
            request.getSession().
			setAttribute(Globals.LOCALE_KEY, currentLocale);//将语言这种到环境中
//然后用ResourceBundle获取相关的资源文件
ResourceBundle resourceBundle = ResourceBundle.
			getBundle("ApplicationResources",currentLocale);

B:Struts2的相关代码

Locale currentLocale = request.getLocale().toString();//获取本地语言
session.setAttribute("WW_TRANS_I18N_LOCALE", LocalizedTextUtil.localeFromString(currentLocale, null));//将语言这种到环境中
//然后用ResourceBundle获取相关的资源文件
ResourceBundle resourceBundle = ResourceBundle.
			getBundle("ApplicationResources",currentLocale);

3.4.Struts1实例

实现思路:当我们在页面上选择中文或者是英文的时候就将相关的语言变量存在cookie中(便于在过滤器中得到是哪一种语言),写一个过滤器(LocaleFilter),过滤每一个页面的请求信息。在LocaleFilter中我们首先判断cookie是是否有约定好的cookie值,如果有就设置这种语言到环境中,如果没有就得到浏览器默认的语言再设置到环境中(用户在画面设置的locale优先级高于浏览器设置语言得到的locale)。

准备工作:

  1. 创建资源文件ApplicationResources_en_US.Properties和ApplicationResources_zh_CN.Properties。
  2. 创建一个LocaleFilter(过滤器)将LocaleFilter配置到web.Xml中。
  3. 在struts-config.Xml中配置
    <message-resources parameter="ApplicationResources" />
    
  4. 创建一个index.jsp来实现中英文的切换。

实现:

a.创建的资源文件:

b.web.xml的配置:

<filter>
		<filter-name>localeFilter</filter-name>
		<filter-class>xx.xx.xx. LocaleFilter</filter-class>
	</filter>
<filter-mapping>
		<filter-name>localeFilter</filter-name>
		<url-pattern>/*</url-pattern>
		<dispatcher>REQUEST</dispatcher>
		<dispatcher>FORWARD</dispatcher>
	</filter-mapping>

c.struts-config.xml中的配置:

<message-resources parameter="ApplicationResources"/>

d.创建index.jsp页面,然后实现国际化。

index.jsp页面html代码

<span class="rk_qh">
		   <a class="rk_qhuan" onclick="clickLan();"><span style="margin:0 2px;">${lan}</span>
					<img id="lan_img" style="position:relative;"src="/images/header/arrow_down.gif"/>
		    </a>
		         <ul id="ul_lans" class="chinese_english_huan" onmouseover="clickLan();" onmouseout="hideLan();">
		      	       <li><a href="javascript:languages(\‘zh_CN\‘)">中文(简体)</a></li>
		      	       <li class="rk_topborder_n"><a href="javascript:languages(\‘en_US\‘)">English</a></li>	      	</ul>
		</span>

Index.jsp页面javascript方法

function languages(lan){
		var cookiesPath = "/";//路径
		var cookiesDomain = ".xxx.com";//设置有效的url
		document.cookie = "xxx_language="+lan+";path="+cookiesPath+";domain="+cookiesDomain;
//将有关信息写到cookie中
		location.reload();//刷新本页面进行国际化切换
	}

e.LocaleFilter(过滤器)代码

package com.ruanko.webapp.filter;

import org.apache.struts.Globals;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.servlet.http.Cookie;
public class LocaleFilter extends OncePerRequestFilter {

	public static final String CHINESELANGUAGE = "中文(简体)";
	public static final String ENGLISHLANGUAGE = "English";

    @SuppressWarnings("unchecked")
	public void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                 FilterChain chain)
            throws IOException, ServletException {

		/*过滤器实现思路:
		(1)判断cookies中是否有值,有值就将cookies中的值得到一个Locale
		(2)cookies没值就根据浏览器默认的语言来显示*/

    	Locale currentLocale = null; //定义语言地区信息
		String language = null;//客户端页面写的语言cookies
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for(Cookie cookie : cookies){
	        	if(cookie.getName().equals("xxx_language")){
	        		language=cookie.getValue();//判断和设置cookies里面是否有值。
	        	}
	        }
		}
		try {

			/**
			 * 1.如果cookies中是有值的(前提条件是从页面传过来的语言为空才进下面的逻辑)
			 */
			 if(language != null){
				if ("zh_CN".equals(language)) {//如果cookies中的语言为中文
					currentLocale = new Locale("zh", "CN");
					language = "zh_CN";
				    request.getSession().setAttribute("lan", CHINESELANGUAGE);
				} else if ("en_US".equals(language)) {//如果cookies中的语言为英文
					currentLocale = new Locale("en", "US");
					language = "en_US";
				    request.getSession().setAttribute("lan", ENGLISHLANGUAGE);
				} else {
					currentLocale = new Locale("zh", "CN");
					language = "zh_CN";
				    request.getSession().setAttribute("lan", CHINESELANGUAGE);
				}
			}
			/**
			 * 传过来的语言:如果既没有传过来的语言和cookies里面的值就根据浏览器默认的语言来显示
			 */
			else {
				String defaultLanguage = request.getLocale().toString(); //浏览器默认的语言
				if(defaultLanguage.equals("en_US")){
				    currentLocale = new Locale("en", "CN");
				    request.getSession().setAttribute("lan", ENGLISHLANGUAGE);
				}else{
					currentLocale = new Locale("zh", "CN");
				    request.getSession().setAttribute("lan", CHINESELANGUAGE);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			///最后将设置好的环境类放到session中去
			request.getSession().removeAttribute(Globals.LOCALE_KEY);
			request.getSession().setAttribute(Globals.LOCALE_KEY, currentLocale);
			}

        chain.doFilter(request, response);
    }
}

f.在Java代码中得到资源文件的值

Locale locale =  (Locale) request.getSession().getAttribute(Globals.LOCALE_KEY);
		ResourceBundle resourceBundle = ResourceBundle.getBundle("ApplicationResources",locale);
		String course = resourceBundle.getString("COE_COURSE");

2,实战总结

由于项目国际化主体还是通过jstl方案来获取相应资源文件的设置,但是同时用到了struts1的一些taglibs,同时对于一些插件中用到了server端的缺省locale.解决思路:

1〉针对jstl的设置,通过一个servletFilter 来实现locale的转换。

public class LocaleServletFilter implements Filter  {

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {        
          Locale sesionLocale=request.getLocale();
          String locStr=sesionLocale.toString();
          Locale proLoc = locFromString(locStr);
          LocaleSetId.setLocale(proLoc);
          request.setAttribute("javax.servlet.jsp.jstl.fmt.fallbackLocale", proLoc.toString());
          request.setAttribute("javax.servlet.jsp.jstl.fmt.locale", proLoc.toString());      
          HttpServletRequest hprequest = (HttpServletRequest)request;
          HttpServletResponse hpresponse = (HttpServletResponse)response;
          hprequest.setCharacterEncoding("UTF-8");
          HttpSession session = hprequest.getSession();     
          Config.set(session, Config.FMT_LOCALE, proLoc);
          session.removeAttribute(Globals.LOCALE_KEY);
          session.setAttribute(Globals.LOCALE_KEY, proLoc);

          chain.doFilter(hprequest, hpresponse);        
    }

    
    public Locale locFromString(String locale) {
        String parts[] = locale.split("_");
        if (parts.length == 1) return new Locale(parts[0]);
        else if (parts.length == 2)
        {
          if(parts[1].equalsIgnoreCase("HANS")){
                
            return new Locale(parts[0], "CN");
          }
          else{
                  
            return new Locale(parts[0], parts[1]);
          }
        }
        else if (parts.length == 3 && parts[1].equalsIgnoreCase("HANS"))
        {
            return new Locale(parts[0], parts[2]);
        }
        else return new Locale(parts[0], parts[1], parts[2]);
    }
}
2〉针对struts1,taglib的locale 设置
 /** i18n the title */
    public String getTitle() {
        if (isLocalizedTitle) {
            Locale userLocale =
               RequestUtils.getUserLocale(
                    (HttpServletRequest) pageContext.getRequest(), null);
            HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();
            Locale LocaleProcessed= locFromString(req.getLocale().toString());           
            req.getSession().setAttribute(Globals.LOCALE_KEY, LocaleProcessed);
            pageContext.setAttribute(Globals.LOCALE_KEY, LocaleProcessed);
            try {
                String title=TagUtils.getInstance().message(pageContext, null,
                        Globals.LOCALE_KEY,
                        super.getTitle());
                return title;
            } catch (JspException e) {
                log.debug(e);
                // Do not localize then
            }
        }
        return super.getTitle();
    }

3〉针对插件或服务端代码中用到缺省的locale的问题。

这个在前面servletfilter里面我设置了一个全局变量,在server端如果需要用locale调用如下方法得到。
 LocaleSetId.getLocale();

实战程序化处理Struts1针对zh_HANS_CN国际化问题

时间: 2024-10-25 05:44:32

实战程序化处理Struts1针对zh_HANS_CN国际化问题的相关文章

Struts1 中的国际化

国际化简称i18n是英语Internationalization的缩写.在Struts中实现国际化需要以下几步: 创建资源文件 加载资源文件 在页面中使用<been:message >标签来显示国际化的文本消息. 步骤详解: 1——创建资源文件 创建一个包用来放资源文件. Struts中的默认创建的资源文件名是ApplicationResources.properties.我们要自定义的资源文件名可以这样命名: baseName_language.properties.  baseName是资

【Spring实战】—— 10 AOP针对参数的通知

通过前面的学习,可以了解到 Spring的AOP可以很方便的监控到方法级别的执行 ,针对于某个方法实现通知响应. 那么对于方法的参数如何呢? 比如我们有一个方法,每次传入了一个字符串,我想要知道每次传入的这个字符串是神马?这又如何办到呢! 举个Action上面的例子,一个思考者(thinker),每次在思考时,都会传入一个字符串作为思考的内容. 我们想要每次获取到这个思考的内容,实现一个通知.因此读心者可以通过AOP直接监控到每次传入的内容. 源码参考 首先看一下思考者的接口和实现类: pack

自动化测试框架Cucumber和Robot Framework的实战对比

自动化测试框架Cucumber和RobotFramework的实战对比 一.摘要 自动化测试可以快速自动完成大量测试用例,节约巨大的人工测试成本:同时它需要拥有专业开发技能的人才能完成开发,且需要大量时间进行维护(在需求经常变化的情况下),所以大部分具有很好开发技能的人员不是很愿意编写自动化用例.但由于软件规模的高速增长,人力资源的逐步稀缺,自动化测试已是势在必行. 对于自动化测试首先需要保证其功能是对客户有价值的和正确可用的.而这一切的基础就是用例要能测试客户的需求,期望,最好能让客户参与到测

Java语言的国际化

事实上,Java语言不可能支持所有国家和语言,如需要获取Java语言所支持的语言和国家,可调用Locale类的getAvailableLocale方法获取,该方法返回一个Locale数组,该数组里包含了Java所支持的语言和国家. Java程序的国际化主要通过如下三个类完成 java.util.ResourceBundle:用于加载一个国家,语言资源包 java.util.Locale:用于封装一个特定的国家/区域,语言环境 java.text.MessageFormat:用于格式化带占位符的字

自动化测试框架Cucumber和RobotFramework的对比

一.摘要 自动化测试可以快速自动完成大量测试用例,节约巨大的人工测试成本:同时它需要拥有专业开发技能的人才能完成开发,且需要大量时间进行维护(在需求经常变化的情况下),所以大部分具有很好开发技能的人员不是很愿意编写自动化用例.但由于软件规模的高速增长,人力资源的逐步稀缺,自动化测试已是势在必行. 对于自动化测试首先需要保证其功能是对客户有价值的和正确可用的.而这一切的基础就是用例要能测试客户的需求,期望,最好能让客户参与到测试用例的开发过程中来或让客户评审测试用例,因此出现了ATDD.BDD等各

【SQL】- 基础知识梳理(四) - 存储过程

存储过程的概念 存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行 存储过程的好处 A. 存储过程允许标准组件式编程        存储过程创建后可以在程序中被多次调用执行,而不必重新编写该存储过程的SQL语句.而且数据库专业人员可以随时对存储过程进行修改,但对应用程序源代码却毫无影响,从而极大的提高了程序的可移植性. B. 存储过程能够实现较快的执行速度        如果某一操作包含大量的T-SQL语句代码,分

放假前的“例行安检”

十一长假即将来临,想必大家都已早早规划好了出游计划,是否身体不听使唤的在敲打着键盘(假装认真工作),按奈不住的那颗躁动的心却已飘向远方? 对制造商来说想要安心度过一个愉快的长假,假期前企业的"例行安全检查"必不可少!在互联网和移动计算时代,数字安全面临着极高的安全隐患,为有效应对××××××,最大程度的降低或减少××××××对企业造成的损失,首先,企业需要检查公司的ERP系统是否安全?一些公司认为,自己的ERP是内部部署或由代管服务提供商托管的,在安全方面没有问题.他们对ERP的物理安

SEO同业竞争,如何超越竞争对手?

每一个行业都存在竞争对手,特别是SEO这个领域,同业竞争显得异常激烈,对于一个新企业站,想要在垂直行业中,崭露头角,从目前来看,显得格外困难. 但这并不代表,我们无计可施,所谓知己知彼,我们只有充分的了解竞争对手,才能在SEO同业竞争中,有的放矢. 那么,SEO同业竞争,如何超越竞争对手? 根据以往竞争对手分析的经验,我们将通过如下内容,进一步说明: 1.突出优势 当我们试图超越竞争对手的时候,特别是面临同业竞争中的行业巨头,我们首先要做的就是:寻找对方遗漏的薄弱环节,对方做的相对不专业的地方,

Struts1国际化实例

最近发现MDT推出去的系统的有不同问题,其问题就不说了,主要是策略权限被域继承了.比如我们手动安装的很多东东都是未配置壮态,推的就默认为安全壮态了,今天细找了一下,原来把这个关了就可以了. Struts1国际化实例