激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java國際化簡介_動力節點Java學院整理

Java國際化簡介_動力節點Java學院整理

2020-12-04 09:00stamen Java教程

這篇文章主要為大家簡單介紹了Java國際化的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下

        假設我們正在開發一個支持多國語言的web應用程序,要求系統能夠根據客戶端的系統的語言類型返回對應的界面:英文的操作系統返回英文界面,而中文的操作系統則返回中文界面——這便是典型的i18n國際化問題。對于有國際化要求的應用系統,我們不能簡單地采用硬編碼的方式編寫用戶界面信息、報錯信息等內容,而必須為這些需要國際化的信息進行特殊處理。簡單來說,就是為每種語言提供一套相應的資源文件,并以規范化命名的方式保存在特定的目錄中,由系統自動根據客戶端語言選擇適合的資源文件。

基礎知識

  “國際化信息”也稱為“本地化信息”,一般需要兩個條件才可以確定一個特定類型的本地化信息,它們分別是“語言類型”和“國家/地區的類型”。如中文本地化信息既有中國大陸地區的中文,又有中國臺灣、中國香港地區的中文,還有新加坡地區的中文。java通過java.util.locale類表示一個本地化對象,它允許通過語言參數和國家/地區參數創建一個確定的本地化對象。
  語言參數使用iso標準語言代碼表示,這些代碼是由iso-639標準定義的,每一種語言由兩個小寫字母表示。
  國家/地區參數也由標準的iso國家/地區代碼表示,這些代碼是由iso-3166標準定義的,每個國家/地區由兩個大寫字母表示。     

表5-2給出了一些語言和國家/地區的標準代碼:

Java國際化簡介_動力節點Java學院整理

  java.util.locale是表示語言和國家/地區信息的本地化類,它是創建國際化應用的基礎。下面給出幾個創建本地化對象的示例:

?
1
2
3
4
5
6
7
8
9
10
//①帶有語言和國家/地區信息的本地化對象
locale locale1 = new locale("zh","cn");  
//②只有語言信息的本地化對象
locale locale2 = new locale("zh"); 
//③等同于locale("zh","cn")
locale locale3 = locale.china;  
//④等同于locale("zh")
locale locale4 = locale.chinese;  
//⑤獲取本地系統默認的本地化對象
locale locale 5= locale.getdefault();

  用戶既可以同時指定語言和國家/地區參數定義一個本地化對象①,也可以僅通過語言參數定義一個泛本地化對象②。locale類中通過靜態常量定義了一些常用的本地化對象,③和④處就直接通過引用常量返回本地化對象。此外,用戶還可以獲取系統默認的本地化對象,如⑤所示。
  在測試時,如果希望改變系統默認的本地化設置,可以在啟動jvm時通過命令參數指定:java -duser.language=en -duser.region=us mytest。

本地化工具類

  jdk的java.util包中提供了幾個支持本地化的格式化操作工具類:numberformat、dateformat、messageformat。下面,我們分別通過實例了解它們的用法:
numberformat:

?
1
2
3
4
locale locale = new locale("zh", "cn");
numberformat currfmt = numberformat.getcurrencyinstance(locale);
double amt = 123456.78;
system.out.println(currfmt.format(amt));

  上面的實例通過numberformat按本地化的方式對貨幣金額進行格式化操作,運行實例,輸出以下信息:

¥123,456.78 

代碼清單5-14  dateformat 

?
1
2
3
4
locale locale = new locale("en", "us");
date date = new date();
dateformat df = dateformat.getdateinstance(dateformat.medium, locale);
system.out.println(df.format(date));

  通過dateformat#getdateinstance(int style,locale locale)方法按本地化的方式對日期進行格式化操作。該方法第一個入參為時間樣式,第二個入參為本地化對象。運行以上代碼,輸出以下信息:

jan 8, 2007 

  messageformat在numberformat和dateformat的基礎上提供了強大的占位符字符串的格式化功能,它支持時間、貨幣、數字以及對象屬性的格式化操作。下面的實例演示了一些常見的格式化功能:

代碼清單5-15  messageformat 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//①信息格式化串
string pattern1 = "{0},你好!你于 {1} 在工商銀行存入 {2} 元。";
string pattern2 = "at {1,time,short} on {1,date,long},{0} paid {2,number, currency}.";
 
//②用于動態替換占位符的參數
object[] params = {"john", new gregoriancalendar().gettime(), 1.0e3};
 
//③使用默認本地化對象格式化信息
string msg1 = messageformat.format(pattern1, params);
 
