1.1 什麼是I18N問題?
在英文中, 國際化(Internationalization)被縮寫爲I18N, 即只取首尾兩個字母, 中間字母爲18個。
問題在哪裏?
1.2 一個簡單的例子
public class EnglishHelloWorld {
/** * @param args */ public static void main(String[] args) { System.out.println("Hello World"); }
}
|
public class ChineseHelloWorld {
/** * @param args */ public static void main(String[] args) { System.out.println("世界,你好"); }
} |
上述兩個例子中,如果要分別輸出英文和中文文本,就需要寫兩個程序。利用國際化處理機制,可以只寫一個程序。即我們需要將程序中硬編碼的文本轉移到外部的資源文件(.properties文件)中!針對每一種語言環境,我們需要編寫一個資源文件。然後指定當前應用程序所使用的語言環境,JAVA中的國際化處理機制,將能夠自動找到對應的資源文件,並將其中的文本內容讀出來。
下面我們將硬編碼的文本轉移到資源文件中。我們需要三個資源文件:
一個缺省的資源文件,即如果不指定語言環境,默認使用的資源文件;
一個用於中文環境的資源文件,如果指定是中文環境,將使用此資源文件;
一個用於英文環境的資源文件,如果指定是英文環境,將使用此資源文件;
MessageResources.properties文件:
hello=Hello World! |
MessageResources_en.properties文件:
hello=Hello World! |
MessageResources_zh.properties文件:
hello=/u4e16/u754c/uff0c/u4f60/u597d |
特別注意上述MessageResources_zh.properties文件,因爲JAVA要求.properties文件不允許包含非ASCII(請自行上網查閱ASCII字符包括哪些字符,主要是英文和一些常見的符號,而中文等字符不屬於ASCII字符)字符,所以對於中文,需要將中文轉換爲UNICODE編碼的字符,並用/u+UNICODE編碼來表示中文。
native2ascii.exe程序(在JAVA安裝目錄下面的bin目錄下),就是用來將中文的字符轉換爲/u+UNICODE編碼的文本的工具。
我們可以編寫一個MessageResources_zh.txt文件:
hello=世界,你好 |
然後,在命令行下,通過如下命令,將MessageResources_zh.txt文件轉換爲MessageResources_zh.properties文件:
native2ascii MessageResources_zh.txt MessageResources_zh.properties |
資源文件的命名規則:
資源名稱_語言代碼_國家/地區代碼.properties
其中,國家/地區代碼是可選的。如果要加上國家/地區代碼,上述資源文件,可命名爲:
MessageResources_zh_CN.properties
MessageResources_en_US.properties
語言代碼是小寫的字母,國家/地區代碼是大寫的字母。
補充:JAVA都能支持哪些語言代碼和國家/地區代碼?
public static void main(String[] args) { Locale[] locales = DateFormat.getAvailableLocales(); for(Locale locale:locales){ System.out.println("語言代碼:"+locale.getLanguage()+",國家代碼"+locale.getCountry()); } } |
其輸出如下:
語言代碼:ja,國家代碼JP 語言代碼:es,國家代碼PE 語言代碼:en,國家代碼 語言代碼:ja,國家代碼JP 語言代碼:es,國家代碼PA ………………………………………(忽略其它輸出) |
² 語言代碼標準:http://ftp.ics.uci.edu/pub/ietf/http/related/iso639.txt
² 國家代碼標準:http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
準備好了資源文件之後,我們可以編寫下面的代碼來測試:
public class HelloWorld {
/** * @param args */ public static void main(String[] args) { ResourceBundle rb = ResourceBundle.getBundle("MessageResources",Locale.CHINA); String hello = rb.getString("hello"); System.out.println(hello); }
} |
public class HelloWorld {
/** * @param args */ public static void main(String[] args) { ResourceBundle rb = ResourceBundle.getBundle("MessageResources",Locale.US); String hello = rb.getString("hello"); System.out.println(hello); }
} |
1.3 Locale對象
Locale對象代表了一種語言環境和國家/地區。
比如,日期、貨幣等等都跟Locale有關。隨着Locale的不同,日期貨幣的表現形式也不一樣。
1.4 Struts1對國際化的支持
l 頁面字符串硬編碼
l 異常消息的硬編碼
l 提示信息的硬編碼
1、需要在struts配置文件中指定資源屬性文件的位置和名稱,如
<message-resources parameter="MessageResources" />
關於message-resources 配置中parameter的值
parameter的值,可以指定資源文件的位置和名稱
舉例:
<message-resources parameter="MessageResources" />
表示在類路徑根目錄(WEB-INF/classes目錄)下有MessageResources_XX_XX.properties文件(注意:國家代碼可以省略,跟java中對資源屬性文件的處理一樣)
<message-resources parameter="resources.application"/>
表示在類路徑根目錄下,有一個resources目錄,在這個resources目錄中存放着所有的application_XX_XX.properties資源屬性文件
2、在相應的位置放置相應的文件
MessageResources.properties
MessageResources_zh.properties
MessageResources_en.properties
3、即可運用下述方法,對頁面字符串、異常消息、提示消息的硬編碼換成國際化的表示方法了!
1.4.1 頁面字符串硬編碼的替換
用<bean:message key=”xxx”/>來替換
如何用程序切換網頁顯示的語言
struts利用在session中存放一個Locale對象來達到設置當前語言的目的
默認的情況下,struts根據網頁向後臺提交時所包含的語言編碼信息來提供缺省的Locale對象,這就是我們爲什麼可以通過更改網頁顯示語言設置,就能顯示不同的語言文字的原因。
struts在session中存放的這個Locale對象,取名爲:Globals.LOCALE_KEY 的值,Globals是struts框架提供的一個對象
利用這個原理,我們可以用編程的方式來手工切換整個應用系統的語言。
舉例說明
ChangeLanguageAction
String lan = request.getParameter("lan");
Locale locale = new Locale(lan);
request.getSession().setAttribute(Globals.LOCALE_KEY, locale);
ActionForward f = new ActionForward(); f.setPath(request.getHeader("referer")); f.setRedirect(true);
return f; |
1.4.2 異常消息和提示消息的硬編碼
l 爲什麼需要消息處理?
n 比如登錄成功的提示
n 比如創建失敗的提示
n 等等……總之,程序總是要通過界面來跟用戶交互,所以,在交互的過程中,就產生了衆多的消息文本
l struts提供了專門的處理機制,來將這些消息文本國際化,避免消息文本的硬編碼
l 消息處理,就是在Action和JSP之間傳遞的消息文本的處理(區別於JSP頁面硬編碼文本的消息,JSP頁面硬編碼文本可以使用<bean:message/>標籤來處理)
l Struts交互消息,是通過ActionMessages等對象,以及相應的<html:messages/>和<html:errors/>標籤來處理的
如何創建消息對象?
l ActionMessages與ActionMessage對象
n ActionMessages對象是ActionMessage對象的集合
n 一個ActionMessage對象,代表一個國際化消息文本(字符串)
l 如何創建ActionMessages對象?
n ActionMessages messages = new ActionMessages();
l 如何創建ActionMessage對象?
n ActionMessage msg = new ActionMessage(“key”);
n 其構造方法帶的參數,就是一個在資源屬性文件中的key,所以,它能表示一個國際化消息文本
l 如何將ActionMessage對象添加到ActionMessages對象中?
n messages.add(“message_id”,msg);
n 第一個參數(message_id)表示本ActionMessage對象在ActionMessages對象中區別於其它ActionMessage對象的標識符
如何將消息對象從Action中傳遞到下一個頁面(JSP)?
l 首先我們要決定的是,我們要傳遞的消息是普通消息還是錯誤消息?
n 普通消息:即普通的消息文本
n 錯誤消息:即提示錯誤的消息文本
n 本質上,這兩種消息沒有什麼區別,都是消息文本,但是如果一個頁面同時需要顯示普通的消息文本和錯誤消息文本的時候,就需要進行區分了,比如不同類型的消息文本可能要用不同的樣式來顯示
l 通過一句簡單的代碼,將ActionMessages對象保存到HttpServletRequest對象中
n 保存普通消息:this.saveMessages(request,messages);
n 保存錯誤消息:this.saveErrors(request,messages);
n 這就是調用父類(Action)所提供的方法saveMessages()/saveErrors()來保存消息對象
n 實際上,父類的saveMessages()方法,將消息對象保存在了request中,並命名爲Globals.MESSAGE_KEY
n saveErrors()方法,將消息對象保存在了request中,並命名爲Globals.ERROR_KEY
如何在JSP中使用消息對象?
l 使用<html:messages/>標籤來顯示消息
l <html:messages/>標籤既可以顯示普通消息,也可以顯示錯誤消息
l <html:messages/>標籤的重要屬性:
n name – 消息對象的名稱,如果我們調用saveMessages/saveErrors方法來傳遞消息,那麼這個名字不需要標識(struts使用缺省的名稱,即Globals.MESSAGE_KEY 或Globals.ERROR_KEY )
n id – (這是必需的屬性)因爲我們傳遞的是ActionMessages對象,而不是ActionMessage對象,ActionMessages對象相當於一個集合,我們需要在JSP上依次輸出它所包含的消息,因此需要一個id標識一個變量來臨時存放其每條消息(與<logic:iterate/>標籤的id屬性的意義是一樣的)
n property – 我們傳遞的ActionMessages對象,包含了多條消息文本,如果我們只需要顯示其中一條,則可以通過property屬性來指定顯示哪條消息
n message – 可以取值爲true或false,如果取值爲true,將顯示普通消息,如果取值爲false,將顯示錯誤消息
<html:errors/>標籤
l <html:errors/>標籤只顯示錯誤消息
l <html:errors/>標籤與<html:messages/>標籤類似,但無id屬性
l <html:errors/>標籤通過提供header/footer屬性以及prefix/suffix屬性來定製每條消息的顯示格式
n header/footer – 定義整個錯誤消息顯示之前(之後)要顯示的內容,這些內容也是在資源屬性文件中定義的一些key值,默認的情況下,它們的取值分別爲:errors.header和errors.footer
n prefix/suffix – 定義每條錯誤消息顯示之前(之後)要顯示的內容,這些內容也是在資源屬性文件中定義的一些key值,默認的情況下,它們的取值分別爲:errors.prefix和errors.suffix
舉例如下:
errors.header=<UL>
errors.prefix=<LI>
errors.suffix=</LI>
errors.footer=</UL>