Struts2实现国际化操作及中英文切换

版权声明:转载请注明出处(两个蝴蝶飞) https://blog.csdn.net/yjltx1234csdn/article/details/82109007

“两个蝴蝶飞”特别喜欢"java1234知识分享网"小峰的实用主义,所以本文及其系列文章均是采用实用主义,从项目和代码的角度去分析。由于本人经验有限,嘴皮子不溜,所以学术性,概念性,底层性的知识点暂时不做介绍。文章中有错误之处,欢迎拍砖和指点。特别感谢"java1234知识分享网 "和"黑马程序员官网",所有的资料大部分是两者提供,为了方便书写,故不一一指名出处,请谅解,非常抱歉。


上一章简单介绍了Struts2拦截器的简单应用,登录权限拦截器及与过滤器的区别(八),如果没有看过,请观看上一章


Struts国际化,简写成i18n,全称是internationalization,中间有18个字母. L10n,为本地化 localization。

在说Struts2国际化之前,先说一下Java SE的简单国际化读取。

一  Java SE的简单国际化

JavaSE 提供了一个Locale的类。

一.一  取得所有地区的国家编码和语言编码

        //得到所有地区及它们的主流语言的环境字符串.
		Locale [] localses=Locale.
				getAvailableLocales();
		for (Locale locale : localses) {
			//国家-->国家CN
			System.out.println(
					locale.getDisplayCountry()+
					"-->"+locale.getCountry());
			//语句--->国家的语言 zh
			System.out.println(
					locale.getDisplayLanguage()+
					"----->"+locale.getLanguage());
		}

常用的有中英方切换, 中文: zh-CN,  英文: en_US  。需要其他的编码,可以运行一下程序,或者上网搜索一下。

一.二   读取国际化文件的内容

读取国际化文件,需要有这个文件。一般通常是在src下建立三个文件,一个是基本的,另外两个是中文的和英文的。文件的常见格式命名为:baseName_language_country.properties或者baseName.properties

其中后者一般指的是默认的。 默认为中文。

创建三个属性文件,令baseName命名为i18n。

i18n.properties文件和i18n_zh_CN.properties内容为:

###翻译成中文是 两个蝴蝶飞
i18n.name=\u4e24\u4e2a\u8774\u8776\u98de

i18n_en_US.properties内容为:

i18n.name=YJL

 需要将中文value值转换成Unicode编码。 可以使用在线工具进行转换

用Java提供的ResourceBundle类。

运行默认的属性文件:

        //读取文件  参数为读取的文件名
		ResourceBundle resourceBundle=ResourceBundle.getBundle("i18n");
		//读取属性,参数为key值
		String name=resourceBundle.getString("i18n.name");
		System.out.println("name是:"+name);

运行选择的文件,将语言编码传递进去。

//读取文件  参数为读取的文件名
		//中文
		//ResourceBundle resourceBundle=ResourceBundle.getBundle("i18n",new Locale("zh","CN"));
		//英文
		ResourceBundle resourceBundle=ResourceBundle.getBundle("i18n",new Locale("en","US"));
		//读取属性,参数为key值
		String name=resourceBundle.getString("i18n.name");
		System.out.println("name是:"+name);

一.三  参数传递占位符国际化

中文是:

###带参数传递,欢迎{0}登录,性别是{1},年龄{2}
i18n.welcome=\u6b22\u8fce\u007b\u0030\u007d\u767b\u5f55\u002c\u6027\u522b\u662f\u007b\u0031\u007d\u002c\u5e74\u9f84\u007b\u0032\u007d

英文是:

###带参数
i18n.welcome=Welcome {0} login,sex is {1},age is{2}

是占位符是从0开始的。 将其整体复制进来,连{}也要进行相应的转换。

//读取文件  参数为读取的文件名
		//中文
		ResourceBundle resourceBundle=ResourceBundle.getBundle("i18n",new Locale("zh","CN"));
		//读取属性,参数为key值
		String welcome=resourceBundle.getString("i18n.welcome");
		//实际化所需要的参数  参数不需要转换编码
		Object []params=new Object[]{"两个蝴蝶飞","男",24};
		//利用MessageFormat类进行填充数据
		String wel=MessageFormat.format(welcome,params);
		System.out.println(wel);

 二   Strut2实现国际化

