(轉)在Struts 2.0中國際化(i18n)您的應用程序 + 本人拓展備註

國際化是商業系統中不可或缺的一部分,因此不管您學習的是什麼Web框架,它都是必須掌握的技能。javascript

其實,Struts 1.x在此部分已經作得至關不錯了。它極大地簡化了咱們程序員在作國際化時所需的工做,例如,若是您要輸出一條國際化的信息,只需在代碼包中加入FILE-NAME_xx_XX.properties(其中FILE-NAME爲默認資源文件的文件名),而後在struts-config.xml中指明其路徑,再在頁面用<bean:message>標誌輸出便可。html

不過,所謂「沒有最好,只有更好」。Struts 2.0並無在這部分止步,而是在原有的簡單易用的基礎上,將其作得更靈活、更強大。java

國際化Hello World

下面讓咱們看一個例子——HelloWorld。這個例子演示如何根據用戶瀏覽器的設置輸出相應的HelloWorld。程序員

  1. 在Eclipse建立工程配置開發和運行環境(若是對這個步驟有問題,能夠參考我早前的文章《爲Struts 2.0作好準備》)。
  2. 在src文件夾中加入struts.properties文件,內容以下:
    struts.custom.i18n.resources = globalMessages
    Struts 2.0有兩個配置文件,struts.xml和struts.properties都是放在WEB-INF/classes/下。
    • struts.xml用於應用程序相關的配置
    • struts.properties用於Struts 2.0的運行時(Runtime)的配置
  3. 在src文件夾中加入globalMessages_en_US.properties文件,內容以下:
    HelloWorld = Hello World!
  4. 在src文件夾中加入globalMessages_zh_CN.properties文件,內容以下:
    HelloWorld =你 好,世界!
    在此想和你們分享一個不錯的編寫properties文件的Eclipse插件(plugin),有了它咱們在編輯一些簡體中文、繁體中文等Unicode文本時,就沒必要再使用native2ascii編碼了。您能夠經過Eclipse中的軟件升級(Software Update)安裝此插件,步驟以下:
    一、展開Eclipse的Help菜單,將鼠標移到Software Update子項,在出現的子菜單中點擊Find and Install;
    二、在Install/Update對話框中選擇Search for new features to install,點擊Next;
    三、在Install對話框中點擊New Remote Site;
    四、在New Update Site對話框的Name填入「PropEdit」或其它任意非空字符串,在URL中填入http://propedit.sourceforge.jp/eclipse/updates/;
    五、在Site to include to search列表中,除上一步加入的site外的其它選項去掉,點擊Finsih;
    六、在彈出的Updates對話框中的Select the features to install列表中將全部結尾爲「3.1.x」的選項去掉(適用於Eclipse 3.2版本的朋友);
    七、點擊Finish關閉對話框;
    八、在下載後,贊成安裝,再按提示重啓Eclipse,在工具條看到形似vi的按鈕表示安裝成功,插件可用。此時,Eclpise中全部properties文件的文件名前有綠色的P的圖標做爲標識。
  5. 在WebContent文件夾下加入HelloWorl.jsp文件,內容以下:
    <% @ page  contentType = " text/html; charset=UTF-8 " %>
    <% @taglib prefix = " s " uri = " /struts-tags " %>
    < html >
    < head >
       
    < title > Hello World </ title >
    </ head >
    < body >
       
    < h2 >< s:text name ="HelloWorld" /></ h2 >
       
    < h2 >< s:property value ="%{getText('HelloWorld')}" /></ h2 >
    </ body >
    </ html >
  6. 發佈運行應用程序,在瀏覽器地址欄中輸入http://localhost:8080/Struts2_i18n/HelloWorld.jsp ,出現圖1所示頁面。
    圖1 中文輸出
    圖1 中文輸出
  7. 將瀏覽器的默認語言改成「英語(美國)」,刷新頁面,出現圖2所示頁面。
    圖2 英文輸出
    圖2 英文輸出

上面的例子的作法,與Struts 1.x的作法類似,彷佛並不能體現Struts 2.0的優點。不過,我在上面的例子用了兩種方法來顯示國際化字符串,其輸出是相同的。其實,這就是Struts 2.0的一個優點,由於它默認支持EL,所示咱們能夠用getText方法來簡潔地取得國際化字符串。另外更廣泛的狀況——在使用UI表單標誌時,getText能夠用來設置label屬性,例如:web

