熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

I18N-國際化消息和日志

2022-06-13   來源: Java核心技術 

摘要:

    對於許多軟件開發者來說一提到國際化(亦稱為 in)支持就會感到害怕 要使編寫的代碼能夠面向外國使用者確實需要費一翻思量因為在現有軟件的代碼中添加國際化支持可不是一件輕而易舉的事對於許多軟件開發者來說一提到國際化(亦稱為 in)支持就會感到害怕 要使編寫的代碼能夠面向外國使用者確實需要費一翻思量因為在現有軟件的代碼中添加國際化支持可不是一件輕而易舉的事 如果您感覺到軟件需要支持不同語言和語言環境哪怕這種可能性很小從一開始就做國際化項目的准備比起項目開始後再試圖添加國際化支持也要明智得多

    有人問國際化是什麼意思? 國際化遠不止於將用戶界面消息翻譯成不同的語言 它還涉及到處理不同的字符編碼日期/時間/貨幣的顯示形式以及跨多區域時存在的一些其他差異

介紹 inlog

    本文的目的並不在於討論那些關於國際化的瑣碎的方面而是通過研究一個稱為 IN Messages and Logging (簡稱 inlog) 的開源項目來介紹引入國際化功能時需要執行的一些必要的任務
inlog 允許您在 Java 應用程序內集成國際化的消息這是通過向以下內容提供 API 來完成的
+標注 Java 類以識別國際化消息
+從所有支持的語言環境資源包中獲取國際化消息
+創建特定於語言環境的異常並在其中使用國際化的消息
+使用任何日志框架創建國際化消息日志
+自動生成特定於語言環境的資源包
+自動生成幫助及參考文檔

  定義國際化消息

    國際化軟件時一項最為乏味的工作莫過於維護資源綁定包了 資源綁定包是包含 name=value 這種信息對的屬性文件 (properties)其中 name 是資源綁定包的關鍵字字符串 (key string)value 是翻譯過的消息字符串本身 習慣上為每種語言創建一個資源綁定包在每個綁定包中關鍵字的設置是唯一的而各個關鍵字相關的值就要翻譯成各種語言了 資源綁定文件的名稱應該指明它是為哪種語言創建的例如mybundle_enproperties 文件中的消息是用英語寫的而 mybundle_deproperties 包含德語消息

    inlog 提供了一些用於定義資源綁定消息及其關鍵字字符串的標注用於將資源注入到 inlog 的自定義 Ant 任務中您可以自動生成資源綁定包而不必為確保屬性文件與訪問屬性文件的 Java 代碼之間的一致性作過多的工作

    @INMessage 標注被放在常量上這些常量就是資源綁定包的關鍵字字符串使用的常量 使用這些常量可以迫使執行編譯時檢查例如代碼中引入的拼寫錯誤(如常量名稱的拼寫錯誤)和使用過時消息或已刪除消息這些錯誤在編譯時就可以被探測到 以下是使用此標注的示例

java 代碼

          @INMessage( Hello {} You last visited on {date} )  
        public static final String MSG_WELCOME = examplewelcomemsg;  



    上面的示例定義了一條國際化消息 常量的值定義了資源綁定包的關鍵字字符串(key string) 標注的值是一條實際翻譯好的消息 您可以將這些標注過的常量放到應用程序的任何類或接口中 可以將它們放在單獨的類或接口中(將所有消息定義集中到一個地點)也可以放在使用到它們的類中

    @INResourceBundle 標注用於定義存放消息的資源綁定包文件(properties 文件) 它可以標注整個類或接口也可以標注特定的部分 如果您標注了一個類或接口則該類或接口中的所有 @INMessage 標注都將被存儲在該標注定義的資源綁定包中(默認情況下) 如果只將標注放在特定的常量上那麼它就只是那個常量的綁定包 以下是使用此標注的示例

