不需要轉編碼的I18N

        先回顧一下經典的I18N

message_zh.properties

our.company=\u9999\u6E2F\u5BBD\u9891
our.target=\u6210\u5C31\u9999\u6E2F\u66F4\u7F8E\u597D\u5BB6\u56ED

spring MVC的話,JSP上這樣寫 (煩人spring 的config 省略

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
…
<label><spring:message code='our.company'/></label>
<label><spring:message code='our.target'/></label>
…

        過了兩天老闆叫你把上面“美好”改成“幸福”,要查找和修改\uXXXX的內容,OMG,頭大了有木有。即使I18N的工具,導來導去的也不方便。究其原因是因爲JavaI18N,用到了類PropertiesPropertiesiso8859-1編碼讀文件,各種語言都要轉成\uXXXX這種不方便人直接閱讀編碼。

        這都是十幾年前的方案了,早就該改進了。幸好我們有偉大的UTF-8,使用UTF-8的文件,我們和Java都能讀懂。讓我們開始新的旅程:

1. 寫資源文件

msg_zh.prop (使用.prop文件是爲了不讓eclipse把文件內容轉成\uXXXX的格式)

our_company=香港寬頻
our_target=成就香港更美好家園

將文件以utf-8編碼存盤,明文保存就可以了,方便查看修改,放在classpath裏面便於加載。注意,key裏面不能用’.’,要使用java變量名的命名規則,即字母和下劃線。

2. 加載資源

既然不能使用Properties來加載,我們就自己寫一個資源加載類

public class MsgUtil {
    private static Logger log = Logger.getLogger(MsgUtil.class);
    private static Map<String, String> msgZh = new HashMap<String, String>();
    private static Map<String, String> msgEn = new HashMap<String, String>();
    
    static {
        try {
            loadProp(msgZh, "/resource/i18n/msg_zh.prop");
            loadProp(msgEn, "/resource/i18n/msg_en.prop");
        } catch (Exception e) {
            log.error("MsgUtil init error.", e);
        }
    }
    
    private static void loadProp(Map<String, String> p, String cpFile) throws IOException {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(
                    MsgUtil.class.getResourceAsStream(cpFile), "utf-8"));
            String line, key, value;
            int pos;
            while ((line=br.readLine()) != null) {
                if (line.startsWith("#")) continue;
                pos = line.indexOf('=');
                if (pos > 0) {
                    key = line.substring(0, pos);
                    value = line.substring(pos + 1);
                    p.put(key.trim(), value.trim());
                }
            }
        } finally {
            if (br != null) br.close();
        }
    }
 
    public static String getString(String key){
        return getString(key, getLocale());
    }
 
    public static String getString(String key, String locale) {
        if (key != null && locale != null) {
            return getProp(locale).get(key);
        } else {
            LogUtil.error("Key="+key+", lang="+locale);
        }
        return "!"+key+"!";
    }
    
    public static Map<String, String> getProp(String locale) {
        return K.en.equals(locale) ? msgEn : msgZh;
    }
}

  使用utf-8讀入資源文件。由於我平常遇到的情況比較簡單,只有中、英文,寫這樣一個Util類就夠用了。如果大家有興趣可以寫個I18nBundle來代替Java自帶的ResourceBundle。(如果呼聲高,我也可以動手)。

3. 獲取locale

        經典的方法是從Request header中獲取locale,但我們的情況不需要這麼上綱上線。先給一個缺省的中文localezh),然後把它記在sessioncookie中,如果用戶不愛看,就把它改成英文localeen),當然要更新sessioncookie

4. 將資源應用到jsp

        前方高能!請注意!!

        先加一個攔截器,以spring MVC爲例 (寫一般的filter也可以)

public class GlobalInterceptor implements HandlerInterceptor {
  public boolean preHandle(HttpServletRequest request, HttpServletResponse res,
       Object arg2) throws Exception {
    request.setAttribute("i18n", MsgUtil.getProp(getLocale()));
    …
    return true;
  }
  …
}

看好了,每個request都加了一個“i18n”的bean,這樣在jsp裏面用就爽了。

…
<label>${i18n.our_company}</label>
<label>${i18n.our_target}</label>
…

Java code裏面用也很簡單,

MsgUtil.getString(“our_company”);
MsgUtil.getString(“our_target”, getLocale());
…

如果要帶參數,可以研究一下java.text.MessageFormat


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章