國際化信息又稱為本地化信息,由語言類型(如zh)和國家/地區類型來限定(如CN)。java.util.Locale是創建國際化的基礎類。spring管理國際化定義了MessageSource介面。ResourceBundleMessageSource實現了MessageSource介面。
國際化又稱為本地化。
當你把手機的language由中文切換到英文時,你的微信也相應改用英語,這就是i18n國際化。一般來說,應用軟體提供一套不同語言的資源文件,放到特定目錄中,應用根據不同語言的操作系統決定使用哪一種語言。
一般由兩個條件限定一個國際化類型:語言類型和國家/地區類型。比如:
中文:語言類型:zh,國家/地區類型:CN(中國大陸)/HK(中國香港)/TW(中國臺灣)。
英語:語言類型:en,國家類型:EN。
----------------------------------------------------------------------------------------------------------------
java.util.Locale是一個本地化類,是創建國際化應用的基礎。
創建本地化對象有多種方式:Locale locale1=new Locale("zh","CN");//倆參,語言類型、國家類型
Locale locale2=new Locale("zh");//預設本地語言類型
Locale locale3=Locale.CHINA;//常量
Locale locale4=Locale.getDefault();//預設的本地化對象。
-------------------------------------------------------------------------------------------------------
光有本地化類還不行,需要有個利用本地化對象來操作輸出信息的類:
java.text包中提供了幾個這樣的工具類:DateFormat、MessageFormat、NumberFormat。
----------------------------------------------------------------------------------------------------
NumberFormat舉例:給一個123456.78,把它輸出為¥123456.78,即把數字轉換為貨幣格式。
1 Locale locale = new Locale("zh","CN"); 2 NumberFormat nf=NumberFormat.getCurrencyInstance(locale); 3 System.out.println("一頭羊售價:"+nf.format(d));
public static void main(String args[]){ printCurrency(888.88); }
列印:一頭羊售價:¥888.88
-------------------------------------------------------------------------------------------------------
DateFormat舉例:給一個當前時間Date()對象,把它轉換成英文格式。
public static void printUSDate(Date date){ Locale locale=new Locale("en","US"); DateFormat df=DateFormat.getDateInstance(DateFormat.MEDIUM, locale); System.out.println(df.format(date)); } public static void main(String args[]){ printUSDate(new Date()); }
列印:Jan 10, 2016。
上面的DateFormat.MEDIUM是啥?java源碼註釋:
/** * Constant for long style pattern. */ public static final int LONG = 1; /** * Constant for medium style pattern. */ public static final int MEDIUM = 2; /** * Constant for short style pattern. */ public static final int SHORT = 3; /** * Constant for default style pattern. Its value is MEDIUM. */ public static final int DEFAULT = MEDIUM;
把參數DateFormat.MEDIUM改成DateFormat.LONG,列印:January 10, 2016。
-------------------------------------------------------------------------------------------------------
MessageFormat:增加占位符功能。
什麼是占位符功能?比如:我定義一個字元串:昨天{0}在{1}睡覺呢。傳參{"小明","家"},那麼列印:昨天小明在家睡覺呢。傳參:{"大鵬","學校"},那麼列印:昨天大鵬在學校睡覺呢。
舉例1:銀行給John說:John您好,你於XXX在招商銀行存入XX元。不同時間,銀行又對David說:David您好,你於XXX在招商銀行存入XX元。信息相同,使用MessageFormat。參數信息可以動態改變。
public static void printBankNotice(Object[] params){ String pattern1="{0},你好,你於{1}在招商銀行存入{2}元。"; String message1=MessageFormat.format(pattern1, params); System.out.println(message1); } public static void main(String args[]){ printBankNotice(new Object[]{"John",new GregorianCalendar().getTime(),1.0E3}); }
列印:John,你好,你於16-1-10 上午2:24在招商銀行存入1,000元。
占位符功能還能對參數格式作適當的轉換,參數順序也可以靈活調整。
public static void printBankNotice2(Object[] params){ String pattern2="At{1,time,short} on{1,date,long},{0} paid {2,number,currency}."; MessageFormat mf=new MessageFormat(pattern2,Locale.US); System.out.println(mf.format(params)); } public static void main(String args[]){ printBankNotice2(new Object[]{"John",new GregorianCalendar().getTime(),1.0E3}); }
列印:At2:32 AM onJanuary 10, 2016,John paid $1,000.00.
---------------------------------------------------------------------------------------------------
應用程式中需要國際化,則使用java.util.ResourceBundle,
舉例:定義一個英文的屬性文件和一個中文的屬性文件,裡面放一些問候語,根據程式的需要選擇不同語言的問候語。
步驟:
1.在程式的特定位置定義兩個properties文件,一個是中文的,一個是英文的,名稱格式為:
<資源名>_<語言代碼>_<國家/地區編碼>.properties
resource_en_US.properties內容:
greeting.common=How are you! greeting.morning = Good morning! greeting.afternoon =Good Afternoon\!
resource_zh_CN.properties內容:
greeting.common=\u60A8\u597D\uFF01 greeting.morning=\u65E9\u4E0A\u597D\uFF01 greeting.afternoon=\u4E0B\u5348\u597D\uFF01
(資源文件只能包含ASCII字元,所以你這樣寫了,程式運行時需要把這樣的字元轉換成Unicode的表示形式。但是這樣編寫我們不熟悉,也不現實,所以,MyEclipse提供了屬性編輯器,可以方便我們寫中文):
切換到Properties視窗:
在這裡編寫就好。
接下來使用ResourceBundle。
public static void resourceBoundle(){ ResourceBundle rb1 = ResourceBundle.getBundle("com/baobaotao/i18n/resource",Locale.US); ResourceBundle rb2 = ResourceBundle.getBundle("com/baobaotao/i18n/resource",Locale.CANADA); System.out.println("us:"+rb1.getString("greeting.common")); System.out.println("cn:"+rb2.getString("greeting.common")); }
上文講到了占位符功能,在這裡,你也可以把properties文件的屬性值寫成占位符形式,然後用ResourceBundle結合MessageFormat實現國際化字元串的動態改變。
---------------------------------------------------------------------------------------------------------
Spring的國際化
spring定義了MessageSource介面來實現國際化,它引入了java.util.Locale,並用getMessage方法載入國際化信息。也就是說,spring國際化的原理還是引用了上面講的java的那一套,不過把它引入到了spring容器中。
類圖結構:
根據繼承關係我們看到,ResourceBundleMessageSource、ReloadableResourceBundleMessageSource、ApplicationContext都具有MessageSource功能。
-----------------------------------------------------------------------------------------------------------------------------------------------
ResourceBundleMessageSource是spring一般的國際化方法類。使用也很簡單,
在XML中註冊該類,容器啟動時就會實例化該類:
<bean id="myResource1" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>com/baobaotao/i18n/fmt_resource</value>
</list>
</property>
</bean>
list裡面可以放多個properties文件,這裡fmt_resource是一個通用名,包含了該名下所有的properties文件,
在代碼中,啟動spring容器,載入MessageSource,定義格式化串,調用getMessage就可以了:
private static void rsrBdlMessageResource(){ String[] configs = {"com/baobaotao/i18n/beans.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(configs); //步驟1:獲取MessageSource實例化對象 MessageSource ms = (MessageSource)ctx.getBean("myResource1"); //步驟2:定義格式化串 Object[] params = {"John", new GregorianCalendar().getTime()}; //步驟3:調用getMessage方法啊 String str1 = ms.getMessage("greeting.common",params,Locale.US); String str2 = ms.getMessage("greeting.morning",params,Locale.CHINA); String str3 = ms.getMessage("greeting.afternoon",params,Locale.CHINA); System.out.println(str1); System.out.println(str2); System.out.println(str3); }
-------------------------------------------------------------------------------------------------
ReloadableResourceBundleMessageSource:
跟ResourceBundleMessageSource相比,它多了一個定時刷新功能,即,系統在不重啟的情況下,修改properties文件,使用ReloadableResourceBundleMessageSource重新載入(定時)。
在XML中註冊bean的時候加一個定時屬性就可以了:
<bean id="myResource2" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <value>com/baobaotao/i18n/fmt_resource</value> </list> </property> <property name="cacheSeconds" value="2"/> </bean>
---------------------------------------------------------------------------------------------------------
ApplicationContext的國際化功能:
ApplicationContext屬於容器級,它賦予了國際化信息功能,是因為國際化信息常常作為容器的公共基礎設施對所有組件開放。
使用容器級國際化很簡單,針對ResourceBundleMessageSource作一點點修改:
配置文件上的修改:
<bean id="mySource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>com/baobaotao/i18n/fmt_resource</value> </list> </property> </bean>
代碼修改:
去掉getBean步驟,直接用ctx.getMessage獲取字元串。
------------------------------------------------------------------------------------------------------
總結:
- 國際化信息又稱為本地化信息,由語言類型(如zh)和國家/地區類型來限定(如CN)。
- java.util.Locale是創建國際化的基礎類。
- NumberFormat(對數字轉換成特定格式)、DateFormat(對日期輸出為特定格式)、MessageFormat(使用占位符)等是操作國際化的工具類。
- 使用ResourceBundle類處理針對國際化的properties文件(命名規則有限定,如resource_en_US.properties)。
- spring管理國際化定義了MessageSource介面。
- ResourceBundleMessageSource實現了MessageSource介面。
- ReloadableResourceBundleMessageSource實現了MessageSource介面,多了定時更新國際化信息的功能。
- ApplicationContext實現了MessageSource介面,把國際化信息上升到了容器級。
玉不琢,不成器;人不學,不知道。——《禮記·學記》