il8n國際化java
支持多國語言的web應用,根據客戶端系統的語言類型返回對應的界面web
方案spring
爲每種語言提供一套相應的資源文件,並以規範化命名的方式保存在特定的目錄中,由系統自動根據客戶端語言選擇適合的資源文件返回ide
JDK對國際化的支持工具
一、國際化信息,也稱爲本地化信息,通常須要兩個條件能夠肯定,即語言類型和國家/地區類型。java經過java.util.Locale類表示一個本地化對象spa
@Test public void testLocale() { // 語言參數和國家/地區參數都使用ISO標準語言代碼表示,每種語言由兩位小寫字母表示,每一個國家/地區由兩個大寫字母表示 Locale locale = new Locale("zh", "CN"); } @Test public void testLocale1() { Locale locale = Locale.getDefault(); System.out.println(locale); // zh_CN }
二、java.util包中還提供了幾個支持本地化工具類,如NumberFormat、DateFormat、MessageFormat3d
@Test public void numberFormat() { double amt = 123456.78; Locale locale = new Locale("zh", "CN"); NumberFormat currFmt = NumberFormat.getCurrencyInstance(locale); System.out.println(currFmt.format(amt)); // ¥123,456.78 } @Test public void dateFormat() { Date date = new Date(); Locale locale = new Locale("en", "US"); DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); // 第一個參數是時間樣式 System.out.println(df.format(date)); // Jan 17, 2019 } @Test public void messageFormat1() { // 如下兩行是不一樣本地化的資源,{n}是佔位符 String pattern1 = "{0},你好!你於{1}在工商銀行存入{2} 元。"; String pattern2 = "At {1,time,short} On {1,date,long},{0} paid {2,number,currency}.";// short表示獲取時分秒部分,long獲取日期部分 // 將要替換的變量 Object[] params = {"John", new GregorianCalendar().getTime(),1.0E3}; // 中國格式 String msg1 = MessageFormat.format(pattern1,params); System.out.println(msg1); // John,你好!你於19-1-17 上午11:56在工商銀行存入1,000 元。 // 美國格式 MessageFormat mf = new MessageFormat(pattern2, Locale.US); String msg2 = mf.format(params); System.out.println(msg2); // At 11:56 AM On January 17, 2019,John paid $1,000.00. }
國際化資源的命名規範code
國際化資源的命名規範:資源名_語言代碼_國家/地區代碼.properties;資源名.properties是默認的資源文件,即系統按照命名規範在系統中找不到對應的文件時就使用默認的資源文件;資源名_語言代碼.properties是某一語言的默認資源文件
示例:my_zh_CN.properties、my_en_US.propertiesorm
JDK ResourceBoundle 加載國際化資源xml
若是應用中有大量的本地化資源文件,直接經過File操做太笨拙。java提供了專門用於加載本地化資源文件的java.util.ResourceBoundle
一、資源文件
greeting.common=How are you! greeting.morning = Good morning! greeting.afternoon = Good Afternoon!
greeting.common=How are you! greeting.morning = Good morning! greeting.afternoon = Good Afternoon!
greeting.common=\u60a8\u597d\uff01 greeting.morning=\u65e9\u4e0a\u597d\uff01 greeting.afternoon=\u4e0b\u5348\u597d\uff01
greeting.common=How are you! {0},today is {1} greeting.morning = Good morning! {0},now is {1,time,short} greeting.afternoon = Good Afternoon! {0} now is {1,date,long}
greeting.common=How are you! {0},today is {1} greeting.morning = Good morning! {0},now is {1,time,short} greeting.afternoon = Good Afternoon! {0}, now is {1,date,long}
greeting.common=\u60a8\u597d\uff01 {0}\uff0c\u4eca\u5929\u662f {1} greeting.morning=\u65e9\u4e0a\u597d\uff01 {0}\uff0c\u73b0\u5728\u662f{1,time,short} greeting.afternoon=\u4e0b\u5348\u597d\uff01 {0}\uff0c\u73b0\u5728\u662f{1,date,long}
二、程序
@Test public void resourceBoundle(){ // 若是不指定本地化對象,將使用本地系統默認的本地化對象。 ResourceBundle rb1 = ResourceBundle.getBundle("resource",Locale.US); ResourceBundle rb2 = ResourceBundle.getBundle("resource",Locale.CANADA); System.out.println("us:"+rb1.getString("greeting.common")); // us:How are you! System.out.println("cn:"+rb2.getString("greeting.common")); // cn:您好! } @Test // 在資源文件中使用佔位符 public void resourceBoundleFmt(){ ResourceBundle rb1 = ResourceBundle.getBundle("fmt_resource",Locale.US); ResourceBundle rb2 = ResourceBundle.getBundle("fmt_resource",Locale.CHINA); Object[] params = {"John", new GregorianCalendar().getTime()}; String str1 = new MessageFormat(rb1.getString("greeting.common"),Locale.US).format(params); String str2 =new MessageFormat(rb2.getString("greeting.morning"),Locale.CHINA).format(params); String str3 =new MessageFormat(rb2.getString("greeting.afternoon"),Locale.CHINA).format(params); System.out.println(str1); System.out.println(str2); System.out.println(str3); }
Spring的MessageSource接口
Spring定義了訪問國際化信息的MessageSource接口,MessageSource接口被HierarchicalMessageSource、ApplicationContext這兩個接口擴展。
HierarchicalMessageSource添加了兩個方法,setParentMessageSource()和getParentMessageSource(),用來設置父子層級的MessageSource。
HierarchicalMessageSource最重要的兩個實現類是ResourceBundleMessageSource、ReloadableResourceBundleMessageSource,它們基於java的ResourceBundle實現。ReloadableResourceBundleMessageSource提供了定時刷新功能,在不重啓系統的狀況下能夠更新資源。
ApplicationContext也實現了MessageSource接口,在AbstractApplicationContext的refresh()方法中調用initMessageSource()就是初始化容器中的國際化信息資源,它根據反射機制從BeanDefinitionRegistry中找出名爲messageSource且類型爲org.springframework.context.MessageSource的bean,並將這個bean定義的信息資源加載爲容器級的國際化信息資源,假設bean沒有被命名爲messageSource,會拋出異常。
資源文件使用上面的properties文件
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myResource" class="org.springframework.context.support.ResourceBundleMessageSource"> <!-- basenames要寫死,父類源碼裏有這個屬性 --> <property name="basenames"> <list> <value>fmt_resource</value> </list> </property> </bean> </beans>
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myResource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- basenames要寫死,父類源碼裏有這個屬性 --> <property name="basenames"> <list> <value>fmt_resource</value> </list> </property> <property name="cacheSeconds" value="5"/> </bean> </beans>
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- id的值messageSource是寫死的,默認爲找它 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- basenames要寫死,父類源碼裏有這個屬性 --> <property name="basenames"> <list> <value>fmt_resource</value> </list> </property> </bean> </beans>
@Test public void TestResourceBundleMessageSource() throws InterruptedException { //ApplicationContext context = new ClassPathXmlApplicationContext("xml/my.xml"); ApplicationContext context = new ClassPathXmlApplicationContext("xml/my2.xml"); MessageSource messageSource = context.getBean("myResource", MessageSource.class); // 數據 Object[] params = {"John", new GregorianCalendar().getTime()}; // 獲得了最終的字符串 String message1 = messageSource.getMessage("greeting.common", params, Locale.US); String message2 = messageSource.getMessage("greeting.morning", params, Locale.CHINA); String message3 = messageSource.getMessage("greeting.afternoon", params, Locale.CHINA); System.out.println(message1); System.out.println(message2); System.out.println(message3); } @Test public void TestApplication() throws InterruptedException { ApplicationContext context = new ClassPathXmlApplicationContext("xml/my3.xml"); // 下面這行代碼是能夠省略的,由於默認加載messageSource的bean;固然不省略也能夠 //MessageSource messageSource = context.getBean("messageSource", MessageSource.class); // 數據 Object[] params = {"John", new GregorianCalendar().getTime()}; // 獲得了最終的字符串 String message1 = context.getMessage("greeting.common", params, Locale.US); String message2 = context.getMessage("greeting.morning", params, Locale.CHINA); String message3 = context.getMessage("greeting.afternoon", params, Locale.CHINA); System.out.println(message1); System.out.println(message2); System.out.println(message3); }
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.16.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.16.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.16.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.14.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>