js国际化

  在Java项目中,尤其是WEB项目中,一般都是通过Struts框架的特性进行国际化的。
  在采用Struts的项目架构中,借用Struts的的国际化标签等特性,可以非常方便的对jsp文件及action类文件进行国际化。但是,在一个面向大众用户的, 开放的WEB应用中,通常有非常多的js文件,如何对js文件进行国际化呢?
在互联网上,通过baidu,google,查找,对js国际化的方法一般是:
  jsp页面中,通过判断客户端的Locale(request.getLocale()),加载不同语言的js文件,对图片的处理方法也是类似。不同语言 的js文件,内容上基本一致,只是把需要显示的文字翻译成不同语言的文字。缺点:不是真正的国际化,如果需要100个国家语言的用户访问,就得需要的 100个js文件。
  对于jsp文件,是通过struts国际化标签,在服务器端根据locale输出特定Locale的消息。因此,设想,js文件,能够也通过后台输出特定locale国际化的消息。

基本理论就是:

  借用ajax,struts技术,js需要国际化的消息,通过ajax技术,通过后台输出,后台处理方式完全和jsp,action类中的处理方式一致.

详细代码实现:

系统采用的框架:struts2.1.6 + spring+hibernate+dwr2.06.
其中dwr是个ajax框架,封装了ajax的调用。

  • js需要请求国际化的消息,必然要和服务器交互,也即通过js调用java类中的方法,这可以通过dwr实现。
    java类:
    JSActionSupport.java
/*
 * Copyright (c) 2002-2006 by OpenSymphony
 * All rights reserved.
 */
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;
import java.util.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;

import javax.servlet.http.HttpServletRequest;


/**
 * 这个类实际上就是struts2中的ActionSupport类的修改,主要修改了getLocale方法,目的是通过ajax调用,获取ajax请求中的locale。同时增加了2个方法 getMsg,getMsgs,用与暴露给js远程调用。
 * JS ActionSupport for get the International message
 * @see ActionSupport class
 */
public class JSActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {

    protected static Log LOG = LogFactory.getLog(ActionSupport.class);

    private final transient TextProvider textProvider = new TextProviderFactory().createInstance(getClass(), this);
    private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
    /**
     * Get the International Message by the key
     * @param key
     * @return
     */
    public String getMsg(String key) {
        return this.getText(key);
    }
    /**
     * Get the International Message by key collection
     * @param key
     * @return
     */
    public List < String > getMsgs(List < String > key) {
        List < String > result = new ArrayList < String > ();
        for (String temp: key) {
            result.add(this.getMsg(temp));
        }
        return result;
    }

    public void setActionErrors(Collection errorMessages) {
        validationAware.setActionErrors(errorMessages);
    }

    public Collection getActionErrors() {
        return validationAware.getActionErrors();
    }

    public void setActionMessages(Collection messages) {
        validationAware.setActionMessages(messages);
    }

    public Collection getActionMessages() {
        return validationAware.getActionMessages();
    }

    /**
     * @deprecated Use {@link #getActionErrors()}.
     */
    public Collection getErrorMessages() {
        return getActionErrors();
    }

    /**
     * @deprecated Use {@link #getFieldErrors()}.
     */
    public Map getErrors() {
        return getFieldErrors();
    }

    public void setFieldErrors(Map errorMap) {
        validationAware.setFieldErrors(errorMap);
    }

    public Map getFieldErrors() {
        return validationAware.getFieldErrors();
    }

    /**
     * 重写了这个方法,获取ajax请求中的locale,stuts2中的类会调用此方法。
     * Get Locale from dwr request
     */
    public Locale getLocale() {
        //return ActionContext.getContext().getLocale();
        WebContext webCxt = WebContextFactory.get();
        HttpServletRequest request = webCxt.getHttpServletRequest();
        Locale result = request.getLocale();
        return result;
    }

    public String getText(String aTextName) {
        return textProvider.getText(aTextName);
    }

    public String getText(String aTextName, String defaultValue) {
        return textProvider.getText(aTextName, defaultValue);
    }

    public String getText(String aTextName, String defaultValue, String obj) {
        return textProvider.getText(aTextName, defaultValue, obj);
    }

    public String getText(String aTextName, List args) {
        return textProvider.getText(aTextName, args);
    }

    public String getText(String key, String[] args) {
        return textProvider.getText(key, args);
    }

    public String getText(String aTextName, String defaultValue, List args) {
        return textProvider.getText(aTextName, defaultValue, args);
    }

    public String getText(String key, String defaultValue, String[] args) {
        return textProvider.getText(key, defaultValue, args);
    }

    public String getText(String key, String defaultValue, List args, ValueStack stack) {
        return textProvider.getText(key, defaultValue, args, stack);
    }

