dotnetcore3.1 WPF 實現多語言


dotnetcore3.1 WPF 實現多語言

Intro

最近把 DbTool 從 WinForm 遷移到了 WPF,並更新到了 dotnet core 3.1,並實現了基於 Microsoft.Extensions.Localization 實現了基本的多語言支持。下面來分享一下如何來實現

服務注冊

如果不熟悉如何在 WPF 中使用依賴注入,可以參考上一篇文章 dotnetcore3.1 WPF 中使用依賴注入

在應用啟動前注冊 Localization 服務,我這里使用的是自己自定義的基於 JSON 的多語言服務

services.AddJsonLocalization(options => options.ResourcesPathType = ResourcesPathType.CultureBased);

服務注冊的最后使用了一個 ServiceLocator 模式的代碼(DependencyResolver),保存了所有的注冊服務,后面的 Localizer 擴展會用到

DependencyResolver.SetDependencyResolver(services);

代碼文件實現方式

代碼文件(如:MainWindow.xaml.cs) 中實現多語言較為簡單,直接注入 IStringLocalizer 即可,獲取對應的要實例化的,比如:

public partial class MainWindow: Window
{
    private readonly IStringLocalizer<MainWindow> _localizer;
    public MainWindow(
        IStringLocalizer<MainWindow> localizer)
    {
        InitializeComponent();

        _localizer = localizer;
    }
    // ...
    {
     // ...
     MessageBox.Show(_localizer["Success"], _localizer["Tip"]);
    }
}
 

xaml 實現方式

LocaliazerExtension

xaml 文件中使用需要自定義一個擴展,定義如下,【實現源碼】

public class LocalizerExtension : MarkupExtension
{
    private readonly IStringLocalizerFactory _localizerFactory;
    public string Key { get; }

    public LocalizerExtension(string key)
    {
        Key = key;
        _localizerFactory = DependencyResolver.Current.
            ResolveService<IStringLocalizerFactory>();
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var targetRootType = serviceProvider.GetType()
            .GetProperty("System.Xaml.IRootObjectProvider.RootObject", BindingFlags.Instance | BindingFlags.NonPublic)
            ?.GetValue(serviceProvider)
            ?.GetType();
        if (null == targetRootType)
        {
            targetRootType = typeof(MainWindow);
        }

        var localizer = _localizerFactory.Create(targetRootType);
        var value = localizer[Key];
        return (string)value;
    }
}

這里使用到了上面提到的 ServiceLocator 模式的代碼,從 DependencyResolver 獲取注冊的服務,感覺這里的實現需要優化,有更好想法的小伙伴還望一起交流一下,另外如果你的應用比較簡單,我覺得上面代碼里的通過反射獲取 targetRootType 的代碼可以直接使用某一個類型例如:typeof(MainWindow) ,這樣會更高效

在 xaml 中使用

  1. Window 標簽中添加擴展對應的命令空間,例如: xmlns:loc="clr-namespace:DbTool.Localization"
  2. 在需要實現多語言的地方引用,例如:<TextBlock Margin="0,0,4,0" Text="{loc:Localizer DbConnectionString}"></TextBlock>
  3. 在對應的資源文件中配置要使用多語言資源,如上面的 DbConnectionString
<Window x:Class="DbTool.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:loc="clr-namespace:DbTool.Localization"
        mc:Ignorable="d"
        Title="DbTool" Height="450" Width="800" FontSize="14">
    <Grid>
        <TextBlock Margin="0,0,4,0" Text="{loc:Localizer DbConnectionString}"></TextBlock>
    </Grid>
</Window>

語言切換

發生語言切換時或應用啟動時設置默認語言時,要更新當前線程的 Culture 信息

// set current culture
var defaultCulture = "zh";
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(defaultCulture);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(defaultCulture);

實現效果

中文

英文

More

這種方式的實現,目前還需要重啟之后界面的語言才會發生變化,可以進一步優化,實現動態多語言,修改語言之后界面就切換,目前不是太需要,暫時沒做,有需要的可以先自己研究一下。

Reference


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM