Files
sharp-basic/examples/05-Localization/README.md
T

279 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 05 - 国际化(i18n)示例
演示如何使用 Sharp.Wpf 的国际化功能实现多语言支持,包括运行时切换语言、资源文件管理等。
## 🎯 学习目标
- 使用 `ILocalizationService` 实现多语言
- 在 XAML 中使用 `{loc:Localize}` 绑定本地化字符串
- 运行时动态切换语言
- 管理资源文件(.resx)
- 格式化带参数的本地化字符串
## 📦 使用的模块
- **Sharp.Wpf** - ILocalizationService, LocalizeExtension
## 🚀 快速运行
```bash
cd examples/05-Localization
dotnet run
```
## 📝 核心代码讲解
### 1. 创建资源文件
```
Resources/
├── Strings.resx # 默认语言(中文)
├── Strings.en-US.resx # 英文
└── Strings.ja-JP.resx # 日文(可选)
```
**Strings.resx** (中文):
```xml
<data name="Welcome" xml:space="preserve">
<value>欢迎使用 Sharp 框架</value>
</data>
<data name="Username" xml:space="preserve">
<value>用户名</value>
</data>
<data name="Password" xml:space="preserve">
<value>密码</value>
</data>
<data name="Login" xml:space="preserve">
<value>登录</value>
</data>
<data name="WelcomeUser" xml:space="preserve">
<value>欢迎, {0}!</value>
</data>
```
**Strings.en-US.resx** (英文):
```xml
<data name="Welcome" xml:space="preserve">
<value>Welcome to Sharp Framework</value>
</data>
<data name="Username" xml:space="preserve">
<value>Username</value>
</data>
<data name="Password" xml:space="preserve">
<value>Password</value>
</data>
<data name="Login" xml:space="preserve">
<value>Login</value>
</data>
<data name="WelcomeUser" xml:space="preserve">
<value>Welcome, {0}!</value>
</data>
```
### 2. App.xaml.cs - 注册国际化服务
```csharp
using System.Globalization;
using System.Resources;
using Wpf.Localization;
protected override void OnStartup(StartupEventArgs e)
{
var services = new ServiceCollection();
services.AddSharpWpf();
// 添加国际化支持
var resourceManager = new ResourceManager(
"LocalizationExample.Resources.Strings", // 资源文件的完整命名空间
Assembly.GetExecutingAssembly());
services.AddLocalization(
resourceManager,
new CultureInfo("zh-CN"), // 中文
new CultureInfo("en-US"), // 英文
new CultureInfo("ja-JP") // 日文
);
services.AddViewModel<MainViewModel>();
var provider = services.BuildServiceProvider();
var mainWindow = provider.GetRequiredService<MainWindow>();
mainWindow.Show();
}
```
### 3. MainViewModel.cs - 语言切换
```csharp
using Wpf.Localization;
public class MainViewModel : ViewModelBase
{
private readonly ILocalizationService _localization;
private readonly IDialogService _dialogService;
public ILocalizationService Localization => _localization;
public List<CultureInfo> AvailableLanguages { get; }
public CultureInfo CurrentLanguage
{
get => _localization.CurrentCulture;
set
{
_localization.ChangeCulture(value);
OnPropertyChanged();
}
}
public ICommand ChangeLanguageCommand { get; }
public ICommand ShowGreetingCommand { get; }
public MainViewModel(
ILocalizationService localization,
IDialogService dialogService)
{
_localization = localization;
_dialogService = dialogService;
AvailableLanguages = localization.GetSupportedCultures().ToList();
// 监听语言变化
_localization.CultureChanged += (s, culture) =>
{
_dialogService.ShowMessage(
$"语言已切换到: {culture.NativeName}",
"提示");
};
ChangeLanguageCommand = new RelayCommand<CultureInfo>(culture =>
{
if (culture != null)
{
CurrentLanguage = culture;
}
});
ShowGreetingCommand = new RelayCommand(() =>
{
// 使用格式化字符串
var message = _localization.GetString("WelcomeUser", "张三");
_dialogService.ShowMessage(message, "问候");
});
}
}
```
### 4. MainWindow.xaml - 使用本地化绑定
```xml
<Window x:Class="LocalizationExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc="clr-namespace:Wpf.Localization;assembly=Sharp.Wpf"
Title="国际化示例" Height="400" Width="500">
<StackPanel Margin="20">
<!-- 方式1: 使用 LocalizeExtension(推荐) -->
<TextBlock Text="{loc:Localize Welcome}" FontSize="24" FontWeight="Bold"/>
<!-- 语言选择 -->
<StackPanel Orientation="Horizontal" Margin="0,20,0,0">
<TextBlock Text="选择语言:" VerticalAlignment="Center" Margin="0,0,10,0"/>
<ComboBox ItemsSource="{Binding AvailableLanguages}"
SelectedItem="{Binding CurrentLanguage}"
DisplayMemberPath="NativeName"
Width="150"/>
</StackPanel>
<!-- 登录表单 -->
<StackPanel Margin="0,30,0,0">
<!-- 用户名 -->
<TextBlock Text="{loc:Localize Username}"/>
<TextBox Margin="0,5,0,15"/>
<!-- 密码 -->
<TextBlock Text="{loc:Localize Password}"/>
<PasswordBox Margin="0,5,0,15"/>
<!-- 登录按钮 -->
<Button Content="{loc:Localize Login}"
Height="35" FontSize="14"/>
</StackPanel>
<!-- 方式2: 直接绑定 Localization 服务 -->
<StackPanel Margin="0,30,0,0">
<TextBlock Text="{Binding Localization[Welcome]}" FontStyle="Italic"/>
<TextBlock Text="{Binding Localization[Username]}" Margin="0,5,0,0"/>
</StackPanel>
<!-- 测试格式化字符串 -->
<Button Content="显示问候" Command="{Binding ShowGreetingCommand}" Margin="0,20,0,0"/>
</StackPanel>
</Window>
```
### 5. 在代码中使用本地化
```csharp
// 方式1: 通过服务获取
var welcomeText = _localization.GetString("Welcome");
// 方式2: 带格式化参数
var greeting = _localization.GetString("WelcomeUser", username);
// 方式3: 索引器(用于绑定)
var password = _localization["Password"];
```
## 🎓 练习建议
### 练习1:添加更多语言
添加法语(fr-FR)或德语(de-DE)资源文件。
### 练习2:保存语言偏好
将用户选择的语言保存到配置文件,下次启动时自动加载。
### 练习3:动态加载资源
实现从外部 JSON 文件加载翻译资源(而非编译进程序)。
### 练习4:翻译进度显示
显示每种语言的翻译完成度(如:英文 95%,日文 60%)。
## 💡 常见问题
**Q: 资源文件修改后不生效?**
A: 确保:
1. 资源文件的"生成操作"设为"嵌入的资源"
2. 重新生成项目(Clean + Rebuild)
**Q: 如何支持从右到左(RTL)语言?**
A: 监听 CultureChanged 事件,设置 `FlowDirection`:
```csharp
_localization.CultureChanged += (s, culture) => {
if (culture.TextInfo.IsRightToLeft) {
Application.Current.MainWindow.FlowDirection = FlowDirection.RightToLeft;
}
};
```
**Q: 能否热重载资源文件?**
A: Sharp.Wpf 当前使用编译时嵌入资源,不支持运行时重载。可以使用外部 JSON 文件实现热重载。
**Q: 如何处理复数形式?**
A: 使用不同的资源键或使用占位符:
```
"{Count} items" → "{0} 个项目"
```
## 📚 延伸阅读
- [.NET 资源文件](https://learn.microsoft.com/zh-cn/dotnet/core/extensions/resources)
- [CultureInfo 类](https://learn.microsoft.com/zh-cn/dotnet/api/system.globalization.cultureinfo)
- [WPF 本地化](https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/globalization-for-wpf)
- 下一个示例:[06-Theming](../06-Theming/README.md)
---
**构建面向全球用户的应用!** 🌍