    public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
        return textProvider.getText(key, defaultValue, args, stack);
    }

    public ResourceBundle getTexts() {
        return textProvider.getTexts();
    }

    public ResourceBundle getTexts(String aBundleName) {
        return textProvider.getTexts(aBundleName);
    }

    public void addActionError(String anErrorMessage) {
        validationAware.addActionError(anErrorMessage);
    }

    public void addActionMessage(String aMessage) {
        validationAware.addActionMessage(aMessage);
    }

    public void addFieldError(String fieldName, String errorMessage) {
        validationAware.addFieldError(fieldName, errorMessage);
    }

    public String input() throws Exception {
        return INPUT;
    }

    public String doDefault() throws Exception {
        return SUCCESS;
    }

    /**
     * A default implementation that does nothing an returns "success".
     * <p/>
     * Subclasses should override this method to provide their business logic.
     * <p/>
     * See also {@link com.opensymphony.xwork2.Action#execute()}.
     *
     * @return returns {@link #SUCCESS}
     * @throws Exception  can be thrown by subclasses.
     */
    public String execute() throws Exception {
        return SUCCESS;
    }

    public boolean hasActionErrors() {
        return validationAware.hasActionErrors();
    }

    public boolean hasActionMessages() {
        return validationAware.hasActionMessages();
    }

    public boolean hasErrors() {
        return validationAware.hasErrors();
    }

    public boolean hasFieldErrors() {
        return validationAware.hasFieldErrors();
    }

    /**
     * Clears all errors and messages. Useful for Continuations and other situations
     * where you might want to clear parts of the state on the same action.
     */
    public void clearErrorsAndMessages() {
        validationAware.clearErrorsAndMessages();
    }

    /**
     * A default implementation that validates nothing.
     * Subclasses should override this method to provide validations.
     */
    public void validate() {}

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    /**
     * <!-- START SNIPPET: pause-method -->
     * Stops the action invocation immediately (by throwing a PauseException) and causes the action invocation to return
     * the specified result, such as {@link #SUCCESS}, {@link #INPUT}, etc.
     * <p/>
     *
     * The next time this action is invoked (and using the same continuation ID), the method will resume immediately
     * after where this method was called, with the entire call stack in the execute method restored.
     * <p/>
     *
     * Note: this method can <b>only</b> be called within the {@link #execute()} method.
     * <!-- END SNIPPET: pause-method -->
     *
     * @param result the result to return - the same type of return value in the {@link #execute()} method.
     */
    public void pause(String result) {}

}
  • 配置dwr(dwr.xml),达到暴露给js远程调用的目的。
      getMsg(String key)可以实现获取单个key的国际化消息,但是一个js文件中,可能文件中的不同地方都需要国际化的消息,而如果通过getMsg(String key),则导致多次ajax请求,增大服务器压力,因此,可以通过集合方式(getMsgs(List key),一个文件中,一次ajax请求,获取该文件中全部的国际化消息。
<dwr>
   <allow>
      <!--International support for js-->
      <create creator="spring" javascript="jsActionSupport">
         <param name="beanName" value="jsActionSupport"/>
         <include method="getMsg"/>
         <include method="getMsgs"/>
         <!-- JSActionSupport类中,仅这2个方法暴露给远程调用-->
      </create>
      <convert converter="list" match="java.util.List"/>
   </allow>
   <signatures>
      <![CDATA[
         import java.util.List;
         import JSActionSupport;
         JSActionSupport.getMsgs(List<String>key);
         ]]> 
   </signatures>
</dwr>

具体的dwr使用与配置,可以参考dwr文档。
   然后可以通过http://localhost/webcontext/dwr/,进行测试dwr是否部署正确。
   编辑资源文件,方法和struts国际化资源文件一样。为了逻辑清晰,可以把专属于js调用的国际化消息单独放在一个资源文件中 (JSActionSupport.properties,JSActionSupport_en.properties),这个资源文件和 JSActionSupport在同一类包中(package)。

客户端js文件编写与调用

example.js文件内容

dwr.engine.setAsync(false);
var jsResult;
var jsPara;
jsPara = ["key1",
    "key2",
    "key3"
];
jsActionSupport.getMsgs(jsPara, function(data) <!-- js远程调用Java方法 -->
    {
        jsResult = data;
    });

function exampleTest() {
        alert(jsResult[0]; alert(jsResult[1];
    }

总结:
国际化的本质都是通过判断客户端请求头携带的locale信息,根据locale输出国际化消息。

参考资料:
1.http://directwebremoting.org/dwr/index.html (可以下载dwr组件及文档,接受了dwr的使用)
2.http://blog.csdn.net/wen1019/article/details/4785190

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页