Struts2实现国际化可以在前端实现,也可以在后端进行相应的实现。 一般国际化的都是前端的显示标签和提示内容,故采用前端国际化的较多一点。

在前端国际化时,用一个登录表单的页面来进行相应的说明。(前堤是先搭建一个基本的Struts的运行环境,包括struts.xml和web.xml的配置)

二.一 利用<s:text> 实际国际化

1.首先根据前端的页面标签和提示信息,将国际化内容大致提取出来,放置在国际化的属性文件中。按照i18n.模块.标签的方式进行命名。

zh_CN中文与默认的一致,内容为:

###下面是登录表单login.jsp的国际化配置
###登录页面
i18n.login.title=\u767b\u5f55\u9875\u9762
###用户名
i18n.login.userName=\u7528\u6237\u540d
###密码
i18n.login.password=\u5bc6\u7801
###登陆
i18n.login.submit=\u767b\u9646
###重置
i18n.login.reset=\u91cd\u7f6e
###下面是登录成功表单success.jsp的国际化配置
###带参数传递,欢迎{0}登录,性别是{1},年龄{2}
i18n.success.welcome=\u6b22\u8fce\u007b\u0030\u007d\u767b\u5f55\u002c\u6027\u522b\u662f\u007b\u0031\u007d\u002c\u5e74\u9f84\u007b\u0032\u007d

en_US英文为:

###下面是登录表单login.jsp的国际化配置
###登录页面
i18n.login.title=login page
###用户名
i18n.login.userName=userName
###密码
i18n.login.password=password
###登陆
i18n.login.submit=login
###重置
i18n.login.reset=reset
###下面是登录成功表单success.jsp的国际化配置
###带参数
i18n.success.welcome=Welcome {0} login,sex is {1},age is{2}

2. 在Struts.xml中配置资源所在的路径,改变常量的值。(必须配置,否则找不到文件在哪儿)

<!-- 添加国际化的资源所在的位置 -->
	<constant name="struts.custom.i18n.resources" value="i18n"></constant>

3. 写前端界面,将内容和提示信息都换成<s:text name="key">的形式。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><s:text name="i18n.login.title"/></title>
</head>
<body>
	<s:form action="User_login.action" namespace="/" method="post">
			<s:text name="i18n.login.userName"/>: <s:textfield  name="name"/>  <br/>
			<s:text name="i18n.login.password"/>: <s:password name="password"/><br/>
   			<%--
   			下面写法都是错误的,无法正常显示。
   			<s:submit value='%{<s:text name="i18n.login.submit"/>}'/>
   			<s:reset value="<s:text name='i18n.login.reset'/>"/>
   			 --%>
   			<input type="submit" value="<s:text name='i18n.login.submit'></s:text>"/>
   			<input type="reset" value="<s:text name='i18n.login.reset'></s:text>"/>
	</s:form>
</body>
</html>

注意,<s:submit>是无法使用的,改成标准的html标签即可。

也可以使用<s:set> 先setter一样,然后再使用。  用getText()方式来获取。

             <s:set var="submit" value="getText('i18n.login.submit')"/>
   			 <s:submit value="%{submit}"></s:submit>

4. 在前端界面时,也可以传递相应的参数。用<s:param>

在成功界面,填充参数。

    <s:text name="i18n.success.welcome">
		<s:param name="0">蝴蝶飞</s:param>
		<s:param name="1">男</s:param>
		<s:param name="2">24</s:param>
	</s:text>

运行后结果为: 

现在改变成英文状态, goole浏览器改变settings,高级选择语言,添加美国英语,并将其选择为浏览器语言,并move to up,移动到最上面

 运行一下login.jsp和success.jsp,结果显示如下: 可以正常国际化

有三个占位符,如果只填充两个呢,将24去掉: 不出错,多余的不填充。

 如果多填充一个呢?  也不出错,会将多余的进行截取。

5. 在Struts中也可以进行后端的读取,在跳转到"toLogin"---(显示Login.jsp) 之前,也就是在toLogin()方法时,将login.jsp上所显示的标签全部读取出来,进行设置存放,到达login.jsp页面时再进行显示。 特别麻烦,用前端<s:text>

6. 有的会将属性文件放在相对应的包下,即本项目中,在com.yjl.web包下新建一个properties包,然后将属性文件放置在里面。感觉不太好用,故最好放在src目录下。

三  中英文链接动态选择语言

