2010年5月25日 星期二

將WPF介面多國語言化(Localization)

要將WPF介面變成支援多國語言首先要注意一個問題
因為介面可能同時定義在XAML或C#檔案中
所以如果使用傳統的resx或是單純讀文字檔的方法是沒辦法直接做到的
(當然,如果把所有的介面文字都使用C#定義也是可行
不過這樣就不太符合WPF的精神了)

這時候需要加入新的資源字典(ResourceDictionary)

資源字典是一個XAML檔案,通常的命名會以CultureInfo的Name命名
(例如en-US.xaml或zh-TW.xaml)
這邊我們定義了一系列的字串,並賦予對應的索引(key)

<ResourceDictionary
...
xmlns:sys="clr-namespace:System;assembly=mscorlib">

<sys:String x:Key="OK">
OK
</sys:String>
<sys:String x:Key="Msg">
Msg
</sys:String>
</ResourceDictionary>

繁體中文的語系檔如下

<ResourceDictionary
...
xmlns:sys="clr-namespace:System;assembly=mscorlib">

<sys:String x:Key="OK">
確定
</sys:String>
<sys:String x:Key="Msg">
訊息
</sys:String>
</ResourceDictionary>

必須注意的是,此時此資源字典的BuildAction可以設定為Page或Content

設為Page的時候,此檔案會直接被包含到應用程式中
通常在預設語系會採用此種做法(確保至少有一種語言字典可以被找到)

而設成Content的時候,將會將此檔案獨立出來
此時,複製到輸出目錄(CopyToOutputDirectory)
需設成有更新時才複製(Copy if newer)或永遠複製(Copy always)

這種方式的好處是可以彈性的加入或移除某種語系的支援而不需要重新編譯
但是就可能會有很多檔案,在發佈的時候會造成一些麻煩
而且使用者可以任意的改動語系檔案,可能造成其他的錯誤

另外一種就是將非預設語系都包成另一個Dll(全部都設成page)
動態載入需要的語系,這樣一樣可以在不需要重新編譯程式的狀態下換語系檔
也可以保有語系檔的封閉性,只是在讀的時候可能會稍微麻煩一些
可以參考在WPF中引用被封裝的資源檔(影像)

在定義資源檔後,可以透過

private void LoadLanguage()
{
ResourceDictionary rd = null;

/// get current culture name
string lang = CultureInfo.CurrentCulture.Name;

try
{
rd = Application.LoadComponent(
new Uri(lang + " .xaml", UriKind.Relative))
as ResourceDictionary;
}
catch
{
}

if (rd != null)
{
/// find current lang xaml, replace default
if (Resources.MergedDictionaries.Count > 0)
{
Resources.MergedDictionaries.Clear();
}
Resources.MergedDictionaries.Add(rd);
}
}

將語系檔載入到應用程式的資源裡面

而在使用的地方則可以使用DynamicResource去讀取

<Button Content="{DynamicResource OK}"
Click="BtnClick" />

如果是在C#檔裡則是可以用FindResource去讀

private void BtnClick(object sender, RoutedEventArgs e)
{
MessageBox.Show(FindResources("Msg") as string);
}

此時會從物件本身開始向上查找,直到找到或Application層級為止

--
參考資料
關於讓WPF軟件界面支持全球化和本地化
WPF - Resource
FrameworkElement.FindResource 方法
資源概觀

1 則留言:

  1. CultureInfo list:

    http://msdn.microsoft.com/zh-cn/library/system.globalization.cultureinfo%28en-us,VS.71%29.aspx (MSDN)

    http://www.cnblogs.com/whtydn/archive/2009/10/13/1582279.html (风浪网编程海角 中的整理)


    此外
    CultureInfo.CurrentCulture.Name 是取得全名

    如台灣是
    zh-TW

    若要只取語系的話
    可以用
    CultureInfo.CurrentCulture.TwoLetterISOLanguageName
    or
    CultureInfo.CurrentCulture.Parent.Name
    or
    currentCultureInfo.Parent.IetfLanguageTag

    三個方式取得

    如台灣的話就會取得
    zh

    回覆刪除