Struts 2 的国际化(二)

 

二、 Struts 2 的国际化入门

 

    Struts 2 国际化是建立在 Java 国际化的基础之上,一样也是通过提供不同国家/语言环境的消息资源,然后通过 ResourceBundle 加载指定 Locale 对应的资源文件,再取得该资源文件中指定 key 对应的消息。整个过程与 Java 程序的国际化完全相同,只是 Struts 2 框架对 Java 程序国际化进行了进一步封装,简化。


2.1 加载全局资源文件

 

    Struts 2 提供了很多加载国际化资源文件的方法,最简单、最常用的就是加载全局的国际化资源文件这种方式是通过配置常量来实现不管在 struts.xml ,还是在 struts.properties 文件中配置常量,只需要配置 struts.custom.i18n.resources 常量即可

 

假设系统需要加载的国际化资源文件的 baseName 为 messageResource,则:

struts.properties

struts.custom.i18n.resources=messageResource
 

struts.xml

<constant name="struts.custom.i18n.resources" value="messageResource"/>

 

通过这种方式加载国际化资源文件后,Struts 2 应用就可以在所有地方取出这些国际化资源文件了,包括 JSP 和 Action

 

2.2 访问国际化消息

 

  Struts 2 既可以在 JSP 页面中通过标签输出国际化消息,也可以在 Action 类中输出国际化消息。

 

  Struts 2 访问国际化消息主要有如下 3 种方式:

●  JSP 页面,可以使用 Struts 2 的 <s:text .../> 标签,该标签可以指定一个 name 属性,该属性指定了国际化资源文件中的 Key

●  Action 类中,可以使用 ActionSupport 类的 getText() 方法,该方法接受一个 name 参数,该参数指定了国际化资源文件中的 Key

●  表单元素Label 里输出国际化信息 ,可以为该表单标签指定一个 key 属性,该 key 指定了国际化资源文件中的 Key

 

messageResource_en_US.properties

#资源文件的内容就是key-value对
loginPage=Login Page
errorPage=Error Page
succPage=Welcome Page
failTip=Sorry,You can't log in!
succTip=welcome,you has logged in!
user=User Name
pass=User Pass
login=Login

messageResource_zh_CN.properties

loginPage=登录页面
errorPage=错误页面
succPage=成功页面
failTip=对不起,您不能登录!
succTip=欢迎,您已经登录!
user=用户名
pass=密  码
login=登录
 

上面 messageResource_zh_CN.properties 文件必须使用 native2ascii 工具处理。

 

提供上面 2 份资源文件后,通过上一节所介绍的方式加载国际化资源文件,系统会根据浏览者所在的 Locale 来加载对应的语言资源文件。

 

login.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title><s:text name="loginPage"/></title>
	<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
<s:form action="login">
	<s:textfield name="username" key="user"/>
	<s:textfield name="password" key="pass"/>
	<s:submit key="login"/>
</s:form>
</body>
</html>
 

上面 JSP <s:text .../> 标签直接输出国际化信息,也通过表单元素中指定 key 属性来输出国际化消息 。通过这种方式,就可以完成 JSP 中普通文本、表单元素标签的国际化。

 

如果在 Action 中,可以用 ActionSupport getText() 方法

LoginAction.java

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

public class LoginAction extends ActionSupport
{
	//封装两个请求参数的属性
	private String username;
	private String password;

	//username属性的setter和getter方法
	public void setUsername(String username)
	{
		this.username = username;
	}
	public String getUsername()
	{
		return this.username;
	}

	//password属性的setter和getter方法
	public void setPassword(String password)
	{
		this.password = password;
	}
	public String getPassword()
	{
		return this.password;
	}

	//定义处理用户请求的execute方法
	public String execute()throws Exception
	{
		ActionContext ctx = ActionContext.getContext();
		//用户登录成功
		if (getUsername().equals("crazyit")
			&& getPassword().equals("leegang") )
		{
			ctx.getSession().put("user" , getUsername());
			//调用getText方法取出国际化消息
			ctx.put("tip" , getText("succTip"));
			return SUCCESS;
		}
		else
		{
			//调用getText方法取出国际化消息
			ctx.put("tip" , getText("failTip"));
			return ERROR;
		}
	}
}
 

