前两天在我的Gajax框架中实现了i18n
先来几张图
1. 中文界面
2. 英文界面
3. 界面语言设置窗口
实现步骤如下:
1. 写一个LocaleServlet
package org.gajaxframework.i18n; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.gajaxframework.context.GajaxContext; /** * Gajax Locale Servlet * * @author Sam Chen * @version 1.0 05/24/2008 11:54 */ public class LocaleServlet extends HttpServlet { private static String DEFAULT_LANGUAGE = "EN"; private static String localeConfigLocation = "/WEB-INF/locale"; private static Map<String, String> LOCALES = new HashMap<String, String>(); private static Log log = LogFactory.getLog(LocaleServlet.class); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // String language = (String) request.getParameter("language"); String pathInfo = request.getPathInfo(); String language = null == pathInfo ? "" : pathInfo.substring(pathInfo.lastIndexOf("/") + 1); if (null == language || "".equals(language.trim())) { // FIXME: get language setting from the user's customized settings language = "EN"; } language = (null == language ? DEFAULT_LANGUAGE : language.toUpperCase()); String resource = LOCALES.get(language); if (null == resource) { log.warn("No locale resource found for language '" + language + "'. Defaults to '" + DEFAULT_LANGUAGE + "'"); resource = LOCALES.get(DEFAULT_LANGUAGE); } else { log.info("Locale resource found for language '" + language + "'."); } printResource(response, resource); } /** * print locale resource to the client * * @param response */ private void printResource(HttpServletResponse response, String resource) throws IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter writer = response.getWriter(); writer.print(resource); writer.flush(); writer.close(); } // ====================== initialization ====================== @Override public void init(ServletConfig config) throws ServletException { String customizedDEFAULT_LANGUAGE = config.getInitParameter("DEFAULT_LANGUAGE"); String customizedlocaleConfigLocation = config.getInitParameter("localeConfigLocation"); // override the default(hard-coded) configurations if there're customized configurations if (null != customizedDEFAULT_LANGUAGE) { DEFAULT_LANGUAGE = customizedDEFAULT_LANGUAGE; } if (null != customizedlocaleConfigLocation) { localeConfigLocation = customizedlocaleConfigLocation; } loadLocales(localeConfigLocation); } /** * load all the locales and put 'em to the map * @param localeConfigLocation */ private void loadLocales(String localeConfigLocation) { localeConfigLocation = GajaxContext.REAL_PATH + localeConfigLocation; File localeConfigFolder = new File(localeConfigLocation); File[] localeFiles = localeConfigFolder.listFiles(); for (int i = 0, l = localeFiles.length; i < l; i++) { File localeFile = localeFiles[i]; String fileName = localeFile.getName(); if (!fileName.endsWith(".properties") || fileName.endsWith(".original.properties")) { continue; } String language = fileName.substring(fileName.indexOf("_") + 1, fileName.indexOf(".properties")); InputStream is = null; try { is = new FileInputStream(localeFile); Properties properties = new Properties(); properties.load(is); String json = conver2Json(properties); LOCALES.put(language.toUpperCase(), json); log.info("Locale resource for language '" + language + "' loaded:\n" + json); } catch (FileNotFoundException fnfe) { ; } catch (IOException ioe) { ; } finally { try { is.close(); } catch (Exception x) {} } } } /** * convert key-value pairs to JSON format * @param properties * @return */ private String conver2Json(Properties properties) { StringBuilder sb = new StringBuilder(); sb.append("GajaxLocale={\n"); sb.append(" 'PROJECT_NAME':'MyDesktop',\n"); sb.append(" 'PROJECT_VERSION':'1.0 Beta',\n"); sb.append(" 'SERVLET_CONTEXT_NAME':").append("'").append(GajaxContext.SERVLET_CONTEXT_NAME).append("',\n"); List<String> keys = new ArrayList<String>(); for (Enumeration<Object> em = properties.keys(); em.hasMoreElements();) { String key = (String) em.nextElement(); keys.add(key); } Collections.sort(keys, new Comparator<String>() { public int compare(String k1, String k2) { return k1.compareTo(k2); } }); for (int i = 0, l = keys.size(); i < l; i++) { String key = keys.get(i); String value = properties.getProperty(key); String suffix = i == l - 1 ? "};" : ","; if (null == value || "".equals(value.trim()) || "null".equalsIgnoreCase(value.trim())) { sb.append(" '").append(key).append("'").append(":").append("null").append(suffix).append("\n"); } else { sb.append(" '").append(key).append("'").append(":").append("'").append(value).append("'").append(suffix).append("\n"); } } return sb.toString(); } }
为了得到中文Locale资源文件对应的UTF-8编码的文件,写个bat来调用%JAVA_HOME%/bin/native2ascii.exe
@echo off echo ============================================== echo Native2Ascii Utility echo Author Sam Chen, Senior Software Engineer, GRS echo Version 1.0 05/24/2008 11:23 echo ============================================== set CURRENT_DIR=%cd% echo Current DIR is %CURRENT_DIR% cd ../workspace/MyDesktop/WEB-INF/locale set CURRENT_DIR=%cd% echo Current DIR changed to %CURRENT_DIR% native2ascii.exe -encoding UTF-8 ./Gajax_zh.original.properties ./Gajax_zh.properties echo Command 'native2ascii.exe -encoding UTF-8 ./Gajax_zh.original.properties ./Gajax_zh.properties' executed successfully @pause
在web.xml文件中配置这个serlet
<servlet> <servlet-name>localeServlet</servlet-name> <servlet-class>org.gajaxframework.i18n.LocaleServlet</servlet-class> <init-param> <param-name>DEFAULT_LANGUAGE</param-name> <param-value>EN</param-value> </init-param> <init-param> <param-name>localeConfigLocation</param-name> <param-value>/WEB-INF/locale</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>localeServlet</servlet-name> <url-pattern>/jslib/i18n/GajaxLocale/*</url-pattern> </servlet-mapping>
2. html文件中用script标签下载locale资源
<!-- i18n resources --> <script type="text/javascript" src="jslib/i18n/GajaxLocale/zh" charset="utf-8"></script>
注意这个script标签应该排在最前头,以保证locale资源对后续javascript可用
3. 再来个helper -- locale.js
/** * GRS.framework.data.Locale * @author Sam Chen * @version 1.0 11/21/2007 21:22 * @version 1.0 05/24/2008 19:51 * (replaced hard-coded locale object with the JSON object downloaded from the server side) */ Ext.namespace("GRS.framework.data"); GRS.framework.data.Locale = function(M) { this.map = M || {} }; Ext.extend(GRS.framework.data.Locale, Ext.util.Observable, { get : function(key) { var value = this.map[key] || (key + ' not found!'); if(arguments.length > 1 && value.indexOf('{') >= 0) { value = new Ext.Template(value).apply(Array.prototype.slice.call(arguments, 1)) } return value } }); // GajaxLocale is a JSON object downloaded from the server side var locale = new GRS.framework.data.Locale(GajaxLocale); // shortcut for the method locale.get $ = locale.get.createDelegate(locale);
4. html文件如下
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>MyDesktop App</title> <link rel="stylesheet" type="text/css" href="jslib/ext-2.1/resources/css/ext-all.css" /> <link rel="stylesheet" type="text/css" href="resources/css/icons/icons.css" /> <!-- i18n resources --> <script type="text/javascript" src="jslib/i18n/GajaxLocale/zh" charset="utf-8"></script> <script type="text/javascript" src="jslib/ext-2.1/adapter/ext/ext-base.js"></script> <script type="text/javascript" src="jslib/ext-2.1/ext-all.js"></script> <script type="text/javascript" src="jslib/grsframework/data/Locale.js"></script> <!-- DESKTOP --> <script type="text/javascript" src="jslib/desktop/core/StartMenu.js"></script> <script type="text/javascript" src="jslib/desktop/core/TaskBar.js"></script> <script type="text/javascript" src="jslib/desktop/core/Desktop.js"></script> <script type="text/javascript" src="jslib/desktop/core/App.js"></script> <script type="text/javascript" src="jslib/desktop/core/Module.js"></script> <script type="text/javascript" src="jslib/desktop/core/DesktopConfig.js"></script> <!-- DESKTOP HELPERS --> <script type="text/javascript" src="jslib/desktop/helpers/color-picker/color-picker.ux.js"></script> <link rel="stylesheet" type="text/css" href="jslib/desktop/helpers/color-picker/color-picker.ux.css" /> <script type="text/javascript" src="jslib/desktop/helpers/preferences/Preferences.js"></script> <link rel="stylesheet" type="text/css" href="jslib/desktop/helpers/preferences/preferences.css" /> <!-- MODULES --> <script type="text/javascript" src="jslib/modules/layout-window/js/layout-window.js"></script> <script type="text/javascript" src="jslib/modules/docs/js/docs.js"></script> <link rel="stylesheet" type="text/css" href="jslib/modules/docs/css/docs.css" /> <!-- DESKTOP STYLES --> <link rel="stylesheet" type="text/css" href="jslib/ext-2.1/examples/desktop/css/desktop.css" /> <link rel="stylesheet" type="text/css" href="resources/css/desktop-sam.css" /> </head> <body id="desktop-body" scroll="no" background="resources/wallpapers/blue-swirl.jpg"> </body> </html>
谨发此文,以抛砖引玉。