當(dāng)前的富客戶端可以包含兩部分:分別為JSP
頁(yè)面和通過(guò)富客戶端js組件(如extjs)
渲染的組件化窗口頁(yè)。針對(duì)這兩部分分別做如下處理:
對(duì)于JSP頁(yè)面的部分采用JSTL標(biāo)準(zhǔn)庫(kù)的fmt標(biāo)簽,如通過(guò):
<fmt:message key="page.login.title"/>這樣的形式進(jìn)行展現(xiàn),其中message對(duì)應(yīng)的文本在服務(wù)端配置,并在web.xml中配置資源文件的位置,也可以采用spring標(biāo)簽,Structs標(biāo)簽等多種機(jī)制。不過(guò)為了以后的程序修改兼容性,建議采用JSTL進(jìn)行JSP頁(yè)面的國(guó)際化。
對(duì)于JavaScript,考慮到為提高效率,因?yàn)槭庆o態(tài)資源,可以很方便的在一定周期內(nèi)要在客戶端瀏覽器進(jìn)行緩存,不同的瀏覽器會(huì)有不同的緩存機(jī)理,在IE中,js文件通過(guò)定義一定的過(guò)期期限,C:"Documents and Settings"用戶名"Local Settings"Temporary Internet Files下進(jìn)行緩存,Firefox是C:"Documents and Settings"用戶名"Local Settings"Application Data"Mozilla"Firefox"Profiles"XXXXXXX.default"Cache,為了緩存而不是每次下載為了實(shí)現(xiàn)富客戶端而集成的很大的js,不能用動(dòng)態(tài)的網(wǎng)頁(yè)來(lái)生成(即把JavaScript包裝為JSP頁(yè)面,最簡(jiǎn)單的,把js擴(kuò)展名改成jsp并利用jsp的機(jī)制做國(guó)際化)。因此,需要對(duì)JavaScript中國(guó)際化的內(nèi)容通過(guò)變量單獨(dú)加載,舉例如下:
var Message = function(){
this.title =’中文標(biāo)題’;
……
};
var msg = new Message();
/********************************
或:
var msg = {
title : ‘中文標(biāo)題’;
};
*********************************/
new Ext.Window({
title : msg.title,
width : 265,
height : 140
});
其中msg對(duì)象的定義可以通過(guò)在另一個(gè)JavaScript文件中引用的本地化文件所定義,也可以通過(guò)AJAX返回JSON對(duì)象的形式來(lái)獲取或者動(dòng)態(tài)地進(jìn)行服務(wù)端生成。
兩種方法的優(yōu)缺點(diǎn)定義如下:
方法
|
缺點(diǎn)
|
優(yōu)點(diǎn)
|
前臺(tái)主動(dòng)定義
|
會(huì)產(chǎn)生大量零碎的文件(M個(gè)JavaScript文件需要對(duì)象N個(gè)語(yǔ)言的資源文件,總數(shù)M×N,如果把這些資源文件都放在一個(gè)JavaScript文件中定義,則對(duì)客戶端來(lái)說(shuō),要下載過(guò)多不必要的資源)
|
資源定義非常靈活,可以保證只定義自己需要的資源,并且可以做到隨時(shí)更改其內(nèi)容
|
后臺(tái)自動(dòng)獲取
|
加重了服務(wù)器的負(fù)擔(dān),需要用到AJAX或者類似dwr的服務(wù)端動(dòng)態(tài)加載。具有一定的復(fù)雜性
|
可以和后臺(tái)及JSP頁(yè)面共享同一個(gè)資源定義文件,并動(dòng)態(tài)生成資源定義文件,減少了開(kāi)發(fā)人員的負(fù)擔(dān)
|
綜上,可以采取如下國(guó)際化方法:
針對(duì)JavaScript文件的國(guó)際化,分成兩部分來(lái)進(jìn)行:
對(duì)于通用的文本定義,如:”確定”,”返回”等等,放在前臺(tái)的資源文件中,隨JavaScript文件一同加載,對(duì)于特殊的文本定義通過(guò)后臺(tái)自動(dòng)獲取的形式來(lái)展現(xiàn),這樣就可以結(jié)合兩種方法的優(yōu)點(diǎn)。
后臺(tái)實(shí)現(xiàn)的如下:
按照命名規(guī)約定義頁(yè)面的文本元素,然后動(dòng)態(tài)的生成一個(gè)如下的json對(duì)象:
{
messageName : messageValue
……
}
然后前臺(tái)頁(yè)面JavaScript在加載時(shí)獲取這個(gè)json對(duì)象,并應(yīng)用到頁(yè)面文本元素的定義中,如利用Extjs的使用方法:
var msg = Ext.util.json.decode(jsonString); 或者服務(wù)器動(dòng)態(tài)生成時(shí)就表述為var msg={…};的形式,并在頭文件指向動(dòng)態(tài)的地址(類似dwr動(dòng)態(tài)生成的機(jī)制),然后就可以通過(guò)msg.XXX來(lái)獲得文本定義了。文中涉及的代碼如下:
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.ResourceBundle;

import net.sf.json.JSONObject;


/** *//**
* 根據(jù)層次結(jié)構(gòu)獲取到特定前綴的所有的資源名稱,并把它們放在一個(gè)JSON對(duì)象中返回,對(duì)于相同類型的資源請(qǐng)求進(jìn)行緩存,
* 不再動(dòng)態(tài)生成新的內(nèi)容。這個(gè)對(duì)象要納入到Spring的容器中進(jìn)行管理,把bean的管理模式設(shè)置為單例模式就好,所以這里
* 沒(méi)有提供對(duì)于類的單例封裝
*
* * @author 楊一
*/


public class HierarchicalMessage
{

/** *//**資源對(duì)象的基礎(chǔ)名稱*/
private String bundleName;

/** *//**特定組件所使用的前綴*/
private String prefix;

/** *//**緩存對(duì)象用的哈希表*/
private HashMap<String, JSONObject> cachingMap = new HashMap<String, JSONObject>();

/** *//**設(shè)置或注入對(duì)象的基礎(chǔ)名稱*/

public void setBundleName(String bundleName)
{
this.bundleName = bundleName;
}


/** *//**設(shè)置或注入所使用的前綴*/

public void setPrefix(String prefix)
{
this.prefix = prefix;
}


/** *//**根據(jù)注入的結(jié)果返回語(yǔ)言包,(某些情況下,請(qǐng)求的資源是一定的)*/

public JSONObject getMessagesWithPrefix(Locale localeName)
{
return getMessagesWithPrefix(this.bundleName,this.prefix,localeName);
}

/** *//**
* 根據(jù)層次結(jié)構(gòu)獲取到特定前綴的所有的資源名稱,并把它們放在一個(gè)JSON對(duì)象中返回
* */

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();
//此處無(wú)需緩存,因?yàn)镴ava核心庫(kù)會(huì)做這件工作
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
{

/** *//**
* 動(dòng)態(tài)生成一個(gè)用于國(guó)際化的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中獲取用戶的登陸語(yǔ)言環(huán)境
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頁(yè)面中先于功能js導(dǎo)入對(duì)應(yīng)的語(yǔ)言js,名稱相同,路徑在/i18n/xxx.js
同時(shí)在根classpath下的i18n/messages資源下定義page.xxx.xxx
@2008 楊一. 版權(quán)所有. 保留所有權(quán)利