实现的效果是,在登录页面或者主页面选择一种语言,然后全局都使用这种语言。 如Login.jsp时显示一种默认的语言,有一个选择语言的框,点击中文后,跳转到success.jsp显示中文,success.jsp跳转到list.jsp也会显示中文。在login.jsp页面点击英文后,跳转到success.jsp显示英文,success.jsp跳转到list.jsp也会显示英文。 模拟这种全局都显示一种语言的项目。要想全局都使用这种语言,就需要对全局性进行一次判断,故最好用拦截器实现。 非常幸运的是,Struts2中有一个i18n的拦截器,我们只需要稍微添加一些操作即可。

1. 正常写LoginAction代码。

package com.yjl.web.action;

import com.opensymphony.xwork2.ActionSupport;

/**
* @author 两个蝴蝶飞
* @version 创建时间:Aug 27, 2018 10:56:50 AM
* 登录的国际化操作
*/
public class LoginAction extends ActionSupport{
	private static final long serialVersionUID = 1L;
	//跳转到首页,用的是默认的语言环境
	public String toLogin(){
		return "toLogin";
	}
	//跳转到登录页面,用的是选择的语言环境
	public String login(){
		return SUCCESS;
	}
	//根据所选择的语言环境,继续相应的跳转,表示全局性选择语言。
	public String list(){
		return "list";
	}
}

2. 正常配置Struts.xml的简单配置

<struts>
	<!--修改国际化编码 -->
	<constant name="struts.i18n.encoding" value="UTF-8"></constant>
	<constant name="struts.devMode" value="true"></constant>
	<!-- 添加国际化的资源所在的位置 -->
	<constant name="struts.custom.i18n.resources" value="i18n"></constant>
	<!--修改struts中ui的主题,为simple-->
	<constant name="struts.ui.theme" value="simple"></constant>
	<package name="user" extends="struts-default" namespace="/">
		<action name="Login_*" class="com.yjl.web.action.LoginAction" method="{1}">
				<result name="toLogin">/login.jsp</result>
				<result name="success">/success.jsp</result>
				<result name="list">/list.jsp</result>
		</action>
	</package>
</struts>

3. 开发各个页面

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><s:text name="i18n.login.title"/></title>
</head>
<body>
	<s:form action="Login_login.action" namespace="/" method="post">
			<s:text name="i18n.login.userName"/>: <s:textfield  name="name"/>  <br/>
			<s:text name="i18n.login.password"/>: <s:password name="password"/><br/>
 
   			<input type="submit" value="<s:text name='i18n.login.submit'></s:text>"/>
   			<input type="reset" value="<s:text name='i18n.login.reset'></s:text>"/>
   			<s:a action="Login_login.action?request_locale=zh_CN" namespace="/">中文</s:a>
   			<s:a action="Login_login.action?request_locale=en_US" namespace="/">英文</s:a>
	</s:form>
</body>
</html>

success.jsp页面

<body>
	<s:text name="i18n.success.welcome">
		<s:param name="0">两个蝴蝶飞</s:param>
		<s:param name="1">男</s:param>
		<s:param name="2">24</s:param>
	</s:text>
	<s:a action="Login_list" namespace="/">跳转到list页面</s:a>
</body>
</html>

list.jsp页面

<body>
	<s:text name="i18n.success.welcome">
		<s:param name="0">YJL</s:param>
		<s:param name="1">男</s:param>
		<s:param name="2">24</s:param>
	</s:text>
</body>
</html>

4. 重启服务器,检测逻辑是否正确

重启服务器,页面按照设定进行相应的跳转,只是语言只是一种语言,没有改变。 因为并没有写拦截器呢。

5. 创建国际化拦截器类I18nInterceptor

在com.yjl.web.interceptor包下创建一个类 I18nInterceptor

package com.yjl.web.interator;
import java.util.Locale;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

/**
* @author 两个蝴蝶飞
* @version 创建时间:Aug 27, 2018 5:44:21 PM
* 类说明  国际化的拦截器
*/
public class I18NInterceptor extends MethodFilterInterceptor{
	private static final long serialVersionUID = 1L;
	@Override
	protected String doIntercept(ActionInvocation ai) throws Exception {
		//1. 得到ActionContext对象,从而获取session
		ActionContext actionContext=ai.getInvocationContext();
		Map<String,Object> session=(Map<String, Object>) actionContext.getSession();
		//2.得到里面设置的值Locale  注意key值
		Locale locale=(Locale) session.get("WW_TRANS_I18N_LOCALE");
		//3. 判断这个值是否为null,如果为null则设置一个默认值
		if(locale==null){
			Locale defaultLocale=new Locale("zh","CN");
			//将其设置到session中
			session.put("WW_TRANS_I18N_LOCALE", defaultLocale);
		}
		//返回
		return ai.invoke();
	}
}