通过这种方式,即使 Action 需要设置在下一个页面显示的信息,也无需直接设置字符串常量,而是使用国际化消息的 key 来输出,从而实现程序的国际化。

 

struts.xml

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
	"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<constant name="struts.custom.i18n.resources"
		value="messageResource"/>
	<constant name="struts.i18n.encoding" value="GBK"/>

	<package name="lee" extends="struts-default">
		<action name="login" class="lee.LoginAction">
			<result name="error">/error.jsp</result>
			<result>/welcome.jsp</result>        
		</action>
		<action name="">
			<result>.</result>        
		</action>
	</package>
</struts>

 

welcome.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title><s:text name="succPage"/></title>
	<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
	${requestScope.tip}
</body>
</html>

 error.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title><s:text name="errorPage"/></title>
	<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
	${requestScope.tip}
</body>
</html>
 

 

2.3 输出带占位符的国际化消息

 

Java 中使用 MessageFormat 类,完成填充占位符

 

Struts 2 更方便,提供 2 种方式 来填充消息字符串中的占位符

 

 JSP 页面中,则可以通过 <s:text .../> 标签中使用多个 <s:param ...> 标签来填充消息中的占位符。第一个 <s:param ...> 指定第一个占位符值,第二个 <s:param ...> 指定第二个占位符值,依此类推 

 Action 中,则可以通过在调用 getText(String aTextName , List args) getText(String key , String[] args) 方法来填充占位符。

 

 

例如:

messageResource_zh_CN.properties

loginPage=登陆页面
errorPage=错误页面
succPage=成功页面
failTip={0},对不起,您不能登录!
succTip={0},欢迎,您已经登录!
welcomeMsg={0},您好!现在时间是{1}!
user=用户名
pass=密  码
login=登陆

 messageResource_en_US.properties

loginPage=Login Page
errorPage=Error Page
succPage=Welcome Page
failTip={0},Sorry,You can't log in!
succTip={0},Welcome,you has logged in!
welcomeMsg={0},Hello!Now is {1}!
user=User Name
pass=User Pass
login=Login
  

LoginAction.java

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

public class LoginAction extends ActionSupport {
    // 定义两个属性,username和password,用于封装两个请求参数
    private String username;

    private String password;

    // username属性的setter和getter方法
    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsername() {
        return this.username;
    }

    // password属性的setter和getter方法
    public void setPassword(String password) {
        this.password = password;
    }

    public String getPassword() {
        return this.password;
    }

    // 下面省略了两个属性的setter和getter方法
    // ...

    // 定义处理用户请求的execute方法
    public String execute() throws Exception {
        ActionContext ctx = ActionContext.getContext();
        // 用户登录成功
        if (getUsername().equals("crazyit") && getPassword().equals("leegang")) {
            ctx.getSession().put("user", getUsername());
            // 调用getText方法取出国际化信息,使用字符串数组为占位符设置值
            ctx.put("tip", getText("succTip", new String[]{username}));
            return SUCCESS;
        } else {
            // 调用getText方法取出国际化信息,使用字符串数组为占位符设置值
            ctx.put("tip", getText("failTip", new String[]{username}));
            return ERROR;
        }
    }
}
 

welcome.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title><s:text name="succPage"/></title>
	<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
	${requestScope.tip}<br/>
	<jsp:useBean id="d" class="java.util.Date" scope="page"/>
	<s:text name="welcomeMsg">
		<s:param><s:property value="username"/></s:param>
		<s:param>${d}</s:param>
	</s:text>
</body>
</html>

 

上面页面 使用 ${requestScope.tip} 输出 Action类 中取出的国际化消息,通过 <s:text .../> 取出另一个国际化消息,使用 2 个 <param .../> 指定 2 个占位符的值

 

login.jsp

<head>
	<title><s:text name="loginPage"/></title>
	<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
<s:form action="login">
	<s:textfield name="username" key="user"/>
	<s:textfield name="password" key="pass"/>
	<s:submit key="login"/>
</s:form>
</body>
 

