關於讓WPF軟體介面支援全球化和本地化
周銀輝
有朋友詢問如何讓WPF應用能夠提供多語言支援(中文,英文,日文.....),我的建議是:(1)拋棄WinForm時代的資源儲存方式 (2)利用WPF的動態資源特性.
下面簡單介紹一下並打造一個簡單的DEMO:
1,語言資源檔怎樣儲存
我們知道以前(WPF以前)我們將介面上的各國語言分別儲存在.resx類型的檔案中,然後利用ResourceManager來得到相應資源並根據當地的CultureInfo來給介面文本賦值.這是可行的.但在WPF中存在的一個問題是:我們必須為每個控制項在後台代碼中來Code這些邏輯,因為XAML是找不到.resx類型中的資源的.但WPF中絕大多數介面元素都是在XAML中定義的這是一件很麻煩的事情.所以我們應該拋棄這樣的做法.
WPF中的資源繼承了以前的多種儲存形式,但可以在XAML和C#(或其他)中通行的有兩中,一個是Content,一個是Resource,前者是"內容",既是鬆散的資源連結,後者是被編譯並內嵌資源,注意,你在設定資源檔屬性的時候會發現還有一個很讓人混淆的Embedded Resource,這也是內嵌的資源,但其被壓縮為二進位形式,既和以前WinForm的內嵌資源相同,Resource和Embedded Resource在編碼上的區別是前者可以通過Uri找到,這是XAML需要的方式,後者可以通過Stream找到,這可以通過編寫c#代碼來尋找資源.
所以,在這裡看來Content是我們儲存語言資源的良好方式,由於其是鬆散的資源連結,所以為應用程式添加新的語言套件時就可以不重新編譯了,只需將對象的語言檔案拷貝到指定的檔案夾即可.
2,介面元素如何連結到語言文本
這是StaticResource 和 DynamicResource要做的事情,比如:<Button Content="{DynamicResource OK}"/>
至於是使用StaticResource 還是DynamicResource,這取決於你是否要在運行時動態切換,如果僅僅是軟體啟動的時候才切換語言StaticResource就可以了.
3,OK 實戰一下:
3.1 建立項目,並在項目中建立一個Lang檔案夾用於儲存我們的語言檔案
3.2 在Lang檔案夾中,建立"ResourceDictionary(WPF)",命名為"DefaultLanguage.xaml",並將其BuildAction設定為Page,這是一個預設語言資源檔,其將被編譯(而不是鬆散連結,這樣可以確保在軟體語言套件丟失或沒有某國家或地區的對應語言套件時可以有一種預設的介面語言):我們這裡採用英文作為預設語言:<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="OK">
OK
</sys:String>
<sys:String x:Key="Cancel">
Cancel
</sys:String>
</ResourceDictionary>
然後,我們添加另一國語言,比如中文,在Lang檔案夾中,建立"ResourceDictionary(WPF)",命名為"zh-CN.xaml",並將其BuildAction設定為Content,將CopyToOutputDirctory設定為"if new",這樣,我們的中文語言檔案為將被拷貝到應用程式目錄下的Lang目錄下,其他的非預設語言的語言檔案都應該採取這種方式.<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="OK">
確定
</sys:String>
<sys:String x:Key="Cancel">
取消
</sys:String>
</ResourceDictionary>
3.3 為了讓編碼人員在設計器(比如VS,Blend)中所見即所得 (WYSIWYG)地看到介面文本,我們應該將預設語言資源加入到應用程式的資源清單中:<Application x:Class="LangDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="lang\DefaultLanguage.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
這樣我們就可以在設計器中使用這些資源了:
我們可以看到由於我們載入的預設語言是英文,設計器中我們的視窗介面上顯示的是對應的英文文本.
3.4 軟體啟動時載入對應的本地化的語言:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
LoadLanguage();
}
private void LoadLanguage()
{
CultureInfo currentCultureInfo = CultureInfo.CurrentCulture;
ResourceDictionary langRd = null;
try
{
langRd =
Application.LoadComponent(
new Uri(@"Lang\" + currentCultureInfo.Name + ".xaml", UriKind.Relative))
as ResourceDictionary;
}
catch
{
}
if (langRd != null)
{
if (this.Resources.MergedDictionaries.Count > 0)
{
this.Resources.MergedDictionaries.Clear();
}
this.Resources.MergedDictionaries.Add(langRd);
}
}
}
當軟體啟動時,我們根據當地的CultureInfo來載入對應的語言檔案(如果該語言檔案存在的話),由於介面上的文本不是寫入程式碼進去的,而是採用DynamicResource,當後台Resource改變時,前台的引用也會動態改變,OK,當軟體啟動後,我們的介面就自動的切換了,我這台電腦上是中文:
當然,本地化還有很多內容,比如貨幣數字,讀取順序等,這裡僅僅提供了一個思想,你還可以在這裡下載DEMO