國際化英文單詞爲:Internationalization,又稱I18N,I爲由於單詞的第一個字母,18爲這個單詞的長度,而N表明這個單詞的最後一個字母。國際化又稱本地化(Localization,L10N)。 java
Java國際化主要經過以下3個類完成 數組
爲實現程序的國際化,必須提供程序所須要的資源文件。資源文件的內容由key-value對組成,資源文件的命名能夠有3種格式: app
若資源文件包含非西方字符,則須要用JDK自帶的工具來處理:native2ascii,這個工具的語法格式以下: 工具
native2ascii 資源文件名 目標資源文件名 編碼
如: spa
native2ascii mess_zh_XXX.proerties mess_zh_CN.proerties 翻譯
Locale類可獲取各國區域環境(如:Locale.ENGLISH、Locale.CHINESE,這些常量返回一個Locale實例),也能夠獲取當前系統所使用的區域語言環境,也可使用語言和區域來建立Locale對象,Java的本地語言使用的時國際化標準組織(ISO)所定義的編碼,本地語言由小寫的兩個字母的代碼表示,遵循ISO-639-1;國家代碼由大寫的兩個字母的代碼組成,遵循ISO-3166-1,下表爲經常使用的代碼: code
語言orm |
代碼對象 |
國家 |
代碼 |
Chinese |
zh |
China |
CN |
English |
en |
United States |
US |
Japanese |
ja |
Japan |
JP |
可使用Locale的靜態方法 getAvailableLocales 來獲取所支持的語言和國家,該方法返回一個Locale數組,該數組裏包含了java所支持的語言和國家,代碼以下:
Locale[] availableLocales = Locale.getAvailableLocales();
for (Locale l : availableLocales) {
System.out.println("Locale DisplayName=" + l.getDisplayName() + " Country=" + l.getCountry() + " Language="
+ l.getLanguage());
}
數字和貨幣的格式時高度依賴與Locale的,Java類庫提供了一個格式器(formatter)對象的集合,能夠對java.text包中的數字值進行格式化和解析,能夠經過下面的步驟來對特定的Locale的數字進行格式化:
格式化示例代碼:
Locale deLocale = new Locale("de", "DE");
NumberFormat currFmt = NumberFormat.getCurrencyInstance(deLocale);
double amt = 123878.34;
String formatResult = currFmt.format(amt);
System.out.println("amt=" + amt + " Format=" + formatResult);
若是想要讀取一個按照某個Locale的慣用法而輸入或存儲的數字,那邊就須要使用 parse 方法。
解析示例代碼:
Localede Locale=newLocale("de","DE");
NumberFormat currFmt=NumberFormat.getCurrencyInstance(deLocale);
Number input=currFmt.parse(formatResult);
double parseAmt=input.doubleValue();
System.out.println("FormatAmt="+formatResult+"ParseAmt="+parseAmt);
當格式化日期和時間時,須要考慮4個與Locale相關的問題,例如:月份和星期應該用本地語言來表示;年月日的順序要符合本地習慣;公曆可能不是本地首選的日期表示方法;必需要考慮本地時區。Java 使用 DateFormat 類來處理這些問題,和 NumberFormat 類很相似,調用 DateFormat 類的靜態方法,並傳入 Locale 來實例化,還須要設置日期或時間的格式化值,DateFormat 有以下三個工廠方法:
DateFormat.getDateInstance(dateStyle,loc);
DateFormat.getTimeInstance(timeStyle,loc);
DateFormat.getDateTimeInstance(dateStyle,timeStyle,loc);
其日期和時間的風格使用 DateFormat 的靜態常量來表示,經常使用的靜態常量以下:
DateFormat.DEFAULT
DateFormat.FULL
DateFormat.LONG
DateFormat.MEDIUM
DateFormat.SHORT
示例代碼以下:
String fmt = "";
Date nowDate = new Date();
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, zhLocale);
fmt = dateFormat.format(nowDate);
System.out.println("Short style date string " + fmt);
dateFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM, zhLocale);
fmt = dateFormat.format(nowDate);
System.out.println("MEDIUM style time string " + fmt);
dateFormat = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, zhLocale);
fmt = dateFormat.format(nowDate);
System.out.println("FULL style date FULL style time string " + fmt);
若是要解析一個用戶輸入的日期,可使用 DateFormat 類的 parse 方法,但其輸入的格式必須和建立 DateFormat 對象設置的風格一致,若是不一致則會拋出 IllegalArgumentException 異常,默認支持寬鬆的轉換,好比日期 2017年2月30日,會被解析爲 2017年3月2日,若是但願關閉寬鬆的轉換,須要設置 lenient 標識,示例代碼以下:
dateFormat.setLenient(false);
Date convertDate = dateFormat.parse(fmt);
System.out.println("parse string " + fmt + " convertDate " + convertDate);
Java 中的排序時用Unicode字符來決定順序的,好比小寫字母的Unicode值比大寫的大,有重音符的字母的值甚至更大,這樣將使結果失去意義,若是須要定義排序的強度,可使用Locale對象來建立 Collator 類,該類繼承了 Comparator接口,所以能夠將該對象傳遞給 Collections.soft 方法來進行排序,示例代碼以下:
List<String> list = new LinkedList<>();
list.add("America");
list.add("Zulu");
list.add("able");
list.add("zebra");
Collator collator = Collator.getInstance(zhLocale);
// 設置排序強度
collator.setStrength(Collator.PRIMARY);
Collections.sort(list, collator);
能夠設置排序強度來選擇不一樣的排序行爲,字符間的差異能夠被分爲首要的(primary)、其次的(secndary)和再次的(tertiary)。好比,在英語中,A 和 Z 之間的差別被歸類爲首要的;A 和 Å (重音符)之間的差別是其次的;A 和 a 之間是再次的,可使用方法 setStrength 來設置排序強度,Collator.PRIMARY 表示首要的、Collator.SECONDARY 表示其次的、 Collator.TERTIARY 表示再次的,而Collator.IDENTICAL 則表示不容許有任何差別。
偶爾咱們會碰到一個字符或字符序列在描述成Unicode時,能夠有多種方式,例如,字母序列"ffi"能夠用代碼U+FB03描述成單個字符"拉丁小連字ffi",Unicode 標準對字符串定義了四種範式形式:D、KD、C和KC,其中 D 和 KD 時用於排序的,在範化形式 D 重,重音字符被分解爲基字符和組合重音符;範化形式 KD 更進一步將兼容性字符也進行了分解,例如 ffi 連字符或商標符號TM,咱們能夠選擇排序器所使用的範化程度:Collator.NO_DECOMPOSITION表示不對字符串作任何範化;Collator.CANONICAL_DECOMPOSITION 使用範化形式 D;Collator.FULL_DECOMPOSITION 使用範化形式 KD。可使用方法 setDecomposition 來設置分解模式
Java 類庫中有一個 MessageFormat 類,用來格式化帶變量的文本,就像這樣:"今天 {0} 是個好日子,{1} 公司給我發了工資 {2} 元",括號中的數字是一個佔位符,能夠用實際的名字和值來替換他,使用靜態的 MessageFormat.format 方法,該方法使用當前系統的 Locale 對值進行格式化,若是須要用指定的 Locale 來進行格式化,須要使用 MessageFormat 實例的 format 方法,示例代碼以下:
String mfString = "今天 {0} 是個好日子,{1} 公司給我發了工資 {2} 元";
String formatString = MessageFormat.format(mfString, new Date(), "匯元1", 50000);
System.out.println(formatString);
MessageFormat mf = new MessageFormat(mfString, zhLocale);
formatString = mf.format(new Object[]{new Date(), "匯元2", 50000});
System.out.println(formatString);
若是還想在指定佔位符的同時設置類型和樣式,能夠按照以下格式:
String mfString = "今天 {0,date,long} 是個好日子,{1} 公司給我發了工資 {2,number,currency} 元";
mf = new MessageFormat(mfString, zhLocale);
formatString = mf.format(new Object[]{new Date(), "匯元3", 50000});
System.out.println(formatString);
輸出內容
今天 2017年5月26日 是個好日子,匯元3 公司給我發了工資 ¥50,000.00 元
佔位符索引後面能夠跟一個類型和樣式,之間用逗號隔開,類型能夠是number、time、date、choice,若是類型是 number 則樣式有 integer、currency、percent;若是類型是 time 或 date,那麼樣式有 short、medium、long、full 或者是一個日期模式(yyyy-MM-dd);choice 表示但願消息跟隨佔位符的值而變化,選項格式是由一個序列對構成的,每一個序列對包含一個下限和一個格式化字符串,下限和字符串使用#號分隔,對於對之間用 | 分隔,示例以下:
mfString = "今天 {0,date,yyyy-MM-dd} 是個好日子,{1,choice,0#匯元|1#匯元1|2#匯元2} 公司給我發了工資 {2,number,currency} 元";
mf.applyPattern(mfString);
formatString = mf.format(new Object[]{new Date(), 1, 50000});
System.out.println(formatString);
可使用 < 符號或 ≤ 符號 來替換 # ,則表示值小於或者小於等於下限值,示例代碼以下:
// choice說明: 這個表示 小於 1000 而且 1001-5000 的使用"可憐" ,5001-50000 的使用"不夠",50001 以上爲"正好"
mfString = "今天 {0,date,yyyy-MM-dd} 是個好日子,{1} 公司給我發了工資 {2,number,currency} 元,{2,choice,1000<可憐|5000<不夠|50000<正好}";
mf.applyPattern(mfString);
formatString = mf.format(new Object[]{new Date(), "匯元4", 60000});
System.out.println(formatString
輸入內容
今天 2017-05-26 是個好日子,匯元4 公司給我發了工資 ¥60,000.00 元,正好
當本地化一個應用時,可能會有大量的消息字符串、按鈕標籤和其餘的東西須要被翻譯,爲了能靈活的完成這項任務,你會但願外部定義消息字符串,一般稱之爲資源(resource),翻譯人員不須要接觸程序源代碼就能夠很容易的編輯資源文件,在Java 中使用屬性文件來設定字符串資源,並未其餘類型的資源實現相應的類。
當本地化一個應用時,會製造出不少資源包(resource bundle),每個包都是一個屬性文件或者一個描述了玉locale相關的項的類,對於每個包,都要爲全部你想要支持的locale提供相應的版本,並須要對這些包使用一種統一的命名規則,例如,爲中國定義的資源放在一個名爲"包名_zh_CN"的文件中,而爲全部使用中文簡體的國家所共享的資源則放在名爲"包名_zh"的文件中,通常來講,使用
包名_語言_國家
來命名全部和國家相關的資源,使用
包名_語言
來命名全部和語言相關的資源,最後,做爲後備,能夠把默認資源放到一個沒有後綴的文件中,可使用下面的代碼加載一個包:
ResourceBundle resourceBundle = ResourceBundle.getBundle(bundleName, locale);
getBundle 方法加載包的順序以下:
一旦getBundle 方法定位了一個包,好比,"包名_zh_CN" ,他還會繼續查找"包名_zh"和"包名"這二個包,若是這些包也存在,他們在資源層次中就稱爲了"包名_zh_CN"的父包,之後查找資源的時候,若是在當前包中沒有找到,就會去查找其父包。
屬性文件是爲了提供字符串資源經常使用的文件,每行存放一個鍵-值對的文本文件,好比,MyProgramStrings.properties 就是一個屬性文件,存儲屬性文件都是ASCII文件,而後可使用 native2ascii 工具來產生MyProgramStrings_語言_國家.properties 文件,示例以下:
native2ascii MyProgramStrings.properties MyProgramStrings_zh_CN.properties
要查找一個具體的字符串,能夠調用:
String resourceText= resourceBundle.getString("show.text");
示例資源文件內容:
show.text=\u8fd9\u4e2a\u662f\u8d44\u6e90\u6587\u4ef6\u7684\u5185\u5bb9
爲了提供字符串之外的資源,須要定義類,必須繼承 ResourceBundle 類(簡單的方法是繼承 ListResourceBundle類),應該使用標準的命名規則來命名類,好比:
MyProgramResource.java
MyProgramResource_zh.java
MyProgramResource_zh_CN.java
可使用與加載屬性文件相同的 getBundle 方法來加載這個類,其 bundleName 爲 資源包類的完整命名(包名和類名):
ResourceBundle resourceBundle1Class =
ResourceBundle.getBundle("locale.MyProgramResource", Locale.SIMPLIFIED_CHINESE);
要查找一個字符串或其餘類型資源能夠調用:
resourceText = resourceBundle1Class.getString("resourceClass.show.text");
Object resourceObj = resourceBundle1Class.getObject("resourceClass.show.obj");
若是一個Key同時存在屬性文件和包類,則包類的優先。