//④使用指定的本地化對象格式化信息
messageformat mf = new messageformat(pattern2, locale.us);
string msg2 = mf.format(params);
system.out.println(msg1);
system.out.println(msg2);

  pattern1是簡單形式的格式化信息串,通過{n}占位符指定動態參數的替換位置索引,{0}表示第一個參數,{1}表示第二個參數,以此類推。
  pattern2格式化信息串比較復雜一些,除參數位置索引外,還指定了參數的類型和樣式。從pattern2中可以看出格式化信息串的語法是很靈活的,一個參數甚至可以出現在兩個地方:如 {1,time,short}表示從第二個入參中獲取時間部分的值,顯示為短樣式時間;而{1,date,long}表示從第二個入參中獲取日期部分的值,顯示為長樣式時間。關于messageformat更詳細的使用方法,請參見jdk的javadoc。
  在②處,定義了用于替換格式化占位符的動態參數,這里,我們使用到了jdk5.0自動裝包的語法,否則必須采用封裝類表示基本類型的參數值。
  在③處,通過messageformat的format()方法格式化信息串。它使用了系統默認的本地化對象,由于我們是中文平臺,因此默認為locale.china。而在④處,我們顯式指定messageformat的本地化對象。
  運行上面的代碼,輸出以下信息:

引用

john,你好!你于 14-7-7 下午11:29 在工商銀行存入 1,000 元。 
at 11:29 pm on july 7, 2014,john paid $1,000.00. 

  如果應用系統中某些信息需要支持國際化功能,則必須為希望支持的不同本地化類型分別提供對應的資源文件,并以規范的方式進行命名。國際化資源文件的命名規范規定資源名稱采用以下的方式進行命名:

引用

  <資源名>_<語言代碼>_<國家/地區代碼>.properties

  其中,語言代碼和國家/地區代碼都是可選的。<資源名>.properties命名的國際化資源文件是默認的資源文件,即某個本地化類型在系統中找不到對應的資源文件,就采用這個默認的資源文件。<資源名>_<語言代碼>.properties命名的國際化資源文件是某一語言默認的資源文件,即某個本地化類型在系統中找不到精確匹配的資源文件,將采用相應語言默認的資源文件。
  舉一個例子:假設資源名為resource,則語言為英文,國家為美國,則與其對應的本地化資源文件命名為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 

  本地化不同的同一資源文件,雖然屬性值各不相同,但屬性名卻是相同的,這樣應用程序就可以通過locale對象和屬性名精確調用到某個具體的屬性值了。

  讀者可能已經注意到,上面中文的本地化資源文件內容采用了特殊的編碼表示中文字符,這是因為資源文件對文件內容有嚴格的要求:只能包含ascii字符。所以必須將非ascii字符的內容轉換為unicode代碼的表示方式。如上面中文的resource_zh_cn.properties資源文件的三個屬性值分別是“您好!”、“早上好!”和“下午好!”三個中文字符串對應的unicode代碼串。

  如果在應用開發時,直接采用unicode代碼編輯資源文件是很不方便的,所以,通常我們直接使用正常的方式編寫資源文件,在測試或部署時再采用工具進行轉換。jdk在bin目錄下為我們提供了一個完成此項功能的native2ascii工具,它可以將中文字符的資源文件轉換為unicode代碼格式的文件,命令格式如下:

引用

native2ascii [-reverse] [-encoding 編碼] [輸入文件 [輸出文件]]

resource_zh_cn.properties包含中文字符并且以utf-8進行編碼,假設將該資源文件放到d:\目錄下,通過下面的命令就可以將其轉換為unicode代碼的形式:

引用

d:\>native2ascii -encoding utf-8 d:\resource_zh_cn.properties 
d:\resource_zh_cn_1.properties 

  由于原資源文件采用utf-8編碼,所以必須顯式通過-encoding指定編碼格式。

引用

  通過native2ascii命令手工轉換資源文件,不但在操作上不方便,轉換后資源文件中的屬性內容由于采用了ascii編碼,閱讀起來也不方便。很多ide開發工具都有屬性編輯器的插件,插件會自動將資源文件內容轉換為ascii形式的編碼,同時以正常的方式閱讀和編輯資源文件的內容,這給開發和維護帶來了很大的便利。對于myeclipse來說,使用myeclipse properties editor編輯資源屬性文件;對于intellij idea來說,無須安裝任何插件就自然支持資源屬性文件的這種編輯方式了。

  如果應用程序中擁有大量的本地化資源文件,直接通過傳統的file操作資源文件顯然太過笨拙。java為我們提供了用于加載本地化資源文件的方便類java.util.resourceboundle。

  resourceboundle為加載及訪問資源文件提供便捷的操作,下面的語句從相對于類路徑的目錄中加載一個名為resource的本地化資源文件:
