2011年9月9日 星期五

Java 的多國語言

在 Java 上要做多國語言,方法其實不太難,只要使用 ResourceBundle 搭配 properties 檔就可以了。
假設 properties 檔案的檔名為 i18n,則初始化 ResourceBundle 的方法如下
Locale locale = Locale.getDefault();
ResourceBundle bundle = ResourceBundle.getBundle("i18n", locale);
之後要取出多國語言的文字時,只要透過 ResourceBundle 的 getString() 方法即可。
不過要實際演練,還要先設置 properties 檔的內容!

properties 檔案是實際存放多國語言字串的檔案,檔名有固定的格式:自定檔名_語言代碼_國家代碼.properties
例如自定檔名為 i18n、語言是英文、國家是美國的話,檔名就是 i18n_en_US.properties
如果是台灣,就是 i18n_zh_TW.properties
語言代碼與國家代碼可以分別參照 ISO-639 與 ISO-3166 所規範的代碼。
在 Java 的 Locale 類別中所使用的也是一樣的代碼~。
而檔名如果沒有指定語言和國家代碼,則是表示預設的語言檔,例如 i18n.properties。

在建立 properties 檔案時要特別注意的地方是,ResourceBundle 僅允許以 ISO-8859-1 編碼撰寫
因此要在 properties 檔裡面放多國語言的文字時,必須先把文字轉換成 Java Unicode Escape 的格式。
例如:
language.zh_tw=\u7e41\u9ad4\u4e2d\u6587

假設我們建立了兩個 properties 檔案,如下所示。
i18n_en_US.properties
language.en_us=English
language.zh_tw=Traditional Chinese
i18n_zh_TW.properties
language.en_us=\u82f1\u6587
language.zh_tw=\u7e41\u9ad4\u4e2d\u6587
則用上面的程式碼初始化 ResourceBundle 以後,就可以用 getString() 方法取得對應的語言了。
Locale locale = new Locale("zh", "TW");
ResourceBundle bundle = ResourceBundle.getBundle("i18n", locale);
String language = bundle.getString("language.zh_tw");
這裡我在初始化 ResourceBundle 時,指定了要使用的 Locale 是 zh-TW
因此 ResourceBundle 會去幫我找 i18n_zh_TW.properties 檔是否存在
如果不存在的話,它會嘗試去找到預設的 properties。
然後 getString() 處指定要的字串是 key 為 language.zh_t 的字串
因此 language 這個字串物件會得到 \u7e41\u9ad4\u4e2d\u6587 這組萬國碼,也就是 "繁體中文" 的字串。

註:這裡只是舉例而已,實際上如果要對語言的選項做多國語言,上面的例子是很糟糕的
例如語言選項中,我有英文、日文、韓文、繁體中文這四個選項,但如果當前是中文介面時
對美國人、日本人、韓國人來說,他絕對看不懂這四個選項哪個才是他的母語。
因此在語言選項中,最好的方法應該是英文就要用英文來顯示、中文就要用中文顯示,以此類推。


需要特別注意的是~resource 檔案的放置位置跟 getBundle() 時給的位置,是跟 package 有關的 [4]。
如果位置只輸入檔案名稱,ResourceBundle 會去抓 package=null 的位置,所以必須給包含 package 全名的位置。
例如如果 properties 檔案是放在 com.c.b.a 這個 package 裡面
則使用 ResourceBundle 時,指定的 properties 路徑就要是 "com.c.b.a.i18n"。
Locale locale = Locale.getDefault();
ResourceBundle bundle = ResourceBundle.getBundle("com.c.b.a.i18n", locale);

2011-10-19 補充:
如需將 ResourceBundle 指定到某個絕對路徑,請參考:Java 的多國語言:在 ResourceBundle 中使用絕對路徑

2012-02-16 補充:
要把文字轉成 UTF-8 可以用這個工具:http://pulipuli.blogspot.com/2008/01/dspaceutf-8.html

2012-09-13 補充:
因為原本連結的教學文章 [1] 現在連不到了,所以把上面文章整個重寫了一次!另外補充幾個參考連結進去
此外這幾天在測試利用 ResourceBundle 把 i18n 放到 Java Application 上
但意外地遇到了一些奇怪的問題~
目前感覺我有一行是寫下面的內容,然後這一行一放到 properties 檔裡面,似乎編譯的 jar 執行就會出現 MissingResourceException。

dialog.about.email=E-mail: aaaaaaaaaa\u40bbb.ccc.ddd.ee

這串內容其實就是想要寫應用程式的「關於」,內容就是一行「E-mail: aaaaaaaaaa@bbb.ccc.ddd.ee」
當然原文的 E-mail 部分不是這麼寫的,這裡是馬賽克版的 E-mail!XD

除此之外,感覺上 properties 檔似乎盡量不要放空行,好像比較不容易出現奇怪的問題
不過這個只是純感覺 XD,因為我也有在一個網站專案上使用 ResourceBundle,但網站專案放了一堆空行就完全沒有問題...。

參考資料:
1、Java 訊息多國語言化 How-To
2、Java多國語言化
3、java.util.ResourceBundle使用详解
4、Solve java.util.MissingResourceException: Can't find bundle for base name com...config, locale zh_CN
5、Trail: Internationalization

沒有留言: