前两天在我的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>
谨发此文,以抛砖引玉。