少有人走的路

勇哥的工业自动化技术网站

wpf, CommunityToolkit.Mvvm, Autofac, .net8技术栈下的多语言切换

多语言切换。


act103.gif



image.png


LocalizationExtensions.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApp1.Core.Interfaces;

namespace WpfApp1.Core.Extensions
{
    public static class LocalizationExtensions
    {
        private static ILocalizationManager? _localizationManager;

        // 初始化扩展方法的依赖
        public static void Initialize(ILocalizationManager localizationManager)
        {
            _localizationManager = localizationManager;
        }

        // 无Key时,使用defaultValue作为Key
        public static string ToLanguage(this string defaultValue, string key = "")
        {
            if (_localizationManager == null)
                return defaultValue;

            var actualKey = string.IsNullOrEmpty(key) ? defaultValue : key;
            return _localizationManager.GetText(actualKey, defaultValue);
        }
    }
}


ILocalizationManager.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApp1.Core.Interfaces
{
    public interface ILocalizationManager
    {
        string GetText(string key, string defaultValue);
        void ChangeCulture(string cultureName);
    }
}


AutofacModule.cs

using Autofac;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApp1.Core.Interfaces;
using WpfApp1.UI.ViewModels;

namespace WpfApp1.Core.Services
{
    public class AutofacModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            // 注册多语言服务
            builder.RegisterType<LocalizationManager>()
                   .As<ILocalizationManager>()
                   .SingleInstance();

            // 注册ViewModel
            builder.RegisterType<MainViewModel>()
                   .AsSelf()
                   .InstancePerDependency();
        }
    }
}


LocalizationManager.cs

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Resources;
using System.Text;
using System.Threading.Tasks;
using WpfApp1.Core.Interfaces;

namespace WpfApp1.Core.Services
{
    public class LocalizationManager : ILocalizationManager
    {
        private readonly ResourceManager _resourceManager;
        private CultureInfo _currentCulture;

        public LocalizationManager()
        {
            _resourceManager = new ResourceManager("WpfApp1.Resources.Strings", typeof(LocalizationManager).Assembly);
            _currentCulture = CultureInfo.CurrentUICulture;
        }

        public string GetText(string key, string defaultValue)
        {
            try
            {
                var value = _resourceManager.GetString(key, _currentCulture);
                return string.IsNullOrEmpty(value) ? defaultValue : value;
            }
            catch
            {
                return defaultValue;
            }
        }

        public void ChangeCulture(string cultureName)
        {
            _currentCulture = new CultureInfo(cultureName);
            CultureInfo.CurrentUICulture = _currentCulture;
            CultureInfo.CurrentCulture = _currentCulture;
        }
    }
}



image.png

image.png


LocalizeExtension.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Markup;
using WpfApp1.Core.Extensions;

namespace WpfApp1.UI.MarkupExtensions
{
    [MarkupExtensionReturnType(typeof(string))]
    public class LocalizeExtension : MarkupExtension
    {
        public string? Key { get; set; }
        public string? Text { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (string.IsNullOrEmpty(Text))
                return string.Empty;

            // 按文档逻辑:若Key为空则用Text本身作为Key
            return Text.ToLanguage(Key);
        }
    }
}


MainViewModel.cs

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApp1.Core.Extensions;
using WpfApp1.Core.Interfaces;

namespace WpfApp1.UI.ViewModels
{
    public partial class MainViewModel : ObservableObject
    {
        private readonly ILocalizationManager _localizationManager;

        [ObservableProperty]
        private string? _saveButtonText;

        [ObservableProperty]
        private string? _welcomeMessage;

        public MainViewModel(ILocalizationManager localizationManager)
        {
            _localizationManager = localizationManager;
            LoadLocalizedTexts();
        }

        private void LoadLocalizedTexts()
        {
            // 无Key方式
            SaveButtonText = "保存".ToLanguage();
            // 指定Key方式
            WelcomeMessage = "欢迎使用多语言演示".ToLanguage("Welcome_Message");
        }

        [RelayCommand]
        public void SwitchToEnglish()
        {
            _localizationManager.ChangeCulture("en-US");
            LoadLocalizedTexts();
        }

        [RelayCommand]
        public void SwitchToChinese()
        {
            _localizationManager.ChangeCulture("zh-CN");
            LoadLocalizedTexts();
        }
    }
}


MainWindow.xaml