其中Locale defaultLocale=new Locale("zh","CN"); 是采用硬编码编码进去的。

六  在struts.xml中配置拦截器 (拦截器的具体使用请参照上一章)\

<package name="user" extends="struts-default" namespace="/">
		<!-- 配置拦截器,对每一个action都进行拦截 -->
		<interceptors>
			<interceptor name="i18nInterceptor" class="com.yjl.web.interator.I18NInterceptor"></interceptor>
			<interceptor-stack name="defaultStack">
				<interceptor-ref name="i18nInterceptor"></interceptor-ref>
				<interceptor-ref name="defaultStack"></interceptor-ref>
			</interceptor-stack>
		</interceptors>
		<action name="Login_*" class="com.yjl.web.action.LoginAction" method="{1}">
				<result name="toLogin">/login.jsp</result>
				<result name="success">/success.jsp</result>
				<result name="list">/list.jsp</result>
		</action>
	</package>

七  重启服务器,验证语言是否可以进行选择

经过验证,发现可以正常的进行跳转,是多种语言的跳转。

选择中文:

 选择英文:

八  国际化完善操作

项目中有两个小的不完美的地方,第一,默认语言是硬编码。 第二,选择中英文时,不能是两个单独的链接,而应该是一个select框进行选择。

八.一 解决默认语言硬编码

在I18nInterceptor拦截器中添加两个参数,country和language,并指明默认参数为"zh","cn". 表明用户可以不选择这两个参数。

private String country="zh";
	private String language="CN";
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public String getLanguage() {
		return language;
	}
	public void setLanguage(String language) {
		this.language = language;
	}

在struts.xml中配置时:

<interceptors>
			<interceptor name="i18nInterceptor" class="com.yjl.web.interator.I18NInterceptor"></interceptor>
			<interceptor-stack name="defaultStack">
				<interceptor-ref name="i18nInterceptor">
					<param name="country">en</param>
					<param name="language">US</param>
				</interceptor-ref>
				<interceptor-ref name="defaultStack"></interceptor-ref>
			</interceptor-stack>
		</interceptors>

八.二 解决链接显示的问题(最后终于成功)

login.jsp页面

	<div class="content">
		<s:form action="Login_login.action" namespace="/" method="post">
				<s:text name="i18n.login.userName"/>: <s:textfield  name="name"/>  <br/>
				<s:text name="i18n.login.password"/>: <s:password name="password"/><br/>
	   			<input type="submit" value="<s:text name='i18n.login.submit'/>"/>
	   			<input type="reset" value="<s:text name='i18n.login.reset'/>"/>
		</s:form>
	</div>
	<s:select name="i18nCharset" id="i18nSelect" list="#{'zh_CN':'中文','en_US':'英文'}">
   				<%--这里中文和英文也应该用国际化<s:text>显示的,为了简便,为中文写出来 
   					不能用html注释--%>
   				<!-- <option value="zh_CN">中文</option>
   				<option value="en_US">英文</option> -->
   	</s:select>

引入相应的js并且实现代码

<!-- 在线引入jquery 需要联网,用户可以自己下载后本地引用即可-->
<script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
<script>
	$(document).ready(function(){
		$("select#i18nSelect").change(function(){
			//select改变时触发整个
			//取得option中的值
			var charset=$("select#i18nSelect option:selected").val();
			$.post("/Struts_i18n/Login_charsetChange.action",{"request_locale":charset},
					 function(data,status){
		       			 //成功之后,刷新一下界面
		       				window.location.reload();
		       				//设置回显所选择的语言类型 没有作用的
		       					$("select#i18nSelect").val(charset);
		       				
					}
		    );
		   //window.location.href="/Struts_i18n/Login_charsetChange.action?//request_locale="+charset;
		})
		
	});
	
</script>

那么Action中:

//语言编码改变时调用这一个
	public String charsetChange(){
		return "charsetChange";
	}

在struts.xml中