java 代碼

          @INResourceBundle( baseName = messages  
                             defaultLocale = en )  



    以上代碼的意思是所有被 @INMessage 標注的相關消息都將放置在名為 messages_enproperties 綁定包文件中 下面是一個更復雜的示例(包含一系列國際化消息的接口)

java 代碼

          @INResourceBundle( baseName = messages    
                             defaultLocale = en )    
        public interface Messages {    
           @INMessage( Hello {} You last visited on {date} )    
           String MSG_WELCOME = welcomemsg;    
          
           @INMessage( An error occurred please try again )    
           String MSG_ERR = erroroccurred;    
          
           @INMessage( The value is {} )    
           String MSG_VALUE = value;    
        }  



檢索國際化消息

    定義了國際化常量後就可以使用 inlog 的核心類提供的 APImazzinMsg 該 API 用於裝載存放於資源綁定屬性文件中的消息 它還用於將值作為變量參數進行傳遞從而替換消息中的占位符(例如 {} {date}) 另外此 API 將您從直接使用 JDK 類進行編碼的工作中解放出來也許您需要閱讀一下 Javadoc 的 javatextMessageFormat 部分以獲得對 inlog 工作原理的初步認識尤其是它如何使用本地化的數據替換占位符

下面是 Msg 類的使用實例

java 代碼

          // 使用靜態工廠方法創建一個 Msg 對象  
        // 假設默認綁定包的名字是 messages  
        Systemoutprintln( MsgcreateMsg( MessagesMSG_WELCOME  
                                           name  
                                           date ) );  




java 代碼

          // 使用構造函數創建一個 Msg 對象  
        Msg msg = new Msg( new MsgBundleBaseName(messages) );  
        try {  
           String hello = msggetMsg(MessagesMSG_WELCOME name date );  
           do something   
        }  
        catch (Exception e) {  
           throw new RuntimeException( msggetMsg( MessagesMSG_ERR ) );  
        }  

  name 和 date 參數是傳遞一個任意參數列表的示例每個對象代表各個位置上要被替換掉的占位符({} 和 {date} 分別基於前面給出的 MessagesMSG_WELCOME 中的定義)

    Msg 對象會根據綁定包的名稱及其當前的語言環境設置獲知使用哪種語言環境的資源綁定包 綁定包的名稱是綁定包文件的名稱減去語言環境符號和擴展名(在上面的示例中綁定包的名稱是 messages) 您可以通過傳遞到 Msg 的構造函數或者特定的靜態工廠方法的方式來定義 Msg 對象使用的綁定包的名稱如果不進行明確地指定將使用默認的 messages 綁定包的名稱在 Msg 對象的生命周期內將一直存在可以通過調用 Msg 對象的 setLocale() 來切換語言環境(默認語言環境是 JVM 使用的語言環境) 如果您使用了 Msg 對象並且要求根據(被分配了 Msg 對象的)使用者的需要來切換語言環境這將是非常有用的



本地化的異常

    inlog 提供了兩個基本的異常類(分別用於已查看和未查看的異常 LocalizedException 和 LocalizedRuntimeException)可以這兩個類創建自己的本地化異常子類 這些類都具有構造函數其函數簽名與 Msg 類非常相似 在使用構造函數時通過調用資源綁定包的關鍵字和占位符的變量參數列表的方法來指定異常消息同時還可以選擇綁定包的名稱和語言環境 這樣一來異常消息就可以使用本地化的各種語言其原理就是利用了 Msg 可以檢索本地化的消息

創建國際化消息的日志

    inlog 提供了一種方法可以通過該方法記錄國際化的日志信息 日志系統的主類是 mazzinLogger 它提供了 tracedebuginfowarnerror 和 fatal 方法等一些典型的設置 需要指出的是與傳遞一個消息本身組成的字符串不同您為占位符傳遞的是資源綁定包的關鍵字字符串和參數列表 它使用具有保護作用的 mazzinMsg 類來獲取實際的本地化消息

    通過使用工廠類 mazzinLoggerFactory 來獲得 Logger 對象與 logj 等獲得對象的方式基本相同 而不同的是記錄日志消息的方法該方法與通過 mazzinMsg 對象獲取消息非常類似
