1.Java中的國際化
國際化(Internationalization)簡稱 i18n,簡單來說就是不同國家/地區/語言的用戶,訪問同一個程序,得到對應的本地化資源。
首先要確定國家/地區/語言(Locale類)
然后根據不同的Locale獲取對應的本地化資源(locale敏感的)。
而本地化資源相關的主要有兩種:ResourceBundle和Format抽象類的子類。
①Jdk為ResourceBundle抽象類提供了兩個子類(ListResourceBundle和PropertyResourceBundle)
當然也可以參考ResourceBundle編寫自定義的子類MyResources和XMLResourceBundle等(源碼注釋部分)。
(FORMAT_DEFAULT默認使用java.class和java.properties兩種格式)其中properties的命名規則basename_language_country.properties。
②Format,相對簡單不再過多描述。
Format子類中關於Local的使用。
2.Spring中的國際化
首先說明Spring中國際化的支持是AbstractApplicationContext中定義的默認bean(ApplicationContext實現了MessageSource接口), private MessageSource messageSource;
而在基於Spring的Web應用中使用我們更多關注的是如何確定Local的問題,而對資源的獲取則更多的是基於配置。
①通過LocaleResolver獲取Local
- 讀取客戶端瀏覽器的默認語言,根據Request Headers中的Accept-language來判斷。
- 客戶端傳參,並基於Session和Cookie的對Local進行管理(例如一些網站的語言切換選項)。
使用RequestContextUtils.getLocale(request)獲取Local;
參考DispatcherServlet的initLocaleResolver()方法,在bean中配置不同的LocaleResolver實現
②通過MessageSource獲取ResoureBundle
- 對與一些簡單的資源,我們可以采用properties中配置
- 在Web應用中,如果資源文件過多,使用properties維護將是個麻煩,可以采用數據庫存儲結合緩存技術實現。
③messageResoure的配置
核心是AbstractApplicationContext中initMessageSource()中涉及的HierarchicalMessageSource接口;
由AbstractBeanFactory中的containsLocalBean(String name)區分為兩類:使用配置的HierarchicalMessageSource實現和DelegatingMessageSource(HierarchicalMessageSource的簡單實現)
而在messageSource配置class時,有兩個常用的HierarchicalMessageSource實現可供選擇:ResourceBundleMessageSource和ReloadableResourceBundleMessageSource
兩者都是利用資源名通過getMessage()接口就可以加載整套的國際化資源文件,唯一區別在於ReloadableResourceBundleMessageSource可以定時刷新資源文件,以便在應用程序不重啟的情況下感知資源文件的變化。很多生產系統都需要長時間持續運行,系統重啟會給運行帶來很大的負面影響,這時通過該實現類就可以解決國際化信息更新的問題。上面的配置中cacheSeconds屬性讓ReloadableResourceBundleMessageSource每5秒鍾刷新一次資源文件(在真實的應用中,刷新周期不能太短,否則頻繁的刷新將帶來性能上的負面影響,一般不建議小於30分鍾)。cacheSeconds默認值為-1表示永不刷新,此時,該實現類的功能就蛻化為ResourceBundleMessageSource的功能。
④簡單的代碼示例
a.在spring配置文件中定義messageSource<bean>
b.定義不同Local的properties文件,命名規則basename_language_country.properties和java中的一致。
c.代碼
ApplicationContext applicationContext=new FileSystemXmlApplicationContext("classpath:spring-config.xml"); String message=applicationContext.getMessage("HelloWorld",new Object[]{"hello",new Date()}, Locale.CHINA);
小結:可以看出使用spring的國際化更加靈活(ReloadableResourceBundleMessageSource的動態讀取),基於MessageFormat的參數化列表,以及中文支持可以設置編碼格式(java中處理相對麻煩)。
3.總結
Java中:重點了解ResoureBundle的使用參考源碼解析圖。
Spring中:重點分兩部分,①通過LocaleResolver獲取Local,②通過通過MessageSource獲取ResoureBundle
Spring的國際化是基於Java(Jdk)國際化的擴展,在Web項目中使用更加靈活。
閱讀Java(其實這里使用Jdk更合適)源碼還能夠捋清思路,Spring源碼閱讀着有些吃力,目前階段只能結合一些博客挑重點部分的源碼進行解讀了。
4.參考資料