摘要:
對於許多軟件開發者來說
一提到國際化(亦稱為 i
n)支持就會感到害怕
要使編寫的代碼能夠面向外國使用者
確實需要費一翻思量
因為在現有軟件的代碼中添加國際化支持可不是一件輕而易舉的事
對於許多軟件開發者來說
一提到國際化(亦稱為 i
n)支持就會感到害怕
要使編寫的代碼能夠面向外國使用者
確實需要費一翻思量
因為在現有軟件的代碼中添加國際化支持可不是一件輕而易舉的事
如果您感覺到軟件需要支持不同語言和語言環境
哪怕這種可能性很小
從一開始就做國際化項目的准備
比起項目開始後再試圖添加國際化支持也要明智得多
有人問
國際化
是什麼意思? 國際化遠不止於將用戶界面消息翻譯成不同的語言
它還涉及到處理不同的字符編碼
日期/時間/貨幣的顯示形式
以及跨多區域時存在的一些其他差異
介紹 inlog 本文的目的並不在於討論那些關於國際化的瑣碎的方面
而是通過研究一個稱為
I
N Messages and Logging
(簡稱 i
nlog) 的開源項目
來介紹引入國際化功能時需要執行的一些必要的任務
i
nlog 允許您在 Java 應用程序內集成國際化的消息
這是通過向以下內容提供 API 來完成的
+標注 Java 類以識別國際化消息
+從所有支持的語言環境資源包中獲取國際化消息
+創建特定於語言環境的異常
並在其中使用國際化的消息
+使用任何日志框架創建國際化消息日志
+自動生成特定於語言環境的資源包
+自動生成幫助及參考文檔
定義國際化消息 國際化軟件時一項最為乏味的工作莫過於維護資源綁定包了
資源綁定包是包含
name=value
這種信息對的屬性文件 (
properties)
其中
name
是資源綁定包的關鍵字字符串 (key string)
而
value
是翻譯過的消息字符串本身
習慣上為每種語言創建一個資源綁定包
在每個綁定包中關鍵字的設置是唯一的
而各個關鍵字相關的值就要翻譯成各種語言了
資源綁定文件的名稱應該指明它是為哪種語言創建的
例如
mybundle_en
properties 文件中的消息是用英語寫的
而 mybundle_de
properties 包含德語消息
i
nlog 提供了一些用於定義資源綁定消息及其關鍵字字符串的標注
用於將資源注入到 i
nlog 的自定義 Ant 任務中
您可以自動生成資源綁定包
而不必為確保屬性文件與訪問屬性文件的 Java 代碼之間的一致性作過多的工作
@I
NMessage 標注被放在常量上
這些常量就是資源綁定包的關鍵字字符串使用的常量
使用這些常量可以迫使執行編譯時檢查
例如代碼中引入的拼寫錯誤(如常量名稱的拼寫錯誤)和使用過時消息或已刪除消息
這些錯誤在編譯時就可以被探測到
以下是使用此標注的示例
java 代碼
@INMessage( Hello {} You last visited on {date} )
public static final String MSG_WELCOME = examplewelcomemsg;
上面的示例定義了一條國際化消息
常量的值定義了資源綁定包的關鍵字字符串(key string)
標注的值是一條實際翻譯好的消息
您可以將這些標注過的常量放到應用程序的任何類或接口中
可以將它們放在單獨的類或接口中(將所有消息定義集中到一個地點)
也可以放在使用到它們的類中
@I
NResourceBundle 標注用於定義存放消息的資源綁定包文件(
properties 文件)
它可以標注整個類或接口
也可以標注特定的部分
如果您標注了一個類或接口
則該類或接口中的所有 @I
NMessage 標注都將被存儲在該標注定義的資源綁定包中(默認情況下)
如果只將標注放在特定的常量上
那麼它就只是那個常量的綁定包
以下是使用此標注的示例
java 代碼
@INResourceBundle( baseName = messages
defaultLocale = en )
以上代碼的意思是
所有被 @I
NMessage 標注的相關消息都將放置在名為 messages_en
properties 綁定包文件中
下面是一個更復雜的示例(包含一系列國際化消息的接口)
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;
}
檢索國際化消息 定義了國際化常量後
就可以使用 i
nlog 的核心類提供的 API
mazz
i
n
Msg
該 API 用於裝載存放於資源綁定屬性文件中的消息
它還用於將值作為變量參數進行傳遞
從而替換消息中的占位符(例如
{
}
{
date})
另外
此 API 將您從直接使用 JDK 類進行編碼的工作中解放出來
也許您需要閱讀一下 Javadoc 的 java
text
MessageFormat 部分
以獲得對 i
nlog 工作原理的初步認識
尤其是它如何使用本地化的數據替換占位符
下面是 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 對象的)使用者的需要來切換語言環境這將是非常有用的
本地化的異常
i
nlog 提供了兩個基本的異常類(分別用於已查看和未查看的異常
LocalizedException 和 LocalizedRuntimeException)
可以這兩個類創建自己的本地化異常子類
這些類都具有構造函數
其函數簽名與 Msg 類非常相似
在使用構造函數時
通過調用資源綁定包的關鍵字和占位符的變量參數列表的方法來指定異常消息
同時還可以選擇綁定包的名稱和語言環境
這樣一來
異常消息就可以使用本地化的各種語言
其原理就是利用了 Msg 可以檢索本地化的消息
創建國際化消息的日志 i
nlog 提供了一種方法
可以通過該方法記錄國際化的日志信息
日志系統的主類是 mazz
i
n
Logger
它提供了 trace
debug
info
warn
error 和 fatal 方法等一些典型的設置
需要指出的是
與傳遞一個消息本身組成的字符串不同
您為占位符傳遞的是資源綁定包的關鍵字字符串和參數列表
它使用具有保護作用的 mazz
i
n
Msg 類來獲取實際的本地化消息
通過使用工廠類 mazz
i
n
LoggerFactory 來獲得 Logger 對象
與 log
j 等獲得對象的方式基本相同
而不同的是記錄日志消息的方法
該方法與通過 mazz
i
n
Msg 對象獲取消息非常類似
java 代碼
public static final mazzinLogger LOG =
mazzinLoggerFactorygetLogger(MyClassclass);
LOGdebug(MessagesMSG_VALUE value);
try {
}
catch (Exception e) {
LOGwarn(e MessagesMSG_ERR);
}
如果沒有啟用日志級別
則不會查找綁定包
也不會執行任何字符串連接
這一條件有效地加快了日志調用的速度
如果日志消息與特定的表達式相關聯
則需要將表達式的第一個參數傳遞給日志方法
如果啟用了棧傾卸設置
這將允許棧跟蹤傾卸消息(請往下看)
i
nlog 的日志框架中還添加了許多其他的功能
這些功能並非潛在的
第三方的日志框架所能媲美
首先要介紹的功能就是
可以告訴 Logger 是否傾卸異常的棧跟蹤
您可能需要查看一個特定運行任務的所有異常的棧跟蹤
也可能不想看
請注意
對於在 FATAL 日志級別上的異常
不能禁用此功能
使用該方法記錄的致命異常必需允許傾卸棧跟蹤
對於其他的日志級別
日志程序只有在系統屬性 i
nlog
dump
stack
traces 設置為 true (或者在代碼中調用 Logger
setDumpStackTraces(true))的時候才會傾洩棧跟蹤
i
nlog 日志框架附加的第二項功能是
在記錄與一個消息關聯的資源綁定包關鍵字的同時
記錄消息本身
資源綁定包關鍵字對於所有語言環境都是相同的
也就是說
無論消息是用何種語言寫成的
關鍵字是不變的
可以把這些關鍵字想象成
消息的 ID
或
錯誤的代碼
這在生成涉及到這些代碼的幫助文檔時非常有用
用戶將可以參考文檔中的額外幫助文本
以得知到底要傳遞什麼消息(關於如何生成這種文檔
請查看下文)
在默認情況下
此功能處於啟用狀態
要禁用此功能
只需將系統屬性 i
nlog
dump
keys 設置為 false 或者在代碼中調用 Logger
setDumpLogKeys(false)
提供消息 ID
避免在已禁用日志級別上拼接字符串
這些 i
nlog 提供的日志機制也許已經足夠了
也許有人會爭論說
將(除用戶界面消息以外的)日志消息國際化是一種負擔而且也沒有必要
我有時也感到很難說服這種觀點
如果項目沒有這種需求
您當然不必使用國際化日志
即使不使用 i
nlog 提供的日志功能
還可以使用它提供的其他功能嘛
但是
我還是可以舉出一些具體的例子來證明使用國際化消息的好處
請注意
i
nlog 允許定義一個不同的語言環境供日志程序使用(日志語言環境)
該語言環境區別於 Msg 實例使用的語言環境
這就可以幫助使用我的開發團隊的語言來記錄日志消息
而我的用戶界面使用用戶可以閱讀的語言(可能與開發團隊使用的語言不同)
例如
我的用戶說德語
而軟件是由說法語的法國團隊開發的
在這種情況下
德國用戶碰到一個問題時
就可以正常地給法國開發團隊發送日志
軟件可以默認地將語言環境設置為 Locale
FRENCH
另一方面
如果德國用戶希望自行調試問題
法語的日志消息根本不會有任何幫助
在這種情況下
德國用戶簡單地通過設置系統屬性
將日志消息記錄為德語
關於如何切換日志語言環境的信息
請參考 mazz
i
n
LoggerLocale Javadoc
自動生成資源綁定包
i
nlog 提供了一個 Ant 任務
用於自動生成資源綁定包屬性文件
以避免開發者擔負手動向屬性文件中添加消息
清理過時消息的任務
該 Ant 任務將掃描類以查找 @I
N 標注
並根據這些標注為您創建資源綁定包
這意味著
無論添加多少 @I
NMessage 標注字段
它們都將被加入到資源綁定包中
如果您刪除了一個國際化消息常量
則該消息也將從 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 任務的另一個可選功能是生成幫助文檔
該文檔是由所有對資源綁定包關鍵字名稱及其消息值的引用組成的
另外還包含了對這些消息的描述
這是一個可在 @I
NMessage 標注中指定的可選屬性
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