struts.xml

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
	"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<constant name="struts.custom.i18n.resources"
		value="messageResource"/>
	<constant name="struts.i18n.encoding" value="GBK"/>

	<package name="lee" extends="struts-default">
		<action name="login" class="lee.LoginAction">
			<result name="error">/error.jsp</result>
			<result>/welcome.jsp</result>        
		</action>
		<action name="">
			<result>.</result>        
		</action>
	</package>
</struts>
 

 

除此之外,Struts 2提供了对占位符的一种替代方式

这种方式可以避免在使用国际化消息时还需要为占位符传入参数值,如下:

 

#在消息资源中使用表达式
failTip=${username},对不起,您不能登录!
succTip=${username},欢迎,您已经登录!

在上面的消息资源中,通过使用表达式,可以从 ValueStack 中取出该 username 属性值。 自动填充到该消息资源中。


这种方式,当需要 Action 中使用该消息资源时,无需为该消息资源传入参数,即当使用 getText() 方法获取国际化消息时,无需为消息资源中的占位符传入参数

 

 

三、 加载资源文件的不同方式


  前面介绍了最常见的方式,除此之外,Struts 2 还提供了多种方式来加载国际化资源文件,包括指定包范围资源文件 类范围资源文件 临时指定资源文件 等。

 

 

3.1 包范围资源文件

 

   把所以国际化资源都放在同一个全局文件里,文件会过大。为了更好地体现软件工程里 分而治之 的原则,Struts 2 允许针对不同模块、不同 Action 来组织国际化资源文件。


包范围资源文件: 在包的根路径下建立多个文件名为 package_language_country.properties 的文件,一旦建立了这个系列的国际化资源文件,应用中处于该包下的所有 Action 都可以访问该资源文件。

 

注意: 上面的包范围资源文件的 baseName 就是 package ,不是 Action 所在包名。该文件通常只需放在该包的根路径下即可

 

lee.action 下 有 LoginAction.java

package lee.action;

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

public class LoginAction extends ActionSupport
{
	//下面定义了两个属性,用于封装请求参数
	private String username;
	private String password;
	//此处省略了各属性的setter和getter方法

	//username属性的setter和getter方法
	public void setUsername(String username)
	{
		this.username = username;
	}
	public String getUsername()
	{
		return this.username;
	}

	//password属性的setter和getter方法
	public void setPassword(String password)
	{
		this.password = password;
	}
	public String getPassword()
	{
		return this.password;
	}

	//处理用户请求的execute方法
	public String execute() throws Exception
	{
		ActionContext ctx = ActionContext.getContext();
		if (getUsername().equals("crazyit")
			&& getPassword().equals("leegang"))
		{
			ctx.getSession().put("user" , getUsername());
			//取出国际化消息
			ctx.put("tip" , getText("succTip"));
			return SUCCESS;
		}
		else
		{
			//取出国际化消息
			ctx.put("tip" , getText("failTip"));
			return ERROR;
		}
	}
}

 

struts.xml  

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
	"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<constant name="struts.custom.i18n.resources"
		value="messageResource"/>
	<constant name="struts.i18n.encoding" value="GBK"/>

	<package name="lee" extends="struts-default">
		<action name="login" class="lee.action.LoginAction">
			<result name="error">/error.jsp</result>
			<result>/welcome.jsp</result>        
		</action>
		<action name="">
			<result>.</result>        
		</action>
	</package>
</struts>
 

lee 下 有:package_en_US.properties

failTip=Package Scope:Sorry,You can't log in!
succTip=Package Scope:welcome,you has logged in!

 lee 下 有:package_zh_CN.properties

failTip=包范围消息:对不起,您不能登录!
succTip=包范围消息:欢迎,您已经登录!
 

注意: 这 2 份资源文件保存在 WEB-INF/classes/lee 路径下,该资源文件就可以被位于 lee 包 及 lee 包下所有子包内的 Action 访问了

 

结论: Action 将优先使用包范围的资源文件 ,虽然也提供了全局范围的资源文件,但是 Action 优先使用包范围的资源文件

 

 

3.2  Action 范围资源文件

 

Struts 2 还允许为 Action 单独指定一份国际化资源文件。

 

Action 单独指定国际化资源文件的方法 是:

Action 文件所在的路径建立多个文件名为 ActionName_language_country.properties 的文件,一旦建立了这个系列的国际化资源文件Action 将可以访问该 Action 范围的资源文件。

 