< s:textfield name ="name" label ="%{getText('UserName')}" />

資源文件查找順序

之因此說Struts 2.0的國際化更靈活是由於它能夠能根據不一樣須要配置和獲取資源(properties)文件。在Struts 2.0中有下面幾種方法:api

  1. 使用全局的資源文件,方法如上例所示。這適用於遍及於整個應用程序的國際化字符串,它們在不一樣的包(package)中被引用,如一些比較共用的出錯提示;
  2. 使用包範圍內的資源文件。作法是在包的根目錄下新建名的package.properties和package_xx_XX.properties文件。這就適用於在包中不一樣類訪問的資源;
  3. 使用Action範圍的資源文件。作法爲Action的包下新建文件名(除文件擴展名外)與Action類名一樣的資源文件。它只能在該Action中訪問。如此一來,咱們就能夠在不一樣的Action裏使用相同的properties名錶示不一樣的值。例如,在ActonOne中title爲「動做一」,而一樣用title在ActionTwo表示「動做二」,節省一些命名工夫;
  4. 使用<s:i18n>標誌訪問特定路徑的properties文件。使用方法請參考我早前的文章《經常使用的Struts 2.0的標誌(Tag)介紹》。在您使用這一方法時,請注意<s:i18n>標誌的範圍。在<s:i18n name="xxxxx">到</s:i18n>之間,全部的國際化字符串都會在名爲xxxxx資源文件查找,若是找不到,Struts 2.0就會輸出默認值(國際化字符串的名字)。

上面我列舉了四種配置和訪問資源的方法,它們的範圍分別是從大到小,而Struts 2.0在查找國際化字符串所遵循的是特定的順序,如圖3所示:瀏覽器

圖3 資源文件查找順序圖
圖3 資源文件查找順序圖session

假設咱們在某個ChildAction中調用了getText("user.title"),Struts 2.0的將會執行如下的操做: 框架

  1. 查找ChildAction_xx_XX.properties文件或ChildAction.properties;
  2. 查找ChildAction實現的接口,查找與接口同名的資源文件MyInterface.properties;
  3. 查找ChildAction的父類ParentAction的properties文件,文件名爲ParentAction.properties;
  4. 判斷當前ChildAction是否實現接口ModelDriven。若是是,調用getModel()得到對象,查找與其同名的資源文件;
  5. 查找當前包下的package.properties文件;
  6. 查找當前包的父包,直到最頂層包;
  7. 在值棧(Value Stack)中,查找名爲user的屬性,轉到user類型同名的資源文件,查找鍵爲title的資源;
  8. 查找在struts.properties配置的默認的資源文件,參考例1;
  9. 輸出user.title。

參數化國際化字符串

許多狀況下,咱們都須要在動行時(runtime)爲國際化字符插入一些參數,例如在輸入驗證提示信息的時候。在Struts 2.0中,咱們經過如下兩種方法作到這點:eclipse

  1. 在資源文件的國際化字符串中使用OGNL,格式爲${表達式},例如:
    validation.require = ${getText(fileName)} is required
  2. 使用java.text.MessageFormat中的字符串格式,格式爲{ 參數序號(從0開始), 格式類形(number | date | time | choice), 格式樣式},例如:
    validation.between = Date must between { 0 , date, short} and { 1 , date, short}

在顯示這些國際化字符時,一樣有兩種方法設置參數的值:

  1. 使用標誌的value0、value1...valueN的屬性,如:
    < s:text name ="validation.required" value0 ="User Name" />
  2. 使用param子元素,這些param將按前後順序,代入到國際化字符串的參數中,例如:
    < s:text name ="validation.required" >
       
    < s:param value ="User Name" />
    </ s:text >

讓用戶方便地選擇語言

開發國際化的應用程序時,有一個功能是必不可少的——讓用戶快捷地選擇或切換語言。在Struts 2.0中,經過ActionContext.getContext().setLocale(Locale arg)能夠設置用戶的默認語言。不過,因爲這是一個比較廣泛的應用場景(Scenario),因此Struts 2.0爲您提供了一個名i18n的攔截器(Interceptor),並在默認狀況下將其註冊到攔截器鏈(Interceptor chain)中。它的原理爲在執行Action方法前,i18n攔截器查找請求中的一個名爲"request_locale"的參數。若是其存在,攔截器就將其做爲參數實例化Locale對象,並將其設爲用戶默認的區域(Locale),最後,將此Locale對象保存在session的名爲「WW_TRANS_I18N_LOCALE」的屬性中。