<package name="user" extends="struts-default,json-default" namespace="/">
		<!-- 配置拦截器,对每一个action都进行拦截 -->
		<interceptors>
			<interceptor name="i18nInterceptor" class="com.yjl.web.interator.I18NInterceptor"></interceptor>
			<interceptor-stack name="defaultStack">
				<interceptor-ref name="i18nInterceptor">
					<param name="country">en</param>
					<param name="language">US</param>
				</interceptor-ref>
				<interceptor-ref name="defaultStack"></interceptor-ref>
			</interceptor-stack>
		</interceptors>
		<action name="Login_*" class="com.yjl.web.action.LoginAction" method="{1}">
				<result name="toLogin">/login.jsp</result>
				<result name="charsetChange">/login.jsp</result>
				<result name="success">/success.jsp</result>
				<result name="list">/list.jsp</result>
		</action>
	</package>
</struts>

需要引入关于json的包json-default, 其中必须要引入json与struts的jar包。

 重启服务器,运行。 并不能达到预期的效果。原因是,每次在刷新之后,都会将整个页面刷新,后面的js代码根本不执行。调试了很长时间,不行。

最后决定用两个ajax来实现,也就是说将设置select的值单独放在一个ajax里面。这样就可以使用了。(用到的知识点是Struts2利用ajax传递json数据)

Action中:

添加一个charset字符串数据,实现setter和getter方法,传递选择的数据。然后添加一个getCharacterSelect()方法。

package com.yjl.web.action;

import java.util.Locale;
import java.util.Map;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

/**
* @author 两个蝴蝶飞
* @version 创建时间:Aug 27, 2018 10:56:50 AM
* 登录的国际化操作
*/
public class LoginAction extends ActionSupport{
	private static final long serialVersionUID = 1L;
	private String charset;
	public void setCharset(String charset) {
		this.charset = charset;
	}
	public String getCharset() {
		return charset;
	}

	//跳转到首页,用的是默认的语言环境
	public String toLogin(){
		return "toLogin";
	}
	//跳转到登录页面,用的是选择的语言环境
	public String login(){
		return SUCCESS;
	}
	//根据所选择的语言环境,继续相应的跳转,表示全局性选择语言。
	public String list(){
		return "list";
	}
	//语言编码改变时调用这一个
	public String charsetChange(){
		return "charsetChange";
	}
	//获取相应的编码
	public String getCharsetSelect(){
		Map<String,Object> session=(Map<String, Object>) ActionContext.getContext().getSession();
		Locale locale=(Locale) session.get("WW_TRANS_I18N_LOCALE");
		//取得值
		charset=locale.getLanguage()+"_"+locale.getCountry();
		System.out.println("获取的值:"+charset);
		return "getCharsetSelect";
	}
}

在struts.xml中:

    <action name="Login_*" class="com.yjl.web.action.LoginAction" method="{1}">
				<result name="toLogin">/login.jsp</result>
				<result name="charsetChange">/login.jsp</result>
                <!--注意json形式的写法-->
				<result name="getCharsetSelect" type="json">
					<param name="root">charset</param>
				</result>
				<result name="success">/success.jsp</result>
				<result name="list">/list.jsp</result>
				
		</action>

在js中:

<!-- 在线引入jquery 需要联网,用户可以自己下载后本地引用即可-->
<script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
<script>
	$(document).ready(function(){
		$("select#i18nSelect").change(function(){
			//select改变时触发整个
			//取得option中的值
			var charset=$("select#i18nSelect option:selected").val();
				$.post("/Struts_i18n/Login_charsetChange.action",{"request_locale":charset},
						 function(data,status){
			       			 //成功之后,刷新一下界面
			       			window.location.reload();
						}
			    );
		   // window.location.href="/Struts_i18n/Login_charsetChange.action?request_locale="+charset;
		});
	});
	$(document).ready(function(){
		$.post("/Struts_i18n/Login_getCharsetSelect.action",
				 function(data,status){
					//alert("运行成功");
					//alert(data);
					var charset=data;
					//alert(charset);
					//alert("zh_CN");
					//alert(charset=="zh_CN");
					//alert(charset);
	       			 $("select#i18nSelect").val(charset);
				}
		);
	});
</script>

 这样就可以实现自动回显的操作了。 注意两个js思想的使用。

 

谢谢!!!

猜你喜欢

转载自blog.csdn.net/yjltx1234csdn/article/details/82109007
今日推荐