resourcebundle rb = resourcebundle.getbundle("com/baobaotao/i18n/resource", locale) 

  通過以下的代碼即可訪問資源文件的屬性值:
rb.getstring("greeting.common")  

來看下面的實例:
代碼清單5-16  resourceboundle 

?
1
2
3
4
resourcebundle rb1 = resourcebundle.getbundle("com/baobaotao/i18n/resource", locale.us);
resourcebundle rb2 = resourcebundle.getbundle("com/baobaotao/i18n/resource", locale.china);
system.out.println("us:"+rb1.getstring("greeting.common"));
system.out.println("cn:"+rb2.getstring("greeting.common"));

  rb1加載了對應美國英語本地化的resource_en_us.properties資源文件;而rb2加載了對應中國大陸中文的resource_zh_cn.properties資源文件。運行上面的代碼,將輸出以下信息:

引用

us:how are you! 
cn:你好! 

  加載資源文件時,如果不指定本地化對象,將使用本地系統默認的本地化對象。所以,在中文系統中,resourcebundle.getbundle("com/baobaotao/i18n/resource")語句也將返回和代碼清單5-14中rb2相同的本地化資源。
  resourcebundle在加載資源時,如果指定的本地化資源文件不存在,它按以下順序嘗試加載其他的資源:本地系統默認本地化對象對應的資源→默認的資源。上面的例子中,假設我們使用resourcebundle.getbundle("com/baobaotao/i18n/resource",locale.canada)加載資源,由于不存在resource_en_ca.properties資源文件,它將嘗試加載resource_zh_cn.properties的資源文件,假設resource_zh_cn.properties資源文件也不存在,它將繼續嘗試加載resource.properties的資源文件,如果這些資源都不存在,將拋出java.util.missingresourceexception異常。

在資源文件中使用格式化串

  在上面的資源文件中,屬性值都是一般的字符串,它們不能結合運行時的動態參數構造出靈活的信息,而這種需求是很常見的。要解決這個問題很簡單,只須使用帶占位符的格式化串作為資源文件的屬性值并結合使用messageformat就可以滿足要求了。

  上面的例子中,我們僅向用戶提供一般性問候,下面我們對資源文件進行改造,通過格式化串讓問候語更具個性化:

引用

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} 

  將該資源文件保存在fmt_resource_en_us.properties中,按照同樣的方式編寫對應的中文本地化資源文件fmt_resource_zh_cn.properties。

  下面,我們聯合使用resourceboundle和messageformat得到美國英文的本地化問候語:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//①加載本地化資源
resourcebundle rb1 = 
    resourcebundle.getbundle("com/baobaotao/i18n/fmt_ resource",locale.us); 