下面,我將提供一完整示例演示它的使用方法。

package tutorial;

import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;

public class Locales {
   
public Map<String, Locale> getLocales() {
       Map
<String, Locale> locales =new Hashtable<String, Locale>(2);
       locales.put(
"American English", Locale.US);
       locales.put(
"Simplified Chinese", Locale.CHINA);
       
return locales;
   }

}

tutorial/Locales.java

<% @taglib prefix = " s " uri = " /struts-tags " %>
< script type ="text/javascript" >
<!--
   
function langSelecter_onChanged() {
        document.langForm.submit();
    }
// -->
</ script >
< s:set name ="SESSION_LOCALE" value ="#session['WW_TRANS_I18N_LOCALE']" />
< s:bean id ="locales" name ="tutorial.Locales" />
< form action ="<s:url includeParams=" get" encode ="true" /> " name="langForm" 
    style="background-color: powderblue; padding-top: 4px; padding-bottom: 4px;">
    Language:
< s:select label ="Language"  
        list
="#locales.locales" listKey ="value"    listValue ="key"
        value
="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"
        name
="request_locale" id ="langSelecter"  
        onchange
="langSelecter_onChanged()" theme ="simple" />
</ form >

LangSelector.jsp

上述代碼的原理爲,LangSelector.jsp先實例化一個Locales對象,並把對象的Map類型的屬性locales賦予下拉列表(select) 。如此一來,下拉列表就得到可用語言的列表。你們看到LangSelector有<s:form>標誌和一段Javascript腳本,它們的做用就是在用戶在下拉列表中選擇了後,提交包含「reqeust_locale」變量的表單到Action。在打開頁面時,爲了下拉列表的選中的當前區域,咱們須要到session取得當前區域(鍵爲「WW_TRANS_I18N_LOCALE」的屬性),而該屬性在沒有設置語言前是爲空的,因此經過值棧中locale屬性來取得當前區域(用戶瀏覽器所設置的語言)。

你能夠把LangSelector.jsp做爲一個控件使用,方法是在JSP頁面中把它包含進來,代碼以下所示:

< s:include value ="/LangSelector.jsp" />


在例1中的HellloWorld.jsp中<body>後加入上述代碼,並在struts.xml中新建Action,代碼以下:

< action name ="HelloWorld" >
   
< result > /HelloWorld.jsp </ result >
</ action >


或者,若是你多個JSP須要實現上述功能,你可使用下面的通用配置,而不是爲每個JSP頁面都新建一個Action。

< action name ="*" >
   
< result > /{1}.jsp </ result >
</ action >


分佈運行程序,在瀏覽器的地址欄中輸入http://localhost:8080/Struts2_i18n/HelloWorld.action,出現圖4所示頁面:
圖3 HelloWorld.action
圖3 HelloWorld.action

在下拉列表中,選擇「American English」,出現圖5所示頁面:
圖3 HelloWorld.action
圖4 HelloWorld.action

可能你們會問爲何必定要經過Action來訪問頁面呢?
你能夠試一下不用Action而直接用JSP的地址來訪問頁面,結果會是不管你在下拉列表中選擇什麼,語言都不會改變。這表示不能正常運行的。其緣由爲若是直接使用JSP訪問頁面,Struts 2.0在web.xml的配置的過濾器(Filter)就不會工做,因此攔截器鏈也不會工做。

 

王樂注:國際化的原理很好,用於國際化沒問題,另外,用於界面上的label說明也很好,好比用戶的維護界面(添刪改查界面)都會有「用戶名稱」標籤名稱,若是有個客戶要求把「用戶名稱」改爲「登陸名稱」,採用國際化的原理,在properties文件中改一個「用戶名稱」的key-value值對就能夠了。咱們如今在每一個界面上直接使用「用戶名稱」字體,須要改好幾個界面,若是有好幾個這樣的需求,就搞死人了。

相關文章
相關標籤/搜索