使用 jQuery.i18n.properties 實現 Web 前端的國際化
國際化是現在 Web 應用程序開發中的重要一環。jQuery.i18n.properties 是一款輕量級的 jQuery 國際化插件,能在不對後端做任何更改的情況下,實現 Web 前端的國際化。與其他國際化工具相比, jQuery.i18n.properties 插件具有簡單、易用、鬆耦合的特點。本文通過實際的例子,介紹如何通過 jQuery.i18n.properties 插件來實現 Web 前端的國際化。
jQuery.i18n.properties 簡介
在介紹 jQuery.i18n.properties 之前,我們先來看一下什麼是國際化。國際化英文單詞爲:Internationalization,又稱 i18n,“i”爲單詞的第一個字母,“18”爲“i”和“n”之間單詞的個數,而“n”代表這個單詞的最後一個字母。在計算機領域,國際化是指設計能夠適應各種區域和語言環境的軟件的過程。
jQuery.i18n.properties 是一款輕量級的 jQuery 國際化插件。與 Java 裏的資源文件類似,jQuery.i18n.properties 採用 .properties 文件對 JavaScript 進行國際化。jQuery.i18n.properties 插件根據用戶指定的(或瀏覽器提供的 )語言和國家編碼(符合 ISO-639 和 ISO-3166 標準)來解析對應的以“.properties”爲後綴的資源文件。
利用資源文件實現國際化是一種比較流行的方式,例如 Android 應用就可以採用以語言和國家編碼命名的資源文件來實現國際化。jQuery.i18n.properties 插件中的資源文件以“.properties”爲後綴,包含了區域相關的鍵值對。我們知道,Java 程序也可以使用以 .properties 爲後綴的資源文件來實現國際化,因此,當我們要在 Java 程序和前端 JavaScript 程序中共享資源文件時,這種方式就顯得特別有用。jQuery.i18n.properties 插件首先加載默認的資源文件(例如:strings.properties),然後加載針對特定語言環境的資源文件(例如:strings_zh.properties),這就保證了在未提供某種語言的翻譯時,默認值始終有效。開發人員可以以 JavaScript 變量(或函數)或 Map 的方式使用資源文件中的 key。
總的來說,jQuery.i18n.properties 有一下一些特點:
-
使用 Java 標準的 .properties 文件作爲資源文件,資源文件命名有以下三種格式:
basename_properties basename_language.properties basename_language_country.properties
- 使用 ISO-639 作爲語言編碼標準,ISO-3166 作爲國家名稱編碼標準
- 按順序加載默認資源文件和指定語言環境的資源文件,保證默認值始終可用
- 未指定語言環境時使用瀏覽器提供的語言
- 可以在資源字符串中使用佔位符(例如:hello= 你好 {0}! 今天是 {1}。)
- 資源文件中的 Key 支持命名空間(例如:com.company.msgs.hello = Hello!)
- 支持跨行的值
- 可以以 JavaScript 變量(或函數)或 Map 的方式使用資源文件中的 Key
jQuery.i18n.properties API
jQuery.i18n.properties 的 API 非常簡單,只有少數幾個 API,即 jQuery.i18n.properties()、jQuery.i18n.prop()、jQuery.i18n.browserLang()。當然,和其他 jQuery 插件一樣,我們也可以採用 $.i18n.properties()、$.i18n.prop() 和 $.i18n.browserLang() 的形式使用這用這些 API。
jQuery.i18n.properties(settings)
該方法加載資源文件,其中 settings 是配置加載選項的一系列鍵值對,各配置項的具體描述如表 1 所示。
表 1. settings
選項 | 描述 | 類型 | 可選? |
---|---|---|---|
name | 資源文件的名稱,例如 strings 或 [strings1,strings2],前者代表一個資源文件,後者代表資源文件數組。 | String 或 String[] | 否 |
path | 資源文件所在目錄的路徑 | String | 是 |
mode | 加載模式:“vars”表示以 JavaScript 變量或函數的形式使用資源文件中的 Key,“map”表示以 Map 的方式使用資源文件中的 Key,“both”表示可以同時使用兩種方式。如果資源文件中的 Key 包含 JavaScript 的關鍵字,則只能採用“map”。默認值是“vars”。 | String | 是 |
language | ISO-639 指定的語言編碼(如:“en”表示英文、“zh”表示中文),或同時使用 ISO-639 指定的語言編碼和 ISO-3166 指定的國家編碼(如:“en_US”,“zh_CN”等)。如果不指定,則採用瀏覽器報告的語言編碼。 | String | 是 |
cache | 指定瀏覽器是否對資源文件進行緩存,默認爲 false。 | boolean | 是 |
encoding | 加載資源文件時使用的編碼。默認爲 UTF-8。 | String | 是 |
callback | 代碼執行完成時運行的回調函數 | function | 是 |
jQuery.i18n.properties() 的使用方法如清單 1 所示。
清單 1. jQuery.i18n.properties() 用法
jQuery.i18n.properties({ name:'strings',// 資源文件名稱 path:'bundle/',// 資源文件所在目錄路徑 mode:'both',// 模式:變量或 Map language:'pt_PT',// 對應的語言 cache:false, encoding: 'UTF-8', callback: function() {// 回調方法 } });
jQuery.i18n.prop(key)
該方法以 map 的方式使用資源文件中的值,其中 key 指的是資源文件中的 key。當 key 指定的值含有佔位符時,可以使用 jQuery.i18n.prop(key,var1,var2 … ) 的形式,其中 var1,var2 …對各佔位符依次進行替換。例如資源文件中有“msg_hello= 您好 {0},今天是 {1}。”的鍵值對,則我們可以採用“jQuery.i18n.prop( ‘ msg_hello ’ , ’小明’ , ’星期一’ );”的形式使用 msg_hello。
jQuery.i18n.browserLang() 用於獲取瀏覽瀏覽器的語言信息,這裏不再單獨介紹。
示例
下面我們以一個具體的示例來介紹如何通過 jQuery.i18n.properties 插件來實現 Web 前端的國際化。我們建立一個名爲 hello-i18n 的 Java Web 應用,該應用根據瀏覽器的語言決定以英文或中文顯示登錄界面,登錄成功後以相應的語言顯示歡迎信息,登錄失敗則以相應的語言顯示錯誤信息。
爲了達到鬆耦合的目的,前端採用純 JavaScript+HTML 來實現(我們的目的是介紹如何實現國際化,而不是如何美化界面,因此暫不使用 CSS),服務器端採用 RESTFul Web 服務。前端通過 jQuery Ajax 的方式與服務器端進行交互,避免 JSP 等傳統 Java Web 應用中前後端代碼冗雜在一起的現象。
開發測試環境
- 操作系統:Windows7 64 位專業版。
- IDE:Eclipse-JEE-Juno。
- Libs:jQuery 1.7.1,jQuery.i18n.properties 1.0.9,Apache Wink 1.1.3。
- 測試瀏覽器:Google Chrome 21.0.1180.83 m,FireFox 15.0.1。
服務器端的 RESTFul Web 服務
我們採用 Apache Wink 來實現服務器端 RESTFul Web 服務(關於如何使用 Apache Wink 來實現 RESTFul Web 服務,請參考“參考資料”一節中關於 Wink 的參考資料),這個 Web 服務實現用戶驗證功能。由於我們的重點不在服務器端,因此我們不真正驗證用戶,而是模擬驗證功能,並生成一個假的密鑰(在真實的環境中,密鑰會被用來對其他 REST 請求進行驗證)。REST API 如表 2 所示,代碼如清單 2 所示。
表 2. REST API
屬性 | 描述 |
---|---|
描述 | 驗證用戶信息,並生成密鑰 |
URI 示例 | http://localhost:8080/rest/users/{id}/tokens |
HTTP 請求類型 | POST |
Request Boy | {password:”…”} |
Response Headers | Content-type: application/json |
Response Code |
200:OK - 驗證成功 401:Unauthorized - 密碼不正確 403:Forbidden - 用戶不存在 |
Response Body | {token:” Y29udHJvbGxlci5yZWFkIiwib3BlbmlkIiwicGFzc dvcQd3Jp dGUiXSwiZW...”} |
清單 2. REST 代碼
@Path("/users") public class RESTApi { @Path("/{id}/tokens") @POST @Produces({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON }) public Response authenticate(@PathParam("id") String id, Map<String, Object> payload) { // 模擬驗證功能,僅當用戶名爲"i18n", 密碼爲"123456"時驗證成功 if (id.equals("i18n")) { String pwd = (String) payload.get("password"); if (pwd.equals("123456")) { // 生成模擬密鑰 Map<String, String> token = new HashMap<String, String>(); token.put("token", "Y29udHJvbGxlci5yZWFkIiwib3BlbmlkIiwicGFzc3dvcmQud3JpdGUiXSwiZW..."); return Response.status(Status.OK).entity(token).build(); } else { return Response.status(Status.UNAUTHORIZED).build(); } } return Response.status(Status.FORBIDDEN).build(); } }
建立資源文件
在 Eclipse 中,對 hello-i18n 項目建立如圖 1 所示的目錄結構。
圖 1. 項目組織結構
在 i18n 目錄下創建 strings.properties 和,stirngs_zh.properties 兩個資源文件,其中 strings.properties 對應默認翻譯,如清單 3 所示;string_zh.properties 對應中文翻譯,如清單 4 所示。
清單 3. stirngs.properties
string_username=User name string_password=Password string_login=Login string_hello=Hello {0},Welcome to jQuery.i18n.properties,your token is {1}。 string_usernotexist=User does not exist string_wrongpassword=Wrong Password
清單 4. strings_zh.properties
string_username= 用戶名 string_password= 密碼 string_login= 登陸 string_hello= 您好 {0},歡迎使用 jQuery.i18n.properties,您的密鑰是:{1}。 string_usernotexist= 用戶不存在 string_wrongpassword= 密碼錯誤
引用 jQuery.i18n.properties 插件
和其他 jQuery 插件一樣,jQuery.i18n.properties 插件依賴於 jQuery,因此我們首先需要引用 jQuery。jQuery.i18n.properties 對 jQuery 的版本沒有明確要求,這裏我們使用 jQuery-1.7.1。我們使用清單 5 所示的方式在 index.html 中引用 jQuery 和 jQuery.i18n.properties 插件。
清單 5. 引用 jQuery.i18n.properties
<script type="text/javascript" src="resources/lib/jquery-1.7.1.min.js"> </script> <script type="text/javascript" src="resources/lib/jquery.i18n.properties-1.0.9.js"> </script>
index .html 中還定義了界面元素,如清單 6 所示。
清單 6. 界面元素
<div id="content"> <div> <label id="label_username"></label> <input type="text" id="username"></input> </div> <div> <label id="label_password"></label> <input type="password" id="password"></input> </div> <input type="button" id="button_login"/> </div>
使用 jQuery.i18n.properties 插件
在 main.js,使用清單 7 所示的方法加載資源文件,清單 7 中未指定“language”參數選項,表示使用瀏覽器語言。除了在 jQuery.i18n.properties() 定義的回調函數中使用資源文件中的定義的值外,成功加載資源文件後,我們也可以在其它地方使用這些值。
清單 7. 加載資源文件
function loadProperties(){ jQuery.i18n.properties({// 加載資瀏覽器語言對應的資源文件 name:'strings', // 資源文件名稱 path:'resources/i18n/', // 資源文件路徑 mode:'map', // 用 Map 的方式使用資源文件中的值 callback: function() {// 加載成功後設置顯示內容 // 顯示“用戶名” $('#label_username').html($.i18n.prop('string_username')); // 顯示“密碼” $('#label_password').html($.i18n.prop('string_password')); // 顯示“登錄” $('#button_login').val($.i18n.prop('string_login')); } }); }
當用戶點擊登錄按鈕後,我們使用 REST 請求將用戶信息發送到前文定義的 RESTFul Web 服務,若用戶信息驗證成功,則顯示歡迎信息和 Web 服務返回的密鑰,若驗證失敗則顯示錯誤信息,代碼如清單 8 所示。
清單 8. 前端登錄邏輯
$('#button_login').click(function(){// 點擊登錄按鈕後驗證用戶信息 var id = $('#username').val();// 用戶名 var payload = {}; payload['password']=$('#password').val(); payload = $.toJSON(payload); $.ajax({ url : 'rest/users/' + id + '/tokens',//REST URI type : 'POST', data: payload, // Request body contentType : 'application/json', dataType:'json', success : function(data) { // 驗證成功則顯示歡迎信息和密鑰 // 使用含佔位符的值 $('#content').html($.i18n.prop('string_hello',id,data.token)); }, error : function(jqXHR, textStatus, errorThrown) { if(jqXHR.status == 403){ // 用戶不存在 alert($.i18n.prop('string_usernotexist')); }else if(jqXHR.status == 401){ // 密碼錯誤 alert($.i18n.prop('string_wrongpassword')); }else{ // 其他異常信息 alert(errorThrown); } } }); });
運行效果
將 hello-i18n 項目部署到本地的 Tomcat 上,打開 Chrome 瀏覽器,將語言設置爲英文,在地址欄中輸入 http://localhost:8080/hello-i18n,運行效果如圖 2 所示。
圖 2. 英文環境下的運行效果
將語言更改爲簡體中文,重啓 Chrome,運行效果如圖 3 所示。
圖 3. 中文環境下的運行效果
問題與改進
資源文件命名問題
在上面的示例中,我們的程序只自動識別中文和英文兩種翻譯,而不能進一步區分簡體中文與繁體中文。爲了使上面的示例能夠根據瀏覽器語言設置自動區分簡體中文和繁體中文,我們將簡體中文對應的資源文件 strings_zh.properties 重命名爲 strings_zh_CN.properties,並添加如清單 9 所示的繁體中文資源文件 strings_zh_TW.properties。
清單 9. strings_zh_TW.properties
string_username= 用戶名 string_password= 密碼 string_login= 登入 string_hello= 您好 {0},歡迎使用 jQuery.i18n.properties,您的密鑰是:{1}。 string_usernotexist= 用戶不存在 string_wrongpassword= 密碼錯誤
運行程序,分別將瀏覽器語言設置爲“中文(簡體中文)”和“中文(繁體中文)”進行測試,發現程序並不能如我們預期顯示簡體中文和繁體中文,而是都以英文顯示。分析後發現,造成這種現象的原因,是 jQuery.i18n.properties 插件默認的資源文件命名方式與瀏覽器上報的語言區域編碼不一致,從而導致插件加載資源文件失敗。以簡體中文爲例,jQuery.i18n.properties 默認的資源文件命名方式爲“zh_CN”的形式,而瀏覽器上報的語言區域編碼爲 zh-CN”的形式,此時 jQuery.i18n.properties 插件加載資源文件的步驟如下:
- 加載默認資源文件即 strings.properties,成功。
- 加載名稱爲 strings_zh.properties 的資源文件,失敗。
- 加載名稱爲 stirngs_zh-CN.properties 的資源文件,失敗。
由於第 2 步和第 3 步都失敗,所以 jQuery.i18n.properties 使用默認資源文件 strings.properties 中的翻譯,也就是英文翻譯。同理,繁體中文也不能正常顯示。解決該問題有 3 種方法:
- 採用 strings_zh-CN.properties 的方式命名資源文件。這是最簡單的方法,但這種命名方式和 Java 標準的資源文件命名方式不一致;
-
使用默認的資源文件命名方式,並在調用 jQuery.i18n.properties() 方法之前使用 var lang = jQuery.i18n.browserLang()
的方式
顯式獲取瀏覽器的語言,然後將 lang 中的“-”替換爲”_”,並在使用 jQuery.i18n.properties() 方法時將 lang 作爲參數。 - 更改 jQuery.i18n.properties 的源碼。
這裏我們採用最簡單的第一種方式,將簡體中文對應的資源文件 string_zh_CN.properties 重命名爲 stirngs_zh-CN.properties,並將繁體中文對應的資源文件 strings_zh_TW.properties 重命名爲 strings_zh-TW.properties。現在,程序就可以根據瀏覽器語言設置自動區分簡體中文和繁體中文了,繁體中文的運行效果如圖 4 所示。
圖 4. 繁體中文環境下的運行效果
總結
本文對 jQuery 國際化插件 jQuery.i18n.properties 進行了介紹,並用實際例子介紹瞭如何使用 jQuery.i18n.properties 插件實現 Web 前端的國際化。總結起來,jQuery.i18n.properties 具有輕量級(壓縮後僅 4kb)、簡單易用等特點,但是作爲一個普及度不高的輕量級插件,不一定適用於大型的或對效率要求極高的場景。
希望本文能爲正在尋找小型 Web 應用前端國際化解決方案的讀者提供一定的參考。