resourcebundle rb2 = 
    resourcebundle.getbundle("com/baobaotao/i18n/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);

運行以上的代碼,將輸出以下信息:

引用

how are you!john,today is 1/9/07 4:11 pm 
早上好!john,現在是下午4:11 
下午好!john,現在是2007年1月9日 

messagesource

  spring定義了訪問國際化信息的messagesource接口,并提供了幾個易用的實現類。首先來了解一下該接口的幾個重要方法:

string getmessage(string code, object[] args, string defaultmessage, locale locale)

code表示國際化資源中的屬性名;args用于傳遞格式化串占位符所用的運行期參數;當在資源找不到對應屬性名時,返回defaultmessage參數所指定的默認信息;locale表示本地化對象;

string getmessage(string code, object[] args, locale locale)  throws nosuchmessageexception

與上面的方法類似,只不過在找不到資源中對應的屬性名時,直接拋出nosuchmessageexception異常;

string getmessage(messagesourceresolvable resolvable, locale locale)  throws nosuchmessageexception

messagesourceresolvable 將屬性名、參數數組以及默認信息封裝起來,它的功能和第一個接口方法相同。

messagesource的類結構

  messagesource分別被hierarchicalmessagesource和applicationcontext接口擴展,這里我們主要看一下hierarchicalmessagesource接口的幾個實現類,如圖5-7所示:

Java國際化簡介_動力節點Java學院整理

  hierarchicalmessagesource接口添加了兩個方法,建立父子層級的messagesource結構,類似于前面我們所介紹的hierarchicalbeanfactory。該接口的setparentmessagesource (messagesource parent)方法用于設置父messagesource,而getparentmessagesource()方法用于返回父messagesource。

  hierarchicalmessagesource接口最重要的兩個實現類是resourcebundlemessagesource和reloadableresourcebundlemessagesource。它們基于java的resourcebundle基礎類實現,允許僅通過資源名加載國際化資源。reloadableresourcebundlemessagesource提供了定時刷新功能,允許在不重啟系統的情況下,更新資源的信息。staticmessagesource主要用于程序測試,它允許通過編程的方式提供國際化信息。而delegatingmessagesource是為方便操作父messagesource而提供的代理類。

resourcebundlemessagesource

  該實現類允許用戶通過beanname指定一個資源名(包括類路徑的全限定資源名),或通過beannames指定一組資源名。在前面的代碼清單中,我們通過jdk的基礎類完成了本地化的操作,下面我們使用resourcebundlemessagesource來完成相同的任務。讀者可以比較兩者的使用差別,并體會spring所提供的國際化處理功能所帶給我們的好處:
  通過resourcebundlemessagesource配置資源

?
1
2
3
4
5
6
7
8
9
<bean id="myresource"
class="org.springframework.context.support.resourcebundlemessagesource">
 <!--①通過基名指定資源,相對于類根路徑-->
 <property name="basenames">
  <list>
   <value>com/baobaotao/i18n/fmt_resource</value>
  </list>
 </property>
 </bean>

啟動spring容器,并通過messagesource訪問配置的國際化資源,如下代碼清單所示:

代碼清單5-19 訪問國際化消息:resourcebundlemessagesource:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
string[] configs = {"com/baobaotao/i18n/beans.xml"};
applicationcontext ctx = new classpathxmlapplicationcontext(configs);
 
//①獲取messagesource的bean
messagesource ms = (messagesource)ctx.getbean("myresource"); 
object[] params = {"john", new gregoriancalendar().gettime()};
 
//②獲取格式化的國際化信息
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);

  比較代碼清單中的代碼,我們發現最主要的區別在于我們無須再分別加載不同語言、不同國家/地區的本地化資源文件,僅僅通過資源名就可以加載整套的國際化資源文件。此外,我們無須顯式使用messageformat操作國際化信息,僅通過messagesource# getmessage()方法就可以完成操作了。這段代碼的運行結果與前面的代碼的運行結果完全一樣。

reloadableresourcebundlemessagesource

  前面,我們提到該實現類比之于resourcebundlemessagesource的唯一區別在于它可以定時刷新資源文件,以便在應用程序不重啟的情況下感知資源文件的變化。很多生產系統都需要長時間持續運行,系統重啟會給運行帶來很大的負面影響。這時,通過該實現類就可以解決國際化信息更新的問題。請看下面的配置:

  通過reloadableresourcebundlemessagesource配置資源:

xml代碼

?
1
2
3
4
5
6
7
8
9
10
<bean id="myresource"
lass="org.springframework.context.support.reloadableresourcebundlemessagesource">
 <property name="basenames">
  <list>
  <value>com/baobaotao/i18n/fmt_resource</value>
  </list>
 </property>
 <!--① 刷新資源文件的周期,以秒為單位-->
 <property name="cacheseconds" value="5"/> 
 </bean>

  在上面的配置中,我們通過cacheseconds屬性讓reloadableresourcebundlemessagesource每5秒鐘刷新一次資源文件(在真實的應用中,刷新周期不能太短,否則頻繁的刷新將帶來性能上的負面影響,一般不建議小于30分鐘)。cacheseconds默認值為-1表示永不刷新,此時,該實現類的功能就蛻化為resourcebundlemessagesource的功能。
  我們編寫一個測試類對上面配置的reloadableresourcebundlemessagesource進行測試:

代碼清單5-21  刷新資源:reloadableresourcebundlemessagesource 

?
1
2
3
4
5
6
7
8
9
10
11
string[] configs = {"com/baobaotao/i18n/beans.xml"};
applicationcontext ctx = new classpathxmlapplicationcontext(configs);
 
messagesource ms = (messagesource)ctx.getbean("myresource");
object[] params = {"john", new gregoriancalendar().gettime()};
 
for (int i = 0; i < 2; i++) {
 string str1 = ms.getmessage("greeting.common",params,locale.us); 
 system.out.println(str1);
 thread.currentthread().sleep(20000); //①模擬程序應用,在此期間,我們更改資源文件 
}

  在①處,我們讓程序睡眠20秒鐘,在這期間,我們將fmt_resource_zh_cn.properties資源文件的greeting.common鍵值調整為:

引用

---how are you!{0},today is {1}--- 
  我們將看到兩次輸出的格式化信息分別對應更改前后的內容,也即本地化資源文件的調整被自動生效了:

引用

how are you!john,today is 1/9/07 4:55 pm 
---how are you!john,today is 1/9/07 4:55 pm--- 

容器級的國際化信息資源

  在如圖5-7所示的messagesource類圖結構中,我們發現applicationcontext實現了messagesource的接口。也就是說applicationcontext的實現類本身也是一個messagesource對象。
  將applicationcontext和messagesource整合起來,乍一看挺讓人費解的,spring這樣設計的意圖究竟是什么呢?原來spring認為:在一般情況下,國際化信息資源應該是容器級。我們一般不會將messagesource作為一個bean注入到其他的bean中,相反messagesource作為容器的基礎設施向容器中所有的bean開放。只要我們考察一下國際化信息的實際消費場所就更能理解spring這一設計的用意了。國際化信息一般在系統輸出信息時使用,如spring mvc的頁面標簽,控制器controller等,不同的模塊都可能通過這些組件訪問國際化信息,因此spring就將國際化消息作為容器的公共基礎設施對所有組件開放。
  既然一般情況下我們不會直接通過引用messagesource bean使用國際信息,那如何聲明容器級的國際化信息呢?我們其實在5.1.1節講解spring容器的內部工作機制時已經埋下了伏筆:在介紹容器啟動過程時,我們通過代碼清單5-1對spring容器啟動時的步驟進行剖析,④處的initmessagesource()方法所執行的工作就是初始化容器中的國際化信息資源:它根據反射機制從beandefinitionregistry中找出名稱為“messagesource”且類型為org.springframework.context.messagesource的bean,將這個bean定義的信息資源加載為容器級的國際化信息資源。請看下面的配置:

代碼清單5-22  容器級資源的配置 

?
1
2
3
4
5
6
7
8
9
<!--①注冊資源bean,其bean名稱只能為messagesource -->
<bean id="messagesource"
  class="org.springframework.context.support.resourcebundlemessagesource">
 <property name="basenames">
  <list>
  <value>com/baobaotao/i18n/fmt_resource</value>
  </list>
 </property>
</bean>

  下面,我們通過applicationcontext直接訪問國際化信息,如下代碼清單所示:

代碼清單5-23  通過applicationcontext訪問國際化信息 
java代碼 

?
1
2
3
4
5
6
7
8
9
string[] configs = {"com/baobaotao/i18n/beans.xml"};
applicationcontext ctx = new classpathxmlapplicationcontext(configs);
//①直接通過容器訪問國際化信息
object[] params = {"john", new gregoriancalendar().gettime()};
  
string str1 = ctx.getmessage("greeting.common",params,locale.us);
string str2 = ctx.getmessage("greeting.morning",params,locale.china); 
system.out.println(str1);
system.out.println(str2);

  運行以上代碼,輸出以下信息:

引用

how are you!john,today is 1/9/07 5:24 pm 
早上好!john,現在是下午5:24 

  假設messagesource bean名字沒有命名為“messagesource”,以上代碼將拋出nosuchmessageexception異常。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91看片在线观看视频 | 午夜精品老牛av一区二区三区 | 久久一级 | 国产精品剧情一区二区三区 | 欧美日韩免费在线观看视频 | 日韩中字在线 | 色就操 | 7777视频 | 热99在线视频 | 国产成人综合在线观看 | 中文在线国产 | 欧美综合日韩 | 国产精品久久久乱弄 | 色婷婷a| 国产91九色在线播放 | 91一区二区三区久久久久国产乱 | 免费看性xxx高清视频自由 | 国产精品视频1区 | 白天操夜夜操 | www深夜成人| 亚洲va久久久噜噜噜久久男同 | 中文字幕一区二区三区久久 | 99精品在线免费 | 特一级黄色毛片 | 97香蕉超级碰碰久久免费软件 | 亚州欧美视频 | 92看片淫黄大片一级 | 成人免费一区二区三区在线观看 | 青青草华人在线 | 成码无人av片在线观看网站 | av视在线 | 性猛交ⅹxxx乱巴西 在线播放中文 | 影视免费观看 | 少妇色诱麻豆色哟哟 | 国产69精品久久久久孕妇黑 | 久草在线观看福利 | 国产免费人做人爱午夜视频 | 91精品国产综合久久婷婷香 | 日韩精品二区 | 精品久久久久久久久久久aⅴ | 成人毛片网站 |