上一篇有簡單介紹主工程的國際化,使用的資源字典(XAML)實現的。這幾天我添加了幾個 Prism 模組(Module),發現子模組使用資源字典的方式實現國際化和本地化不好做,沒有找到比較好的參考文章,所以換了一種方式,使用資源檔案實現了。

一. 本文概述
子模組的國際化和本地化要求:
- 各模組需要有自己單獨的語言檔案。
- 在主工程中動態切換語言時,子模組也需要跟著切換。
- 使用了 Prism 實現模組化框架,即要求主工程與各子模組不能有引用關係,即鬆耦合,不能直接在主工程中切換子模組的語言檔案。
基於上面的要求,我嘗試在各模組(Module)中也定義了語言檔案(XAML),主表單切換語言時,載入模組語言檔案老是提示不存在對應的資源字典檔案,我惱火呀,後面還是參考“Accelerider.Windows”國際化的方式,使用資源檔案實現本地化和國際化了,不糾結 Xaml 的方式了,唉。

下面是修改後的效果:

和上一版異同:
標題列國際化無變化,只是文字綁定換了種方式,實作效果一致。
左側新增了三個子模組(Home\Client\Server),使用 Prism 動態載入的,並且跟隨主工程主表單語言切換而切換語言。
下面簡單介紹怎麼建立模組,以及主表單和模組國際化怎麼做的,真的是很簡單的介紹,具體的實作可以拉程式碼看看。

二. 新增三個 Prism 模組(Module)
可安裝 Prism 範本,快速建立模組工程,當然手工建立.NET Core 工程也是可以的,就是多了幾個步驟而已(需要用 NuGet 安裝 Prism.Wpf 套件(7.2.0.1422)),我使用得的 Prism 範本快速建立的。
2.1 建立模組之前的準備工作

下載上圖搜尋到的 Prism 範本,重啟 VS,它會自動安裝,新增專案時,就有 Prism 模組範本選擇了:

注意要選擇.NET Core 3 的版本,因為我是使用.NET Core 建立的 WPF 專案。
2.2 建立模組
下面是已經建立好的三個模組工程截圖:

目前三個模組檔案組織結構類似:
- I18nResources:資源資料夾,放 3 個語言資源檔案和一個 T4 範本檔案(用於引用語言 Key),其中 T4 範本檔案在 3 個模組和主工程中定義是一樣的,具體可從 github 下載原始碼查看。
- Views 放置檢視檔案,現在只使用到了主工程主表單中顯示的 TabItem 檢視,即 MainTabItem.xaml,繼承自 TabItem。
- xxxxModule.cs:prism 範本定義檔案,prism 發現模組使用。
三個模組關鍵點需要注意:
- 編輯模組工程檔案,修改模組檔案輸出目錄:
// 省略部分程式碼,下面這一行設定為False,代表輸出目錄不帶.NET Core版本資訊
<AppendTargetFrameworkToOutputPath>Flase</AppendTargetFrameworkToOutputPath>
// 省略部分程式碼,修改Debug與Release編譯輸出目錄,方便主工程統一載入模組
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\Build\Debug\Modules</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..\Build\Release\Modules</OutputPath>
</PropertyGroup>
// 省略部分程式碼
- XXXModule 中需要將資源檔案的 ResourceManager 引用新增到另一個庫中儲存,待切換語言時需要使用,如在 HomeModule 的建構函式中新增程式碼如下,只新增這一句程式碼就好,模組的國際化及本地化就算完事了:
I18nManager.Instance.Add(TerminalMACS.Home.I18nResources.UiResource.ResourceManager);
- XXXModule 的 RegisterTypes 方法中註冊檢視"MainTabItem"到"RegionNames.MainTabRegion",主表單使用"RegionNames.MainTabRegion"關聯模組檢視顯示載入。
_regionManager.RegisterViewWithRegion(RegionNames.MainTabRegion, typeof(MainTabItem));
- UI 控制項國際化文字繫結,其中 markup 使用的一個開源庫命名空間,後面會給出連結,本專案直接將該庫載入進了解決方案中;i18NResources:Language 即 T4 範本檔案產生的類,關聯文字翻譯的 Key。繫結文字部分程式碼如下:
<TextBlock Grid.Row="2" Text="{markup:I18n {x:Static i18NResources:Language.MainTabItm_Header}}"
三. 主工程
主工程目錄組織結構如下:

3.1 動態載入 Prism 模組
設定載入 3 個模組的關鍵程式碼在 App.xaml.cs 檔案中,看上面的程式碼,我將三個模組輸出到了 Modules 目錄下,主工程直接載入此目錄即可,其他載入方式還有使用設定檔等,可以參考 Prism 官方範例,文末給出連結:
protected override IModuleCatalog CreateModuleCatalog()
{
string modulePath = @".\Modules";
if (!Directory.Exists(modulePath))
{
Directory.CreateDirectory(modulePath);
}
return new DirectoryModuleCatalog() { ModulePath = modulePath };
}
主表單顯示子模組註冊的 TabItem 檢視,prism:RegionManager.RegionName 即在各子模組中註冊過的區域字串,他與模組對應的 TabItem 檢視關聯,程式碼如下:
<TabControl Grid.ColumnSpan="2" SelectedIndex="0"
Style="{StaticResource MainTabControlStyle}"
ItemContainerStyle="{StaticResource MainTabItemStyle}"
prism:RegionManager.RegionName="{x:Static ui:RegionNames.MainTabRegion}"/>
主表單以 TabControl 的控制項形式展示子模組檢視:

主工程要能正常載入子模組,主工程的工程檔案也需要修改其輸出目錄:
// 省略部分程式碼,下面這一行設定為False,代表輸出目錄不帶.NET Core版本資訊
<AppendTargetFrameworkToOutputPath>Flase</AppendTargetFrameworkToOutputPath>
// 省略部分程式碼,修改Debug與Release編譯輸出目錄,方便主工程統一載入模組
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\Build\Debug</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..\Build\Release</OutputPath>
</PropertyGroup>
// 省略部分程式碼
3.2 修改語言檔案格式
刪除了原有的 XAML 語言檔案,替換為 resx 的資源檔案,和三個模組的資源檔案型別類似,下面是主工程的資源檔案:

替換成資源檔案,編輯是要比 XAML 檔案要方便點,起初是有考慮使用資源檔案實現國際化的,作死想嘗試 XAML 檔案。

3.3 語言切換核心程式碼
動態切換語言的關鍵程式碼改為:
public static void SetLanguage(string language = "")
{
if (string.IsNullOrWhiteSpace(language))
{
language = ConfigHelper.ReadKey(KEY_OF_LANGUAGE);
if (string.IsNullOrWhiteSpace(language))
{
language = System.Globalization.CultureInfo.CurrentCulture.ToString();
}
}
ConfigHelper.SetKey(KEY_OF_LANGUAGE, language);
_lastLanguage = language;
var culture = new System.Globalization.CultureInfo(language);
I18nManager.Instance.CurrentUICulture = culture;
}
核心的語言切換程式碼是最後一句,不詳細說了,解決方案中有庫、有原始碼:
I18nManager.Instance.CurrentUICulture = culture;
四. 原始碼
- 原始碼位址,歡迎 star:https://github.com/dotnet9/TerminalMACS/tree/master/src/TerminalMACS.Manager/TerminalMACS.ManagerForWPF
五. 參考資料
- Prism Template Pack(Prism 範本):https://marketplace.visualstudio.com/items?itemName=BrianLagunas.PrismTemplatePack
- WPF 國際化開源輔助庫:https://github.com/DingpingZhang/WpfExtensions
- Accelerider.Windows(子模組載入參考開源專案):https://github.com/Accelerider/Accelerider.Windows
- Prism-Samples-Wpf(官方 Demo): https://github.com/PrismLibrary/Prism-Samples-Wpf