热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

Struts1和Struts2的国际化作者:田雨成1.国际化是什么?国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式。它要求从产品中抽离所有地域语言,国家地区和文化相关的元素。换言之,应用程序的功能和代码设计考虑在不同地区运行的需要,其代码简化了不同本地版本的生产。开发
最近为了解决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文件    

       
             javax.servlet.jsp.jstl.fmt.localizationContext
             messages
        

     最后在jsp里使用
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>

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

1.2 pure Java环境
     ResourceBundle rb = ResourceBundle.getBundle("messages");
     String welcome = rb.getString("welcome");

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

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

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

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

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



3)Struts的做法

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

  Struts1 Struts2
struts-config.xml  
struts.xml  

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

  Struts1 Struts2
index.jsp  
index.jsp  

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&#20540;,如果有就设置这种语言到环境中,如果没有就得到浏览器默认的语言再设置到环境中(用户在画面设置的locale优先级高于浏览器设置语言得到的locale)。

准备工作:

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

实现:

a.创建的资源文件:

b.web.xml的配置:

	

		localeFilter
		xx.xx.xx. LocaleFilter
	

		localeFilter
		/*
		REQUEST
		FORWARD
	

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

	

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

index.jsp页面html代码

	

		   ${lan}
					
		    
		         

Index.jsp页面Javascript方法

	
function languages(lan){
		var COOKIEsPath = "/";//路径
		var COOKIEsDomain = ".xxx.com";//设置有效的url
		document.COOKIE = "xxx_language="&#43;lan&#43;";path="&#43;COOKIEsPath&#43;";domain="&#43;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中是否有&#20540;,有&#20540;就将COOKIEs中的&#20540;得到一个Locale
		(2)COOKIEs没&#20540;就根据浏览器默认的语言来显示*/
    	
    	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里面是否有&#20540;。
	        	}
	        } 
		}
		try {
			
			/**
			 * 1.如果COOKIEs中是有&#20540;的(前提条件是从页面传过来的语言为空才进下面的逻辑)
			 */
			 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里面的&#20540;就根据浏览器默认的语言来显示
			 */
			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代码中得到资源文件的&#20540;

	
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();




推荐阅读
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • Vue 2 中解决页面刷新和按钮跳转导致导航栏样式失效的问题
    本文介绍了如何通过配置路由的 meta 字段,确保 Vue 2 项目中的导航栏在页面刷新或内部按钮跳转时,始终保持正确的 active 样式。具体实现方法包括设置路由的 meta 属性,并在 HTML 模板中动态绑定类名。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 本文介绍了如何利用JavaScript或jQuery来判断网页中的文本框是否处于焦点状态,以及如何检测鼠标是否悬停在指定的HTML元素上。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 如何在WPS Office for Mac中调整Word文档的文字排列方向
    本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文探讨了在通过 API 端点调用时,使用猫鼬(Mongoose)的 findOne 方法总是返回 null 的问题,并提供了详细的解决方案和建议。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
author-avatar
LKD2008_561
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有