java 代碼

          public static final mazzinLogger LOG =  
                       mazzinLoggerFactorygetLogger(MyClassclass);  
          
        LOGdebug(MessagesMSG_VALUE value);  
          
        try {  
             
        }  
        catch (Exception e) {  
           LOGwarn(e MessagesMSG_ERR);  
        }  



    如果沒有啟用日志級別則不會查找綁定包也不會執行任何字符串連接這一條件有效地加快了日志調用的速度 如果日志消息與特定的表達式相關聯則需要將表達式的第一個參數傳遞給日志方法 如果啟用了棧傾卸設置這將允許棧跟蹤傾卸消息(請往下看)

    inlog 的日志框架中還添加了許多其他的功能這些功能並非潛在的第三方的日志框架所能媲美 首先要介紹的功能就是可以告訴 Logger 是否傾卸異常的棧跟蹤 您可能需要查看一個特定運行任務的所有異常的棧跟蹤也可能不想看 請注意對於在 FATAL 日志級別上的異常不能禁用此功能使用該方法記錄的致命異常必需允許傾卸棧跟蹤 對於其他的日志級別日志程序只有在系統屬性 inlogdumpstacktraces 設置為 true (或者在代碼中調用 LoggersetDumpStackTraces(true))的時候才會傾洩棧跟蹤

    inlog 日志框架附加的第二項功能是在記錄與一個消息關聯的資源綁定包關鍵字的同時記錄消息本身 資源綁定包關鍵字對於所有語言環境都是相同的也就是說無論消息是用何種語言寫成的關鍵字是不變的 可以把這些關鍵字想象成消息的 ID錯誤的代碼 這在生成涉及到這些代碼的幫助文檔時非常有用用戶將可以參考文檔中的額外幫助文本以得知到底要傳遞什麼消息(關於如何生成這種文檔請查看下文) 在默認情況下此功能處於啟用狀態要禁用此功能只需將系統屬性 inlogdumpkeys 設置為 false 或者在代碼中調用 LoggersetDumpLogKeys(false)

    提供消息 ID避免在已禁用日志級別上拼接字符串這些 inlog 提供的日志機制也許已經足夠了 也許有人會爭論說將(除用戶界面消息以外的)日志消息國際化是一種負擔而且也沒有必要 我有時也感到很難說服這種觀點 如果項目沒有這種需求您當然不必使用國際化日志 即使不使用 inlog 提供的日志功能還可以使用它提供的其他功能嘛

    但是我還是可以舉出一些具體的例子來證明使用國際化消息的好處 請注意inlog 允許定義一個不同的語言環境供日志程序使用(日志語言環境)該語言環境區別於 Msg 實例使用的語言環境 這就可以幫助使用我的開發團隊的語言來記錄日志消息而我的用戶界面使用用戶可以閱讀的語言(可能與開發團隊使用的語言不同) 例如我的用戶說德語而軟件是由說法語的法國團隊開發的 在這種情況下德國用戶碰到一個問題時就可以正常地給法國開發團隊發送日志軟件可以默認地將語言環境設置為 LocaleFRENCH 另一方面如果德國用戶希望自行調試問題法語的日志消息根本不會有任何幫助 在這種情況下德國用戶簡單地通過設置系統屬性將日志消息記錄為德語 關於如何切換日志語言環境的信息請參考 mazzinLoggerLocale Javadoc

自動生成資源綁定包

    inlog 提供了一個 Ant 任務用於自動生成資源綁定包屬性文件以避免開發者擔負手動向屬性文件中添加消息清理過時消息的任務

    該 Ant 任務將掃描類以查找 @IN 標注並根據這些標注為您創建資源綁定包 這意味著無論添加多少 @INMessage 標注字段它們都將被加入到資源綁定包中 如果您刪除了一個國際化消息常量則該消息也將從 Ant 任務生成的資源綁定包結果中刪除 要運行該 Ant 任務需要在 Ant 腳本中添加以下類似代碼