还是使用前一节的 Action 类,该 Action 类的类文件位于 WEB-INF/classes/lee/action 路径下,于是我们建立如下 2 份资料文件

 

LoginAction_en_US.properties

failTip=Action Scope:Sorry,You can't log in!
succTip=Action Scope:welcome,you has logged in!

 LoginAction_zh_CN.properties

failTip=Action范围消息:对不起,您不能登录!
succTip=Action范围消息:欢迎,您已经登录!
 

一旦建立了这 2 份资源文件,lee.action.LoginAction 将优先加载 Action 范围的资源文件。

 

 

通过使用这种 Action 范围的资源文件,就可以在不同的 Action 里使用相同的 key 名来表示不同的字符串值 。例如,在 ActionOne 中 title 为 “动作一”,而同样用 title 在 ActionTwo 中则可以表示 “动作二” ,这样就可以简化 key 的命名,无需像 Struts 1 中使用 loginForm.title、registForm.title 来以示区分了。

 

提示: Action 范围的资源文件和包范围的资源文件同时存在时,系统将优先使用 Action 范围的资源文件

 

 

 

3.3  临时指定资源文件

 

临时指定资源文件的方式: 可以在 JSP 页面中输出国际化消息时临时指定国际化资源的位置。

在这种方式下,需要借助 Struts 2 的另外一个标签:<s:i18n .../>

 

如果把 <s:i18n .../> 标签作为 <s:text .../> 标签的父标签,则 <s:text .../> 标签将会直接加载 <s:i18n .../> 标签里指定的国际化资源文件;如果把 <s:i18n .../> 标签当成表单标签的父标签,则表单标签的 key 属性将会从国际化资源文件中加载该消息。

 

 

WEB-INF/classes 路径下,假设包含如下 2 份资源文件:

tmp_zh_CN.properties

#在JSP页面使用的临时资源文件
loginPage=临时消息:登录页面
errorPage=临时消息:错误页面
succPage=临时消息:成功页面
failTip=临时消息:全局消息:对不起,您不能登录!
succTip=临时消息:全局消息:欢迎,您已经登录!
user=临时消息:用户名
pass=临时消息:密  码
login=临时消息:登录
 

tmp_en_US.properties

#在JSP页面临时使用的资源文件
loginPage=Temp Message:Login Page
errorPage=Temp Message:Error Page
succPage=Temp Message:Welcome Page
failTip=Temp Message:Global Message:Sorry,You can't log in!
succTip=Temp Message:Global Message:welcome,you has logged in!
user=Temp Message:User Name
pass=Temp Message:User Pass
login=Temp Message:Login
 

login.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>
	<s:i18n name="tmp">
		<s:text name="loginPage"/>
	</s:i18n>
	</title>
	<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
<!-- 使用i18n作为s:text标签的父标签,临时指定国际化资源文件的baseName为tmp -->
<s:i18n name="tmp">
	<s:form action="login">
		<s:textfield name="username" key="user"/>
		<s:textfield name="password" key="pass"/>
		<s:submit key="login"/>
	</s:form>
</s:i18n>
</body>
</html>
 

 

3.4  加载资源文件的顺序

 

Struts 2 提供了如此多的方式来加载国际化资源文件,这些加载国际化资源文件的方式有自己的优先顺序。假设需要在 ChildAction 中访问国际化消息,则系统加载国际化资源文件的优先级 是:

 

  ①  优先加载系统中保存在 ChildAction 的类文件相同位置,且 baseName ChildAction 的系列资源文件。

  ②  如果在 中找不到指定 key 对应的消息,且 ChildAction 有父类 ParentAction ,则加载系统中保存在 ParentAction 的类文件相同位置,且 baseName ParentAction 的系列资源文件。

  ③  如果在 中找不到指定 key 对应的消息,且 ChildAction 有实现接口 IChildAction ,则加载系统中保存在 IChildAction 的类文件相同位置,且 baseName IChildAction 的系列资源文件。

  ④  如果在 中找不到指定 key 对应的消息,且 ChildAction 有实现接口 ModelDriven (即使用模型驱动模式),则对于 getModel() 方法返回的 model 对象,重新执行第 操作。

  ⑤   如果在 中找不到指定 key 对应的消息,则查找当前包下 baseName package 的系列资源文件。

  ⑥  如果在 中找不到指定 key 对应的消息,则沿着当前包上溯,直到最顶层包来查找 baseName package 的系列资源文件。

  ⑦  如果在 中找不到指定 key 对应的消息,则查找 struts.custom.i18n.resources 常量指定 baseName 的系列资源文件。

  ⑧  如果经过上面步骤一直找不到该 key 对应的消息,将直接输出该 key 的字符串值;如果在上面的步骤 ~ 的任一步中,找到指定 key 对应的消息,系统将停止搜索,直接输出该 key 对应的消息

 

 

