How to internationalize and localize the WPF Prism Module?

How to internationalize and localize the WPF Prism Module?

The previous article briefly introduced the internationalization of the main project, which was implemented using the Resource Dictionary (XAML). I have added several Prism modules (Modules) in the past few days, and found that it is difficult to achieve internationalization and localization of sub-modules by using resource dictionaries. I couldn't find a better reference article, so I changed the method and used resource files to achieve it.

最后更新 4/21/2020 1:45 PM
沙漠尽头的狼
预计阅读 8 分钟
分类
WPF
专题
WPF MVVM Framework Prism Series
标签
.NET WPF Prism internationalization localization

The previous article briefly introduced the internationalization of the main project, which was implemented using the Resource Dictionary (XAML). I have added several Prism modules (Modules) in the past few days, and found that it is difficult to achieve internationalization and localization of sub-modules by using resource dictionaries. I couldn't find a better reference article, so I changed the method and used resource files to achieve it.

I. this paper summarizes

Internationalization and localization requirements for submodules:

  1. Each module needs to have its own separate language file.
  2. When dynamically switching languages in the main project, sub-modules also need to switch accordingly.
  3. Prism is used to implement the modular framework, which requires that the main project and each sub-module cannot have a reference relationship, that is, loose coupling, and language files of sub-modules cannot be directly switched in the main project.

Based on the above requirements, I tried to define language files (XAML) in each module. When the main form switches languages, loading the module language files always prompts that there is no corresponding resource dictionary file. I am annoyed. Later, I still refer to the internationalization method of "Accelerider.Windows" and use resource files to achieve localization and internationalization. I don't bother with Xaml's method anymore. Sigh.

The following is the modified effect:

Differences and differences with the previous edition:

  1. There is no change in the internationalization of the title bar, but the text binding method has been changed to achieve consistent results.

  2. Three sub-modules (Home\Client\Server) have been added to the left, which are dynamically loaded using Prism, and switch languages following the main project main form language switching.

The following is a brief introduction to how to create modules and how to internationalize the main form and modules. It is really a very simple introduction. You can pull the code to see the specific implementation.

II. Add three Prism modules (Modules)

You can install the Prism template and quickly create a module project. Of course, it is also possible to create a. NET Core project manually, just a few more steps (you need to use NuGet to install the Prism.Wpf package (7.2.0.1422)). I used the Prism template to quickly create it.

2.1 Preparation before creating a module

Download the Prism template found in the above figure, restart VS, and it will be automatically installed. When you create a new project, you will have a Prism module template selected:

Be careful to choose the version of. NET Core 3 because I created a WPF project using. NET Core.

2.2 creation module

The following are screenshots of the three module projects that have been created:

Currently, the three module file organization structures are similar:

  • I18nResources: Resource folder, which holds 3 language resource files and a T4 template file (used to reference the language Key). The T4 template file is defined the same in the 3 modules and the main project. You can download the source code from github for details.
  • Views placement view file now only uses the TabItem view displayed in the main form of the main project, i.e. MainTabItem.xaml, which is inherited from TabItem.
  • xxxxModule.cs: prism template definition file, used by prism discovery module.

There are three key points to pay attention to:

  1. Edit the module project file and modify the module file output directory:
// 省略部分代码,下面这一行设置为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>
// 省略部分代码
  1. In XXXModule, you need to add the ResourceManager reference to the resource file to another library and save it. You need to use it when switching languages. For example, add the following code to the constructor of HomeModule. Just add this code. Internationalization and localization of the module are done:
I18nManager.Instance.Add(TerminalMACS.Home.I18nResources.UiResource.ResourceManager);
  1. The views "MainTabItem" to "RegionNames.MainTabRegion" are registered in the RegisterTypes method of XXXModule, and the main form uses the "RegionNames.MainTabRegion" associated module view display and loading.
_regionManager.RegisterViewWithRegion(RegionNames.MainTabRegion, typeof(MainTabItem));
  1. UI controls internationalized text binding. Markup uses an open source library namespace, and links will be given later. This project directly loads the library into the solution; i18NResources:Language is the class generated by the T4 template file, associated with the Key of text translation. The code of the binding text is as follows:
<TextBlock Grid.Row="2" Text="{markup:I18n {x:Static i18NResources:Language.MainTabItm_Header}}"

III. main works

The organizational structure of the main project catalog is as follows:

3.1 Dynamically loading the Prism module

The key code for configuring and loading the three modules is in the App.xaml.cs file. Looking at the code above, I have exported the three modules to the Modules directory. The main project can directly load this directory. Other loading methods include using configuration files. You can refer to the official example of Prism. The link is given at the end of the article:

protected override IModuleCatalog CreateModuleCatalog()
{
    string modulePath = @".\Modules";
    if (!Directory.Exists(modulePath))
    {
        Directory.CreateDirectory(modulePath);
    }
    return new DirectoryModuleCatalog() { ModulePath = modulePath };
}

The main form displays the TabItem view registered by the sub-module. prism:RegionManager.RegionName is the regional string registered in each sub-module. It is associated with the TabItem view corresponding to the module. The code is as follows:

<TabControl Grid.ColumnSpan="2" SelectedIndex="0"
    Style="{StaticResource MainTabControlStyle}"
    ItemContainerStyle="{StaticResource MainTabItemStyle}"
    prism:RegionManager.RegionName="{x:Static ui:RegionNames.MainTabRegion}"/>

The main form displays sub-module views in the form of TabControl controls:

子模块的TabItem视图

If the main project can load sub-modules normally, the project files of the main project also need to modify their output directory:

// 省略部分代码,下面这一行设置为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 Modify language file format

The original XAML language file was deleted and replaced with resx resource file. The type is similar to the resource file of the three modules. The following are the resource files of the main project:

资源文件作为语言文件使用

Replacing it with resource files is more convenient to edit than XAML files. At first, I considered using resource files to achieve internationalization, but I wanted to try XAML files.

折腾是可以涨姿势的

3.3 Language switching core code

The key code for dynamically switching languages is changed to:

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;
}

The core language switching code is the last sentence. Without going into detail, the solution includes libraries and source codes:

I18nManager.Instance.CurrentUICulture = culture;

IV. source code

  • Source code address, welcome star: github.com/dotnet9/TerminalMACS/tree/master/src/TerminalMACS.Manager/TerminalMACS.ManagerForWPF

v. resources

  • Prism Template Pack: marketplace.visualstudio.com/items? itemName=BrianLagunas.PrismTemplatePack
  • WPF Internationalized Open Source Auxiliary Library: github.com/DingpingZhang/WpfExtensions
  • Accelerator.Windows (sub-module loading reference open source project): github.com/Accelerider/Accelerider.Windows
  • Prism-Samples-Wpf (official Demo): https://github.com/PrismLibrary/Prism-Samples-Wpf
Keep Exploring

延伸阅读

更多文章