<Window x:Class="WpfApp1.UI.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ui="clr-namespace:WpfApp1.UI.MarkupExtensions"
        xmlns:vm="clr-namespace:WpfApp1.UI.ViewModels"
        Title="多语言演示" Height="300" Width="400">
    <StackPanel Margin="20" VerticalAlignment="Center">
        <!-- 绑定ViewModel属性 -->
        <TextBlock Text="{Binding WelcomeMessage}"
                   FontSize="16" Margin="0 0 0 20"/>

        <!-- 绑定ViewModel属性 -->
        <Button Content="{Binding SaveButtonText}"
                Command="{Binding SaveCommand}"
                Width="100" Margin="0 0 0 10"/>

        <!-- 切换语言按钮 -->
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Button Content="English" Command="{Binding SwitchToEnglishCommand}" Margin="0 0 10 0"/>
            <Button Content="中文" Command="{Binding SwitchToChineseCommand}"/>
        </StackPanel>
    </StackPanel>
</Window>



App.xaml

<Application x:Class="WpfApp1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApp1"
             >
    <Application.Resources>
         
    </Application.Resources>
</Application>



App.xaml.cs

using Autofac;
using System.Configuration;
using System.Data;
using System.Windows;
using WpfApp1.Core.Extensions;
using WpfApp1.Core.Interfaces;
using WpfApp1.Core.Services;
using WpfApp1.UI.ViewModels;
using WpfApp1.UI.Views;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private IContainer? _container;

        protected override void OnStartup(StartupEventArgs e)
        {
            // 初始化Autofac容器
            var builder = new ContainerBuilder();
            builder.RegisterModule<AutofacModule>();
            _container = builder.Build();

            // 初始化多语言扩展方法
            var localizationManager = _container.Resolve<ILocalizationManager>();
            LocalizationExtensions.Initialize(localizationManager);

            // 启动主窗口
            var mainWindow = new MainWindow
            {
                DataContext = _container.Resolve<MainViewModel>()
            };
            mainWindow.Show();
        }

        protected override void OnExit(ExitEventArgs e)
        {
            _container?.Dispose();
            base.OnExit(e);
        }
    }

}


多语言切换的原理基于以下几个核心组件和流程:


1. 资源文件管理

项目使用了.NET的资源文件系统来存储不同语言的文本:


- Strings.resx - 包含默认语言(中文)的文本

- Strings.en-US.resx - 包含英文的文本

- 这些资源文件被编译成程序集的一部分,通过ResourceManager访问


 2. 本地化管理器 (LocalizationManager)

LocalizationManager是核心组件,负责:


- 初始化 :创建ResourceManager实例,指向正确的资源文件

- 获取文本 :根据键和默认值从资源文件中获取本地化文本

- 切换语言 :通过ChangeCulture方法切换当前的文化信息(CultureInfo)


3. 语言切换流程

当用户点击语言切换按钮时:


1. 命令执行 :触发SwitchToEnglishCommand或SwitchToChineseCommand

2. 调用LocalizationManager :执行ChangeCulture方法,传入对应的文化名称(如"en-US"或"zh-CN")

3. 更新文化信息 :设置Thread.CurrentUICulture和Thread.CurrentCulture

4. 重新加载文本 :调用LoadLocalizedTexts方法,重新从资源文件中获取文本


4. 数据绑定与更新机制

- ViewModel属性 :使用ObservableProperty特性标记需要绑定的属性(如SaveButtonText、WelcomeMessage)

- 自动通知 :当这些属性值变化时,会自动通知UI更新

- 绑定方式 :UI元素通过{Binding PropertyName}绑定到ViewModel的属性


 5. 关键技术点

- 依赖注入 :MainViewModel通过构造函数注入LocalizationManager,实现了松耦合

- 资源查找 :ResourceManager会根据当前的CultureInfo自动查找对应的资源文件

- 属性变更通知 :使用CommunityToolkit.Mvvm的ObservableProperty特性,简化了属性变更通知的实现

这种实现方式的优点是:


- 集中管理多语言资源

- 支持运行时动态切换语言

- 代码结构清晰,易于维护

- 利用了WPF的数据绑定机制,减少了手动UI更新的代码



发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«    2026年2月    »
1
2345678
9101112131415
16171819202122
232425262728
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
搜索
最新留言
文章归档
网站收藏
友情链接

Powered By Z-BlogPHP 1.7.3

Copyright www.skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864