对于在 JSP 中访问国际化消息,则简单得多,分成 2 种形式

●  对于使用 <s:i18n .../> 标签作为父标签的 <s:text .../> 标签、表单标签的形式:

  将从 <s:i18n .../> 标签指定的国际化资源文件中加载指定 key 对应的消息。

  如果在 中找不到指定 key 对应的消息,则查找 struts.custom.i18n.resources 常量指定 baseName 的系列资源文件

  如果经过上面步骤一直找不到该 key 对应的消息,将直接输出该 key 的字符串值;如果在上面的步骤 ①~② 的任一步中,找到指定 key 对应的消息,系统停止搜索,直接输出该 key 对应的消息。


●  如果 <s:text .../> 标签、表单标签没有使用 <s:i18n.../> 标签作为父标签:

   直接加载 struts.custom.i18n.resources 常量指定 baseName 的系列资源文件。如果找不到该 key 对应的消息,将直接输出该 key 的字符串值;否则,则输出该 key 对应的国际化消息。

 

 

四、允许用户自行选择程序语言

 

    在很多成熟的商业软件中,可以让用户自由切换语言,当用户进入系统时,可以出现一个下拉列表框,让用户选择语言。

    struts 2 也可以允许用户自行选择语言。而且 更加简单!

 

4.1  Struts 2 国际化的运行机制

 

  Struts 2 中,通过 ActionContext.getContext().setLocale(Locale arg) 设置用户的默认语言,不过这种方式完全是一种手动方式,而且需要编程实现。

 

