8.1 KiB
8.1 KiB
多语言支持快速开始 | Localization Quick Start
概述 | Overview
XplorePlane 多语言支持系统基于 .NET 原生 Resx 资源文件实现,与 Prism MVVM 架构无缝集成。系统支持简体中文(zh-CN)、繁体中文(zh-TW)和美式英语(en-US)三种语言。
核心特性 | Key Features
- ✅ 基于 .NET Resx 资源文件,编译时类型安全
- ✅ 简洁的 XAML 标记扩展语法
- ✅ 完整的 ViewModel 集成支持
- ✅ 语言设置持久化到 App.config
- ✅ 跨模块事件通知机制
- ✅ 健壮的错误处理和回退机制
- ✅ 多资源源 Fallback Chain 机制,支持模块级资源注册
快速开始 | Quick Start
1. 在 XAML 中使用本地化资源 | Using Localization in XAML
基础用法 | Basic Usage
<Window x:Class="XplorePlane.App.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc="clr-namespace:XplorePlane.Common.Localization.Extensions;assembly=XP.Common"
Title="{loc:Localization Key=App_Title}">
<Grid>
<!-- 按钮文本本地化 | Localized button text -->
<Button Content="{loc:Localization Key=Button_OK}" />
<!-- 标签文本本地化 | Localized label text -->
<Label Content="{loc:Localization Key=Settings_Language}" />
<!-- 菜单项本地化 | Localized menu item -->
<MenuItem Header="{loc:Localization Key=Menu_File}" />
</Grid>
</Window>
命名空间声明 | Namespace Declaration
在 XAML 文件顶部添加命名空间引用:
xmlns:loc="clr-namespace:XplorePlane.Common.Localization.Extensions;assembly=XP.Common"
语法说明 | Syntax Explanation
{loc:Localization Key=ResourceKey}- 完整语法{loc:Localization App_Title}- 简化语法(Key 可省略)- 资源键不存在时,显示键名本身(便于调试)
2. 在 C# 代码中使用静态帮助类 | Using Static Helper in C# Code
适用于不方便依赖注入的场景(静态方法、工具类等)。
using XP.Common.Localization;
// 基本用法 | Basic usage
var title = LocalizationHelper.Get("App_Title");
// 带格式化参数 | With format arguments
var errorMsg = LocalizationHelper.Get("Settings_Language_SwitchFailed", ex.Message);
- 在 ViewModel / Service 中优先使用
ILocalizationService(可测试、可 Mock) - 在静态方法、工具类、或不方便注入的地方使用
LocalizationHelper - 两者读取同一套 Resx 资源文件,结果一致
V1.4.1.1 变更:
LocalizationHelper新增Initialize(ILocalizationService)方法。初始化后,Get()会优先通过ILocalizationService获取字符串(支持 Fallback Chain);未初始化时仍兼容回退到原始ResourceManager。建议在CommonModule或 App 启动时调用初始化。
// 在 CommonModule 或 App 启动时调用 | Call at CommonModule or App startup
LocalizationHelper.Initialize(localizationService);
3. 在 ViewModel 中使用本地化服务 | Using Localization Service in ViewModel
依赖注入 | Dependency Injection
using XplorePlane.Common.Localization.Interfaces;
using XplorePlane.Common.Localization.Enums;
using Prism.Mvvm;
namespace XplorePlane.App.ViewModels
{
public class MyViewModel : BindableBase
{
private readonly ILocalizationService _localizationService;
private readonly ILoggerService _logger;
public MyViewModel(
ILocalizationService localizationService,
ILoggerService logger)
{
_localizationService = localizationService;
_logger = logger;
}
// 获取本地化字符串 | Get localized string
public string GetWelcomeMessage()
{
return _localizationService.GetString("Welcome_Message");
}
// 获取当前语言 | Get current language
public SupportedLanguage CurrentLanguage => _localizationService.CurrentLanguage;
}
}
动态文本绑定 | Dynamic Text Binding
public class StatusViewModel : BindableBase
{
private readonly ILocalizationService _localizationService;
private string _statusMessage;
public string StatusMessage
{
get => _statusMessage;
set => SetProperty(ref _statusMessage, value);
}
public StatusViewModel(ILocalizationService localizationService)
{
_localizationService = localizationService;
// 订阅语言切换事件 | Subscribe to language changed event
_localizationService.LanguageChanged += OnLanguageChanged;
// 初始化状态消息 | Initialize status message
UpdateStatusMessage();
}
private void OnLanguageChanged(object sender, LanguageChangedEventArgs e)
{
// 语言切换时更新文本 | Update text when language changes
UpdateStatusMessage();
}
private void UpdateStatusMessage()
{
StatusMessage = _localizationService.GetString("Status_Ready");
}
}
数据验证消息本地化 | Localized Validation Messages
public class FormViewModel : BindableBase, IDataErrorInfo
{
private readonly ILocalizationService _localizationService;
private string _username;
public string Username
{
get => _username;
set => SetProperty(ref _username, value);
}
public string this[string columnName]
{
get
{
if (columnName == nameof(Username))
{
if (string.IsNullOrWhiteSpace(Username))
{
return _localizationService.GetString("Validation_UsernameRequired");
}
if (Username.Length < 3)
{
return _localizationService.GetString("Validation_UsernameTooShort");
}
}
return null;
}
}
public string Error => null;
}
4. 多资源源 Fallback Chain | Multi-Source Fallback Chain
V1.1 版本引入了多资源源 Fallback Chain 机制,允许各模块注册自己的 Resx 资源文件。查找资源键时,从最后注册的资源源开始向前遍历,第一个返回非 null 值的即为结果。
架构说明 | Architecture
Fallback Chain(查找顺序从右到左):
[XP.Common (默认)] → [XP.Scan (模块注册)] → [XP.Hardware (模块注册)]
↑ 最高优先级
XP.Common为默认资源源,始终位于 Chain[0],不可注销- 后注册的模块优先级更高
- 单个资源源查找异常时自动跳过,继续遍历下一个
- 全部未找到时返回 key 本身并记录警告日志
注册模块资源源 | Register Module Resource Source
在 Prism 模块的 OnInitialized 中注册:
using System.Resources;
using XP.Common.Localization.Interfaces;
public class ScanModule : IModule
{
private readonly ILocalizationService _localizationService;
public ScanModule(ILocalizationService localizationService)
{
_localizationService = localizationService;
}
public void OnInitialized(IContainerProvider containerProvider)
{
// 注册模块资源源到 Fallback Chain
var resourceManager = new ResourceManager(
"XP.Scan.Resources.Resources",
typeof(ScanModule).Assembly);
_localizationService.RegisterResourceSource("XP.Scan", resourceManager);
}
public void RegisterTypes(IContainerRegistry containerRegistry) { }
}
注销模块资源源 | Unregister Module Resource Source
// 注销指定资源源(不可注销默认的 "XP.Common")
_localizationService.UnregisterResourceSource("XP.Scan");
注意事项 | Notes
- 资源源名称不可重复,重复注册会抛出
InvalidOperationException - 注销
"XP.Common"会抛出InvalidOperationException - 注销不存在的名称会静默忽略并记录警告日志
- 线程安全:内部使用
ReaderWriterLockSlim保护读写操作
版本 | Version: 1.1
最后更新 | Last Updated: 2026-04-01