xml 代碼

          <taskdef name=in  
                 classpat  
                 classname=mazzinantINAntTask />  
          
        <in outputdir=${classesdir} verify=true verbose=true>  
        <classpath refid=myclasspath />  
           <classfileset dir=${classesdir}/>  
        in>  



    必需讓 Ant 任務知道含有國際化標注類及其依賴關系的類的類路徑 還必須給出類文件集 其中包含文件集的文件列表供掃描國際化標注之用 建議您在第一次運行 Ant 任務的時候采用冗長模式以便知道 Ant 任務的執行內容 一旦得到了想要的效果再將冗長模式關閉 執行此任務之後資源綁定包屬性文件將出現在指定的輸出目錄中

生成幫助文檔

    使用此 Ant 任務的另一個可選功能是生成幫助文檔該文檔是由所有對資源綁定包關鍵字名稱及其消息值的引用組成的另外還包含了對這些消息的描述 這是一個可在 @INMessage 標注中指定的可選屬性help 屬性 屬性值可以是深入描述消息的任何字符串 可以將文檔想象成在特定情況下將傳遞的具體消息 自動生成的幫助文檔可以提供消息關鍵字消息本身以及消息描述之間的交叉引用

java 代碼

          @INMessage( value=The value is {}  
                      help=This will show you the value of your  
                          + current counter If this value is over  
                          + you should reset it)  
        String MSG_VALUE = value;  
          
        @INMessage( value=Memory has {} free bytes left  
                      help=The VM is very low on memory Increase Xmx  
        String MSG_LOW_MEM = lowmemory;  



    大多數情況下您可以將其作為消息的 ID或者錯誤的代碼列表使用可以將其中的資源綁定包關鍵字當成一個消息 ID或者錯誤的代碼 要生成幫助文檔需要在 任務中使用 內部標記

xml 代碼

          <in outputdir=${classesdir}>  
        <classpath refid=myclasspath />  
           <classfileset dir=${classesdir}/>  
           <helpdoc outputdir=${docdir}/help/>  
        in>  

  對於每個生成的資源綁定包都可以在 <helpdoc> 中指定的目錄下找到一個相應的幫助文檔 文檔是根據用於描述文檔樣式的模板生成的 默認情況下模板是一個簡單的 HTML 頁使用 <table> 標記消息代碼而輸出就是幫助文檔 在 <helpdoc> 標記中還可以指定一些其他的屬性來自定義一個模板以滿足自行定制幫助文檔外觀的需求 有關更多信息請查閱 mazzinantHelpdoc 類的 Javadoc

    在幫助文檔的生成結束之後您就可以得到一個(或一些)包含消息關鍵字代碼消息內容及任何 help 屬性定義內容的文檔了

本地化

  我們已經討論了許多關於如何通過獲取翻譯的消息和本地化的消息國際化軟件的內容 嵌入國際化功能之後剩下的工作就是手動處理那些需要被本地化的資源綁定屬性文件(由 <in> Ant 任務生成或者自行手動編寫)了 必須確保將所有資源綁定包的消息翻譯成需要支持的語言而且這些消息包含的數據也進行相應的本地化 通過定義占位符屬性(例如{date} 將使用目標語言環境的格式和語言輸出日期字符串)可以完成許多本地化方面的工作 不言而喻的是必須找一家優秀的翻譯和本地化公司

  小結

    這篇文章介紹了如何通過一個新的開源項目 inlog 在應用程序中溶入國際化功能 使用該開源項目提供的工具和 API 可以自動管理資源綁定包屬性文件(properties)檢索和管理這些綁定包中的本地化消息甚至還可以生成供最終用戶使用的幫助文檔


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26737.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.