为了简化设置用户默认语言环境, Struts 2 提供了一个名为 i18n 的拦截器Interceptor ),并将其注册在默认的拦截器栈中(defaultStack

 

struts2-core-2.2.1.jar struts-default.xml 中有如下片段:

<interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="debugging"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                  <param name="excludeParams">dojo\..*,^struts\..*</param>
                </interceptor-ref>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
            </interceptor-stack>
 

 ★   i18n 拦截器在执行 Action 方法前,自动查找请求中一个名为 request_locale 的参数。如果该参数存在,拦截器就将其作为参数转换成 Locale 对象,并将其设为用户默认的 Locale

   除此之外,i18n 拦截器还会将上面生成的 Locale 对象保存在用户 Session 的名为 "WW_TRANS_I18N_LOCALE " 属性中。一旦用户 Session 中存在 "WW_TRANS_I18N_LOCALE " 属性,该属性指定的 Locale 会作为浏览者的默认 Locale

 

 

4.2  创建下拉列表框、选择程序语言

 

   实现用户自行选择程序语言功能,只需提供一个下拉框列表,并且当用户选择下拉框中某一项时,系统将该下拉项的值作为 request _locale 参数提交给 Struts 2 .

 

定义一个 javabean 保存系统支持的全部语言:

Locales.java

import java.util.*;

//该JavaBean存放了系统所支持的全部语言
public class Locales {
    // 使用current保存用户当前选择的Locale
    private Locale current;

    public void setCurrent(Locale cur) {
        this.current = cur;
    }

    // 取得本系统所支持的全部语言
    public Map<String, Locale> getLocales() {
        // 将当前系统支持的全部语言保持在Map对象中
        Map<String, Locale> locales = new Hashtable<String, Locale>();
        ResourceBundle bundle = ResourceBundle.getBundle("messageResource",
            current);
        // 添加当前系统支持的语言,key是系统支持语言的显示名字,
        // value是系统支持语言的Locale实例
        locales.put(bundle.getString("enus"), Locale.US);
        locales.put(bundle.getString("zhcn"), Locale.CHINA);
        return locales;
    }
}
 

上述,Map 的 key 是所支持语言的显示名字,value 是所支持语言的 Locale 实例

 


selectlanguage.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<script type="text/javascript">
function langSelecter_onChanged()
{
	document.getElementById("langForm").submit();
}
</script>

<!-- 将HTTP Session中的"WW_TRANS_I18N_LOCALE"
	属性值设置成SESSION_LOCALE -->
<s:set name="SESSION_LOCALE" value="#session['WW_TRANS_I18N_LOCALE']"/>

<!-- 使用lee.Locales创建locales实例 -->
<s:bean id="locales" name="lee.Locales">
	<!-- 为locales实例传入current参数值 -->
	<s:param name="current" 
		value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"/>
</s:bean>

<form action="<s:url/>" id="langForm" 
    style="background-color:#bbbbbb; padding-top: 4px; padding-bottom: 4px;">
    
    <s:text name="language"/>
	<s:select label="Language" list="#locales.locales" 
		listKey="value" listValue="key"
        value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"
        name="request_locale" id="langSelecter" 
        οnchange="langSelecter_onChanged()" theme="simple"/>
</form>
 

注意: 使用 <s:set .../> 将用户 Session 的 " WW_TRANS_I18N_LOCALE " 属性值设置成 SESSION_LOCALE ,并创建了 lee.Locales 类的 locales 实例,并为该实例传入 current 参数值,先判断 SESSION_LOCALE 是否为 null ,如果为 null   则返回 ValueStack 中的 locale 属性值(即用户浏览器设置的 Locale );如果不为 null ,则返回  SESSION_LOCALE 的值(即用户选择的 Locale

 

 

messageResource_en_US.properties

loginPage=Login Page
errorPage=Error Page
succPage=Welcome Page
failTip=Sorry,You can't log in!
succTip=welcome,you has logged in!
user=User Name
pass=User Pass
login=Login

language=Select Lanuage
enus=American English
zhcn=Simplified Chinese
 

messageResource_zh_CN.properties

loginPage=登陆页面
errorPage=错误页面
succPage=成功页面
failTip=对不起,您不能登录!
succTip=欢迎,您已经登录!
user=用户名
pass=密  码
login=登陆

language=选择语言
enus=美式英语
zhcn=简体中文
 

本例 JSP 都放在 WEB-INF/jsp 下,从而避免直接访问 JSP 页面,让所有 JSP 页面都能得到  Struts 2 处理

 

struts.xml

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
	"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<constant name="struts.custom.i18n.resources"
		value="messageResource"/>
	<constant name="struts.i18n.encoding" value="GBK"/>

	<package name="lee" extends="struts-default">
		<action name="login" class="lee.LoginAction">
			<result name="error">/WEB-INF/jsp/error.jsp</result>
			<result name="success">/WEB-INF/jsp/welcome.jsp</result>
		</action>
		<action name="*">
			<result>/WEB-INF/jsp/{1}.jsp</result>
		</action>
		<action name="">
			<result>.</result>
		</action>
	</package>
</struts>

 

 

<action name="*">
        <result>/WEB-INF/jsp/{1}.jsp</result>
 </action>

 上面代码 请求 selectlanguage.action

 

login.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title><s:text name="loginPage"/></title>
</head>
<body>
<s:include value="selectlanguage.jsp"/>
<s:form action="login">
	<s:textfield name="username" key="user"/>
	<s:textfield name="password" key="pass"/>
	<s:submit key="login"/>
</s:form>
</body>
</html>
 

通过如下标签来选择语言

<s:include value="selectlanguage.jsp"/>

 

成功和失败 jsp

welcome.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title><s:text name="succPage"/></title>
</head>
<body>
	${requestScope.tip}
</body>
</html>
 

error.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title><s:text name="errorPage"/></title>
</head>
<body>
	${requestScope.tip}
</body>
</html>
 

原理 : 用户选择了语言后,系统将用户选择设置成了 HTTP Session 的 "WW_TRANS_I18N_LOCALE "  属性值,该 Session 属性值直接决定 Struts 2 系统的语言环境。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值