多语言切换。


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

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更新的代码