富客户端技术中的JavaScript脚本国际化

本文介绍了一种富客户端JavaScript国际化的方案,通过将通用文本置于前端资源文件中,并利用JSON对象动态加载特殊文本的方式,实现了高效的缓存及灵活的文本替换。
当前的富客户端可以包含两部分:分别为JSP页面和通过富客户端js组件(如extjs)渲染的组件化窗口页。针对这两部分分别做如下处理:
对于JSP页面的部分采用JSTL标准库的fmt标签,如通过:

<fmt:message key="page.login.title"/>这样的形式进行展现,其中message对应的文本在服务端配置,并在web.xml中配置资源文件的位置,也可以采用spring标签,Structs标签等多种机制。不过为了以后的程序修改兼容性,建议采用JSTL进行JSP页面的国际化。

对于JavaScript,考虑到为提高效率,因为是静态资源,可以很方便的在一定周期内要在客户端浏览器进行缓存,不同的浏览器会有不同的缓存机理,在IE中,js文件通过定义一定的过期期限,C:"Documents and Settings"用户名"Local Settings"Temporary Internet Files下进行缓存,Firefox是C:"Documents and Settings"用户名"Local Settings"Application Data"Mozilla"Firefox"Profiles"XXXXXXX.default"Cache,为了缓存而不是每次下载为了实现富客户端而集成的很大的js,不能用动态的网页来生成(即把JavaScript包装为JSP页面,最简单的,把js扩展名改成jsp并利用jsp的机制做国际化)。因此,需要对JavaScript中国际化的内容通过变量单独加载,举例如下:


var Message = function(){

this.title =’中文标题’;

……

};

var msg = new Message();



或:


var msg = {

title : ‘中文标题’;

};




new Ext.Window({

title : msg.title,

width : 265,

height : 140

});


其中msg对象的定义可以通过在另一个JavaScript文件中引用的本地化文件所定义,也可以通过AJAX返回JSON对象的形式来获取或者动态地进行服务端生成。

两种方法的优缺点定义如下:
[img]http://yangtao309.iteye.com/upload/attachment/63346/2ccf4750-b2ee-3cf0-95d7-8288ed4f04d2.jpg[/img]

综上,可以采取如下国际化方法:

针对JavaScript文件的国际化,分成两部分来进行:

对于通用的文本定义,如:”确定”,”返回”等等,放在前台的资源文件中,随JavaScript文件一同加载,对于特殊的文本定义通过后台自动获取的形式来展现,这样就可以结合两种方法的优点。

后台实现的如下:

按照命名规约定义页面的文本元素,然后动态的生成一个如下的json对象:


{

messageName : messageValue

……

}


然后前台页面JavaScript在加载时获取这个json对象,并应用到页面文本元素的定义中,如利用Extjs的使用方法:


var msg = Ext.util.json.decode(jsonString); 或者服务器动态生成时就表述为var msg={…};的形式,并在头文件指向动态的地址(类似dwr动态生成的机制),然后就可以通过msg.XXX来获得文本定义了。文中涉及的代码如下:



import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.ResourceBundle;

import net.sf.json.JSONObject;

/** *//**
* 根据层次结构获取到特定前缀的所有的资源名称,并把它们放在一个JSON对象中返回,对于相同类型的资源请求进行缓存,
* 不再动态生成新的内容。这个对象要纳入到Spring的容器中进行管理,把bean的管理模式设置为单例模式就好,所以这里
* 没有提供对于类的单例封装
*
* * @author 杨一
*/

public class HierarchicalMessage {
/** *//**资源对象的基础名称*/
private String bundleName;
/** *//**特定组件所使用的前缀*/
private String prefix;
/** *//**缓存对象用的哈希表*/
private HashMap<String, JSONObject> cachingMap = new HashMap<String, JSONObject>();

/** *//**设置或注入对象的基础名称*/
public void setBundleName(String bundleName) {
this.bundleName = bundleName;
}

/** *//**设置或注入所使用的前缀*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}

/** *//**根据注入的结果返回语言包,(某些情况下,请求的资源是一定的)*/
public JSONObject getMessagesWithPrefix(Locale localeName){
return getMessagesWithPrefix(this.bundleName,this.prefix,localeName);
}

/** *//**
* 根据层次结构获取到特定前缀的所有的资源名称,并把它们放在一个JSON对象中返回
* */
public JSONObject getMessagesWithPrefix(String bundleName, String prefix, Locale localeName){
JSONObject toReturn;
//拼接的缓存字符串的格式为:i18n/messages$page.login$zh_CN
String cachingString = new StringBuilder().append(bundleName).append("$").
append(prefix).append("$").append(localeName.toString()).toString();
toReturn = cachingMap.get(cachingString);
if(toReturn != null){
return toReturn;
}

toReturn = new JSONObject();

//此处无需缓存,因为Java核心库会做这件工作
ResourceBundle rb = ResourceBundle.getBundle(bundleName, localeName);

Enumeration<String> e = rb.getKeys();
String keyRef = null;
String componentPrefix = new StringBuilder().append(prefix).append(".").toString();
int shortNameStartIndex = prefix.length() + 1;
while(e.hasMoreElements()){
keyRef = e.nextElement();
if(keyRef.startsWith(componentPrefix)){
toReturn.put(keyRef.substring(shortNameStartIndex), rb.getString(keyRef));
}
}

cachingMap.put(cachingString, toReturn);

return toReturn;
}
}





import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import HierarchicalMessage;

public class I18nServlet extends HttpServlet {
/** *//**
* 动态生成一个用于国际化的JavaScript脚本
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");

PrintWriter out = response.getWriter();

HierarchicalMessage hm = getHierarchicalMessage();
hm.setPrefix(new StringBuilder().append("page.").append(getBizId(request)).toString());
//此处从session中获取用户的登陆语言环境
String json = hm.getMessagesWithPrefix(request.getLocale()).toString();

out.print(new StringBuilder().append("var msg=").append(json).append(";"));
out.close();
}

private HierarchicalMessage getHierarchicalMessage() {
WebApplicationContext wc = WebApplicationContextUtils
.getWebApplicationContext(getServletContext());
HierarchicalMessage hm = (HierarchicalMessage)wc.getBean("msgBean");
return hm;
}

private String getBizId(HttpServletRequest request) {
StringBuffer urlString = request.getRequestURL();
int start = urlString.lastIndexOf("/") + 1;
int end = urlString.lastIndexOf(".");
return urlString.substring(start, end);
}

}



Spring配置:

<bean id="msgBean" class="HierarchicalMessage" scope="singleton">
<property name="bundleName">
<value>i18n/messages</value>
</property>
<property name="prefix">
<value>sys</value>
</property>
</bean>


Web.xml配置:


<servlet>
<servlet-name>I18nServlet</servlet-name>
<servlet-class>I18nServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>I18nServlet</servlet-name>
<url-pattern>/i18n/*</url-pattern>
</servlet-mapping>


使用方法:

在html页面中先于功能js导入对应的语言js,名称相同,路径在/i18n/xxx.js

同时在根classpath下的i18n/messages资源下定义page.xxx.xxx

原文地址:[url]http://www.blogjava.net/yangyi/archive/2008/12/23/247898.html[/url]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值