如果你打算發布你的應用程序到全球各地,你可能需要為不同地區的用戶界 面准備不同的版本。至少,這需要解決將文本翻譯成適當的語言;同樣需要解決 UI改變的問題。你可能需要特定的外觀適應為本地化的文化習俗。或者,你可能 會發現原始的外觀在翻譯後並不能正常工作,因為詞的長度是不一樣的。(雖然 WPF的外觀體系避免了這一問題,更易於創建更彈性的外觀。)
為你的軟件在不同的市場創建不同的版本是可能的。盡管如此,更加普遍的 辦法是創建一個單獨的版本來適應於不同的場所,通過在運行期選取一個合適的 資源文件。WPF的底層架構ResourceManager可以相當直接地使用這個辦法。
Microsoft對本地化和全球化加以區別。本地化是一個支持一個應用程序在意 個特定的場所使用的過程,通過創建特定文化的資源如文本的翻譯。全球化是一 個確保一個應用程序可以被本地化而不用編譯的過程。使用ResourceManager可 以幫助我們對應用程序進行全球化,因為這個類的在運行期選擇的資源支持一個 單獨的應用程序版本通過提供合適的資源進行本地化。更多信息請參考微軟國際 站點http://msdn.microsoft.com/library/default.asp?url=/library/en- us/vbcon/html/vboriInternationalization.asp (http://shrinkster.com/6m9).
當一個ResourceManager被要求按名稱獲取資源流時,首先它要決定使用哪種 文化。文化時語言與區域的合稱,被典型地表示為一個短字符串。例如,en-US 表示在美國使用的英語。而en-GB則代表在英國使用的英語。前兩個字母表明語 言,後兩個表示區域。同時指明語言和區域是因為即使兩種文化共用一種語言, 在方言和習語上還是有差別的。例如,本書的作者之一來自en-GB,因此喜歡使 用color而不是colour。
ResourceManager的GetStream方法使用一個CultureInfo對象作為參數。如果 你想使用用戶最終配置過的文化,你可以從Thread.CurrentThread的 CurrentUICulture屬性重新獲取一個CultureInfo對象。
雖然可執行體經常將資源編譯到其中,ResourceManager仍然會先尋找指定文 化的資源,在求諸於內嵌資源之前。首先會在包含應用程序目錄的子目錄中按文 化名稱搜索。因此,如果你的應用程序運行在French-Canadian的文化上,會在 名為fr-CA的子目錄中尋找一個叫做MyApp.resources.dll的文件,這裡MyApp是 應用程序或組件的名稱。如果不存在,會接著在尋找名為fr的目錄尋找相同的文 件。這意味著一旦你的翻譯預算並不擴展到為全世界所有使用法語的不同區域產 生不同的版本,你可以取代的提供一套單獨的法語資源,專門用於使用法語的區 域。如果這些子目錄都不存在這個文件,它將求助於使用內嵌資源。
這些被ResourceManager尋找的DLL資源稱為全球化編譯資源,命名的原因是 這些資源都是很小的資源,聚集為一個大的編譯集。
注意到,一旦你提供了一個全球化編譯集,你就不需要提供所有資源的本地 化版本。這樣那些內嵌在你的主編譯集的資源對於所有資源都是很是的。例如, 圖6-6中的應用程序有一個內嵌的bmp文件Sunset.jpg。世界大部分都會有日落, 所以你仍可能需要為南極和北極的版本做特殊的工作。基本的Sunset.jpg可以為 大多數文化使用。這將要浪費空間對於每個全球化資源都要獲取同一張圖片的副 本。幸運的是,這不是必須的。如果一個特定的命名資源在全球化編譯資源中並 不存在,ResourceManager將會回到內嵌資源中來。
你可以把全球化編譯資源想象為僅包含內嵌資源和目標文化所需資源之間的 差別。任何普通的資源都單獨位於主編譯集中。一個特定語言但不限區域的編譯 集所在的子目錄(如fr子目錄),包含不同於特定語言的所需資源。而且,完全 特定文化的子目錄(如fr-CA,fr-FR,fr-BE等)包含那些需要考慮當地習語的 資源(在這裡的上下文中,“資源”是一個通過ResourceManager重新獲得的流 ,而不是通過ResourceDictionary重新獲取到的對象)
6.4.1使用XAML創建本地化應用程序
因為XAML是編譯在BAML資源中的,可以通過ResourceManager獲取到,本地化 是一種內在的特征,由任何WPF應用程序使用XAML創建。盡管如此,在Visual Studio 2005中,並沒有對WPF應用程序本地化提供內在支持,因此需要一些手動 步驟。
如果你要在XAML中創建一個UI,有效的本地化每次產生一個XAML文件。 ResourceManager不能比一個單獨的BAML資源得到更加細密的資源,因此,每一 個BAML資源不是本地化就是非本地化的。由於xaml文件和其後台代碼之間的緊密 聯系,盡管如此,本地化BAML資源具有和原始版本一樣的基本結構,這是非常重 要的。基本上,你可以通過為本地化版本寫一個xaml文件獲取資源,並且嘗試保 持結構的一樣。然而,這是一種具有更具強壯性的方式來保證一致性。
取代以為每種文化創建一組xaml文件,你可以寫一組主要的xaml文件,每個 窗體或頁面都有一個這樣的文件。你可能希望對每種惡化都提供支持,可以使用 一個工具生成特定文化的全球化編譯資源,其中包含本地化資源。你提供配置文 件的工具表明資源應該如何被修改,從而創建本地化的版本。圖6-7解釋了全部 的過程。
這是一個些微冗長的過程。在WPF最新的發布版本中,並未更好的改進和集成 到Visual Studio 2005中。眼下,歡迎此預發布的軟件來到這個精彩的世界。
圖6-7
首先,你必須保證工程通過指定一個默認的UI文化,被設置為創建一個本地 化的應用程序。在寫代碼的時候,沒有辦法在Visual Studio 2005中進行這樣的 操作,所以你必須使用文本編輯器編輯.csproj文件。在PropertyGroup元素中添 加一個UICulture元素(UICulture元素出現在那個部分並不要緊),將其設置為 默認文化。該文化為將要創建的主要資源。這將引起Visual Studio 2005為了這 個默認文化,將所有的二進制資源置入全球化編譯資源中。示例6-28展示了一個 xaml的例子。
示例6-28
<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<UICulture>en-US</UICulture>
</PropertyGroup>
下一步,你必須將Uids標簽添加到xaml中。Uid標簽是xaml元素的一個特殊的 屬性,顯示需要本地化的內容。包含了本地化指令的本地化配置文件,使用Uid 屬性顯示那些元素被修改了。示例6-29展示了一個使用了Uid的TextBlock。
示例6-29
<TextBlock x:Uid="TextBlock_1">Hello, world</TextBlock>
你可以手動添加你想要的。或者你能使用msbuild自動生成它們(msbuild是 一個命令行工具,用來生成工程。Visual Studio 2005使用同樣的創建技術,但 是msbuild提供更多的控制。例如,它允許你在Uid生成WPF創建系統的特征)。 為了自動添加Uids到你的xaml中,運行這個命令:
msbuild /t:updateuid MyProject.csproj
如果你已經做完這些,隨後編輯好你的xaml,你可能想檢查是否以重復的Uid 標簽終結,可以使用以下命令:
msbuild /t:checkuid MyProject.csproj
現在你可以生成這個工程了,或者使用Visual Studio 2005的命令行執行 msbuild,將工程名作為一個參數傳遞。你會發現在生成一個exe或dll的同時, 你的工程也在子目錄中添加了一個全球化資源。(這個子目錄將是添加到工程中 的UICulture元素名稱重的一個。)
下一步是創建一個配置文件用於引導本地化過程。這個文件包含所有的本地 化資源,如翻譯過的字符串。你可以使用LocBaml命令行工具創建這個文件的骨 架。這個工具檢查了BAML流的編譯資源,創建了一個文件,文件中每一行都是一 條本地化信息。你可以將翻譯字符串和任何需要的資源放入這個文件中。
在WPF的當前預覽版本中,LocBaml只提供源代碼的形式,因此在執行之前需 要先生成它。你可以在WinFX SDK文檔中找到這些代碼。在Avalon- Globalization and Localization-How-to Topic section,找到“Localize an Application”標題。這裡將提供給你LocBaml的代碼。
示例6-30展示了如何執行LocBaml生成配置文件的骨架。
示例6-30
LocBaml bin\Debug\en-US\MyApp.resources.dll /out:MyAppResources.csv
這將創建一個CSV文件。表6-1描述了CSV文件中每一列(按出現順序)。為了 本地化一個資源,編輯Value這一列。(注意這個CSV文件並不包含標題行,只依 賴於列的位置。)
表6-1
列名 描述 Baml Name 唯一標志BAML流,這個值表現為 AssemblyManifestStreamName:SubStraemName 的形式 Resource Key 唯一標志本地化資源,這個值表現為 Uid.ElementType.$Property的形式 Localization Category 一個來自LocalizationCategory枚舉的入口,表明是哪一 類內容 Readable 表明在轉換期間資源是否可見 Modifiable 表明在轉換期間Value是否可以更改 Comments 本地化的注釋 Value 資源的值示例6-31展示了配置文件中的一行。(由於頁面寬度,這一行被拆成了3行顯 示在下面)。
示例6-31
HelloApp.g.fr-FR.resources:window1.baml,
TextBlock_1:System.Windows.Controls.TextBlock.$Content,
None,True,True,,Bonjour monde
一旦你已經轉換了所有的值,你就可以再次執行LocXaml生成新的資源dll。 你必須傳遞原始資源dll的路徑,CSV文件(包含翻譯)的路徑,一個目標地址, 以及一個目標文化,正如示例6-32所示。。(由於頁面寬度,這一行被拆成了3 行顯示在下面)。
示例6-32
LocBaml /generate bin\Debug\en-US\MyApp.resources.dll /trans:MyAppResource.csv
/out:bin\Debug\en-GB /cul:en-GB
這將生成一個新的全球化編 譯資源在指定的目錄,以選中的文化為目標。(如果你想生成多個編譯資源,為 每一種文化創建一個CSV文件,為每個文件只執行一次LocBaml。)如果你把資源 編譯結果放在一個按文化命名的應用程序目錄的子目錄中,這將自動在運行期被 獲取到,應用程序會執行選中的特定文化。