<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Terry.Li-彬

    虛其心,可解天下之問;專其心,可治天下之學;靜其心,可悟天下之理;恒其心,可成天下之業。

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks

    Java國際化——資源包的使用


    本文是由JR主持寫作的《J2SE進階》一書的部分章節整理而成,《J2SE進階》正在寫作、完善階段。您閱讀后,有任何建議、批評,請和我聯系,或在http://www.javaresearch.org/forum/thread.jsp?column=376&thread=7576' target='_blank' class='l2'>這兒留言。《J2SE進階》寫作項目組感謝您閱讀本文。

    在當今這個信息社會,尤其是隨著互聯網的出現和普及,人們之間的距離比以往任何時候都更加接近,同時交往也更加頻繁,時下最時髦的概念就是地球村,而我小時候只知道我出生的那個小鄉村。距離近,交往頻繁,人們就不得不考慮如何去與各個不同種族、不同區域的人們打交道。對人如此,對我們的軟件亦是如此,你需要考慮如何讓處于世界不同地方的使用者都能夠很好地使用你的軟件。于是,在每個軟件開始之前,編寫者都可能需要考慮這樣一個問題——國際化。

    我們知道,在Java中可以通過java.util.Locale類來唯一地確定特定語言和國家的組合,即抽象最終用戶的使用環境。同時將用戶相關的一些信息置于資源包中,通過資源包來動態地獲得最終的用戶顯示。資源包可以由資源文件或者資源子類來具體實現。

    注意:本文只打算討論國際化過程中資源包的使用技巧,更多更精彩的內容,請期待《J2SE進階》一書。


    資源包


    在編寫應用程序的時候,需要面對的一個問題是如何來處理與locale相關的一些信息。比如,頁面上的一些靜態文本就希望能夠以用戶習慣的語言顯示。最原始的做法是將這些信息硬編碼到程序中(可能是一大串判斷語句),但是這樣就將程序代碼和易變的locale信息捆綁在一起,以后如果需要修改locale信息或者添加其它的locale信息,你就不得不重新修改代碼。而資源包可以幫助你解決這個問題,它通過將可變的locale信息放入資源包中來達到兩者分離的目的。應用程序可以自動地通過當前的locale設置到相應的資源包中取得所要的信息。資源包的概念類似于Windows編程人員使用的資源文件(rc文件)。

    一般來說,資源包需要完成兩個功能:和具體的locale進行綁定以及讀取locale相關信息。

    ResourceBundle類

    你可以把資源包看作為一個由許多成員(子類)組成的大家庭,其中每個成員關聯到不同的locale對象,那它是如何完成關聯功能的呢?

    資源包中的每個成員共享一個被稱作基名(base name)的名稱,然后在此基礎上根據一定的命名規范進行擴展。下面就列出了一些成員的名稱:
        LabelResources
             LabelResources_de
             LabelResources_de_CH
             LabelResources_de_CH_UNIX
    可見這些子類依據這樣的命名規范:baseName_language_country_variant,其中language等幾個變量就是你在構造Locale類時所使用的。而資源包正是通過這個符合命名規范的名稱來和locale進行關聯的,比如LabelResource_de_CH就對應于由德語(de)和瑞士(CH)組成的locale對象。

    當你的應用程序需要查找特定locale對象關聯的資源包時,它可以調用ResourceBundle的getBundle方法,并將locale對象作為參數傳入。
    1. Locale currentLocale = new Locale("de""CH""UNIX");
    2. ResourceBundle myResources =
    3.       ResourceBundle.getBundle("LabelResources", currentLocale);

    如果該locale對象匹配的資源包子類找不到,getBundle將試著查找最匹配的一個子類。具體的查找策略是這樣的:getBundle使用基名,locale對象和缺省的locale來生成一個候選資源包名稱序列。如果特定locale對象的語言代碼、國家代碼和可選變量都是空值,則基名是唯一的候選資源包名稱。否則的話,具體locale對象(language1,country1和variant1)和缺省locale(language2,country2和variant2)將產生如下的序列:

    • baseName + "_" + language1 + "_" + country1 + "_" + variant1
    • baseName + "_" + language1 + "_" + country1 
    • baseName + "_" + language1 
    • baseName + "_" + language2 + "_" + country2 + "_" + variant2 
    • baseName + "_" + language2 + "_" + country2 
    • baseName + "_" + language2 
    • baseName 

    然后,getBundle方法按照產生的序列依次查找匹配的資源包子類并對結果子類初始化。首先,它將尋找類名匹配候選資源包名稱的類,如果找到將創建該類的一個實例,我們稱之為結果資源包。否則,getBundle方法將尋找對應的資源文件,它通過候選資源包名稱來獲得資源文件的完整路徑(將其中的“.”替換為“/”,并加上“.properties”后綴),如果找到匹配文件,getBundle方法將利用該資源文件來創建一個PropertyResourceBundle實例,也就是最終的結果資源包。與此同時,getBundle方法會將這些資源包實例緩存起來供以后使用。

    如果沒有找到結果資源包,該方法將拋出MissingResourceException異常。所以為了防止異常的拋出,一般來說都需要至少實現一個基名資源包子類。

    注意:基名參數必須是一個完整的類名稱(比如LabelResources,resource.LabelResources等),就相當于你引用一個類時需要指定完整的類路徑。但是,為了和以前的版本保持兼容,在使用PropertyResourceBundles時也允許使用“/”來代替“.”表示路徑。

    比如你有以下這些資源類和資源文件:MyResources.class, MyResources_fr_CH.properties, MyResources_fr_CH.class, MyResources_fr.properties, MyResources_en.properties, MyResources_es_ES.class。你利用以下的locale設置來調用getBundle方法,你將會得到不同的結果資源包(假設缺省locale為Locale(“en”, “UK”)),請參考表13.4。
           表13.4 locale設置與結果資源包
    locale設置        結果資源包
    Locale("fr", "CH")    MyResources_fr_CH.class
    Locale("fr", "FR")        MyResources_fr.properties
    Locale("de", "DE")        MyResources_en.properties
    Locale("en", "US")        MyResources_en.properties
    Locale("es", "ES")        MyResources_es_ES.class

    創建了具體的資源包子類實例以后,就需要獲得具體的信息。信息在資源包中是以鍵值對的方式存儲的,表13.5列出的是LabelResources.properties文件的內容。

    表13.5 LabelResources.properties
    1. # This is LabelResources.properties file
    2. greetings = 您好!
    3. farewell = 再見。
    4. inquiry = 您好嗎?

    其中等號左邊的字符串表示主鍵,它們是唯一的。為了獲得主鍵對應的值,你可以調用ResourceBundle類的getString方法,并將主鍵作為參數。此外,文件中以“#”號開頭的行表示注釋行。

    ListResourceBundle和PropertyResourceBundle子類

    抽象類ResourceBundle具有兩個子類:ListResourceBundle和PropertyResourceBundle,它們表示資源包子類兩種不同的實現方式。

    PropertyResourceBundle是和資源文件配對使用的,一個屬性文件就是一個普通的文本文件,你只需要為不同的locale設置編寫不同名稱的資源文件。但是,在資源文件中只能包含字符串,如果需要存儲其它類型對象,你可以使用ListResourceBundle。

    ListResourceBundle是將鍵值對信息保存在類中的列表中,而且你必須實現ListResourceBundle的具體子類。

    如果ListResourceBundle和PropertyResourceBundle不能夠滿足你的需要,你可以實現自己的ResourceBundle子類,你的子類必須覆蓋兩個方法:handleGetObject和getKeys。

    使用資源文件

    使用資源包最簡單的方法就是利用資源文件,利用資源文件一般需要以下幾個步驟:
    1、創建一個缺省的資源文件
    為了防止找不到資源文件,你最好實現一個缺省的資源文件,該文件的名稱為資源包的基名加上.properties后綴。
    2、創建所需的資源文件
    為你準備支持的locale設置編寫對應的資源文件。
    3、設置locale
    你必須在程序中的某個地方提供locale的設置或者切換功能,或者將其放入配置文件中。
    4、根據locale設置創建資源包
    ResourceBundle resource =
            ResourceBundle.getBundle("LabelBundle",currentLocale);
    5、通過資源包獲取locale相關信息
    String value = resource.getString("welcome");

    注意:在使用基名的時候,特別要注意給出完整的類名(或者路徑名),比如你的應用程序所在的類包為org.javaresearch.j2seimproved.i18n,而你的資源文件在你的應用程序下的resource子目錄中,那你的基名就應該是org.javaresearch.j2seimproved.i18n.resource.LabelBundleBundle而不是resource.LabelBundleBundle。


    使用ListResourceBundle

    使用ListResourceBundle和使用資源文件的步驟基本上一樣,只不過你需要用ListResourceBundle子類來替換相應的資源文件。比如你的應用程序的基名是LabelBundle,而且準備支持Locale("en","US")和Locale("zh","CN"),那你需要提供以下幾個Java文件,注意類名和locale的對應關系。
    LabelBundle_en_US.java
    LabelBundle_zh_CN.java
    LabelBundle.java(缺省類)

    代碼13.3列出的是LabelBundle_zh_CN.java的源代碼,相對于資源文件中“key = value”的寫法,在此文件中你首先利用鍵值對來初始化一個二維數組,并在getContents方法中返回該數組。
          
    代碼13.3:LabelBundle_zh_CN.java
    1. package org.javaresearch.j2seimproved.i18n;import 
    2. java.util.ListResourceBundle;
    3. public class LabelBundle_zh_CN extends ListResourceBundle {   
    4.   public Object[][] getContents() {     
    5.     return contents;   
    6.   }   
    7.   private Object[][] contents = {      
    8.     {"title""稱謂"},      
    9.     {"surname""姓"},      
    10.     {"firstname""名"},   
    11.   };
    12. }


    創建完資源類以后,同樣需要設置locale以及根據locale來創建資源包。在通過資源包獲取具體值的時候,你不能再使用getString方法,而應該調用getObject方法,而且由于getObject方法返回一個Object對象,你還需要進行正確的類型轉換。其實,為了你的程序通用性,我們建議在使用資源文件的時候你也應該調用getObject方法,而不是getString方法。
    1.     String title = (String)resource.getObject("title");

    關于ListResourceBundle的詳細使用,可以參考本書所附代碼中國際化一節的ListResourceBundleSample.java程序。

    MessageFormat類

    上面我們講到利用資源文件來分離代碼和可變的信息。但是在實際過程中,有些信息并不能夠完全事先定義好,其中可能會用到運行時的一些結果,最典型例子的就是錯誤提示代碼,比如提示某個輸入必須在一定范圍內。利用上面所講的資源文件并不能夠很好地解決這個問題,所以Java中引入了MessageFormat類。

    MessageFormat提供一種語言無關的方式來組裝消息,它允許你在運行時刻用指定的參數來替換掉消息字符串中的一部分。你可以為MessageFormat定義一個模式,在其中你可以用占位符來表示變化的部分,比如你有這樣一句話:

    您好,peachpi!歡迎來到Java研究組織網站!當前時間是:2003-8-1 16:43:12。

    其中斜體帶下劃線的部分為可變化的,你需要根據當前時間和不同的登錄用戶來決定最終的顯示。我們用占位符來表示這些變化的部分,可以得到下面這個模式:

    您好,{0}!歡迎來到Java研究組織網站!當前時間是:{1,date} {1,time}。

    占位符的格式為{ ArgumentIndex , FormatType , FormatStyle },詳細說明可以參考MessageFormat的API說明文檔。這里我們定義了兩個占位符,其中的數字對應于傳入的參數數組中的索引,{0}占位符被第一個參數替換,{1}占位符被第二個參數替換,依此類推。
    最多可以設置10個占位符,而且每個占位符可以重復出現多次,而且格式可以不同,比如{1,date}和{1,time}。而通過將這些模式定義放到不同的資源文件中,就能夠根據不同的locale設置,得到不同的模式定義,并用參數動態替換占位符。

    下面我們就以MessageFormatSample.java程序(源文件見本書所附代碼)為例,來詳細說明其中的每個步驟。
    1、找出可變的部分,并據此定義模式,將模式放入不同的資源文件中。
    比如針對上面的模式,定義了下面兩個資源文件:
    MessagesBundle_en_US.properties
    Welcome = Hi, {0}! Welcome to Java Research Organization!
    MessagesBundle_zh_CN.properties
    Welcome = 您好,{0}!歡迎來到Java研究組織網站!

    2、創建MessageFormat對象,并設置其locale屬性。
    1.       MessageFormat formatter = new MessageFormat("");
    2.       formatter.setLocale(currentLocale);

    3、從資源包中得到模式定義,以及設置參數。
    1. messages =     ResourceBundle.getBundle(
    2.   "org.javaresearch.j2seimproved.i18n.resource.MessagesBundle",currentLocale);
    3. Object[] testArgs = {"peachpi",new Date()};

    4、利用模式定義和參數進行格式化。
    1.       System.out.println(formatter.format(messages.getString("welcome"),testArgs));


    關于資源包的組織

    一般來說,你是按照資源的用途來組織資源包的,比如會把所有的頁面按鈕的信息放入一個名為ButtonResources的資源包中。在實際的應用過程中,以下幾個原則可以幫你決定如何組織資源包:
    1、要易于維護。
    2、最好不要將所有的信息都放入一個資源包中,因為這樣資源包載入內存時將會很耗時。
    3、最好將一個大的資源包分為幾個小的資源包,這樣可以在使用的時候才導入必須的資源,減少內存消耗。
    posted on 2008-06-14 11:01 禮物 閱讀(5042) 評論(0)  編輯  收藏 所屬分類: javaJspstruts2.0
    主站蜘蛛池模板: 日本高清免费不卡在线| 成年免费大片黄在线观看岛国| 国产一区视频在线免费观看| 亚洲国产日韩综合久久精品| 在线观看免费为成年视频| 亚洲乱亚洲乱妇24p| 在线免费观看韩国a视频| 麻豆安全免费网址入口| 亚洲Av无码乱码在线播放| jizz18免费视频| 久久久亚洲精品视频| 18女人水真多免费高清毛片| 亚洲一区二区三区久久久久| 成年女人男人免费视频播放| 久久精品国产亚洲av瑜伽| 亚洲午夜精品一级在线播放放| 中文字幕免费在线观看动作大片| 亚洲av伊人久久综合密臀性色 | 美女视频黄的全免费视频网站| 亚洲国产美女精品久久| 成人黄软件网18免费下载成人黄18免费视频 | 亚洲AV无码资源在线观看| 免费v片在线观看无遮挡| 黄床大片免费30分钟国产精品| 亚洲爆乳精品无码一区二区三区| 国产在线一区二区综合免费视频| 亚洲第一页在线播放| 免费观看的a级毛片的网站| japanese色国产在线看免费| 亚洲国产精品久久久久婷婷软件 | 免费又黄又爽又猛大片午夜| 亚洲欧洲日产国码无码网站| 亚洲人成免费网站| 精品在线免费视频| 夜夜亚洲天天久久| 国产真人无遮挡作爱免费视频| 东方aⅴ免费观看久久av| 亚洲日本在线电影| 国产AV无码专区亚洲Av| 99视频在线精品免费观看6| 国产又黄又爽胸又大免费视频|