Winui3支持国际化的,但是目前最好的方案是每次切换语言后,需要重启,才能获得最好体验,虽然也可以实现不刷新更新UI的语言,但是估计可能会麻烦很多。作者就遇到过这个问题,摸索了很久,不是切换语言后,刷新语言没切换,或者出现错误。反正折腾了很久,最终才模式出来一种合理的Winui3的国际化思路。下面分享给大家。
首先是在你的项目中的App.xmal 的后台cs中增加语言设置,(如果用户没有设置语言,默认是读取操作系统的语言,如果程序不支持这种语言,则默认是英语)
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
const string LangSettingKey = "AppLanguageCode";
// 项目支持的全部语言(简化标签)
List<string> supportLangs = new() { "zh-CN", "en-US", "th-TH" };
string finalLang = "en-US"; // 默认值
try
{
var localSetting = ApplicationData.Current.LocalSettings;
// ① 存在本地配置,直接使用
if (localSetting.Values.TryGetValue(LangSettingKey, out var savedVal))
{
finalLang = NormalizeLang(savedVal?.ToString() ?? "");
}
else
{
// ② 无配置:取系统第一个首选语言
string sysLang = ApplicationLanguages.Languages.FirstOrDefault() ?? "";
sysLang = NormalizeLang(sysLang);
// ③ 系统语言在支持列表则用它,不在默认英文
finalLang = supportLangs.Contains(sysLang) ? sysLang : "en-US";
}
}
catch
{
// 未打包运行时 ApplicationData 不可用,忽略
}
ApplicationLanguages.PrimaryLanguageOverride = finalLang;
_window = new MainWindow();
_window.Activate();
}
/// <summary>
/// 语言代码标准化:把系统返回的 zh-Hans-CN 映射到 zh-CN
/// </summary>
private static string NormalizeLang(string lang)
{
if (string.IsNullOrEmpty(lang)) return lang;
return lang switch
{
"zh-Hans-CN" => "zh-CN",
"zh-Hant-TW" => "zh-TW", // 如果以后支持繁体
_ => lang
};
}
这里程序,还不是最好的,读者可以自行修改,比如支持的语言,可以用另外一个类来存储,否则在切换的地方又需要配置,可以用一个公共的静态类来存储,支持的语言,其他所有需要地方调用就可以,例如:
public class Languages
{
public static List<string> supportLangs = new() { "zh-CN", "en-US", "th-TH" };
}
以上的函数的目的就是启动程序的时候,初始化语言,默认先读取用户配置的,没有就跟随系统,再没有就英语。
下面是切换语言的页面
我们还需要有一个地方,来允许用户切换语言,我创建了一个page页面,打开这个page页面,就可以切换语言了。
<?xml version="1.0" encoding="utf-8"?>
<Page
x:Class="ThaiTong.Pages.LanguageSettingPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ThaiTong.Pages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<StackPanel Padding="20" Spacing="24">
<TextBlock x:Uid="Txt_LangTip" FontSize="22"/>
<ComboBox x:Name="cbLangSelect" Width="320" Height="40" CornerRadius="6">
<ComboBoxItem Tag="zh-CN" Content="简体中文"/>
<ComboBoxItem Tag="en-US" Content="English"/>
<ComboBoxItem Tag="th-TH" Content="ภาษาไทย"/>
</ComboBox>
<StackPanel Orientation="Horizontal" Spacing="12">
<Button x:Name="btnSave" x:Uid="Btn_Save" Content="Save" Click="BtnSave_Click" Width="120" Height="38" CornerRadius="5"/>
</StackPanel>
<TextBlock Foreground="Gray" Text="Note: After saving, page will refresh to apply language."/>
</StackPanel>
</Page>
后台代码
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.Windows.ApplicationModel.Resources;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using ThaiTong.Common;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Globalization;
using Windows.Storage;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace ThaiTong.Pages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class LanguageSettingPage : Page
{
private const string LangSettingKey = "AppLanguageCode";
private string _currentLang;
private readonly ResourceLoader _resLoader;
public LanguageSettingPage()
{
InitializeComponent();
_resLoader = new ResourceLoader();
var setting = ApplicationData.Current.LocalSettings;
if (setting.Values.TryGetValue(LangSettingKey, out var saveLang))
{
_currentLang = saveLang.ToString();
}
else
{
string sysLang = ApplicationLanguages.Languages.FirstOrDefault() ?? "";
_currentLang = Languages.supportLangs.Contains(sysLang) ? sysLang : "en-US";
}
//下拉框选中当前语言
foreach (var item in cbLangSelect.Items)
{
if (item is ComboBoxItem cbi && cbi.Tag.ToString() == _currentLang)
{
cbLangSelect.SelectedItem = item;
break;
}
}
}
//保存语言
private async void BtnSave_Click(object sender, RoutedEventArgs e)
{
if (cbLangSelect.SelectedItem is not ComboBoxItem selectItem) return;
string newLang = selectItem.Tag.ToString();
if (_currentLang == newLang) return;
ApplicationData.Current.LocalSettings.Values[LangSettingKey] = newLang;
_currentLang = newLang;
ApplicationLanguages.PrimaryLanguageOverride = newLang;
// 从resw取多语言文本
ContentDialog tipDialog = new ContentDialog()
{
XamlRoot = this.XamlRoot,
Title = _resLoader.GetString("Dlg_LangChange_Title"),
Content = _resLoader.GetString("Dlg_LangChange_Content"),
CloseButtonText = _resLoader.GetString("Dlg_LangChange_BtnOk")
};
await tipDialog.ShowAsync();
}
}
}
每次切换语言,提示用户要重启程序,才能获得更新。
在winui3中,国际化的方式,分两种,一种是xaml页面,一种是cs代码
对于xaml页面,可以使用x:Uid ,类似这样
<TextBlock x:Uid="Txt_LangTip" FontSize="22"/>
然后你还需要添加语言国际化资源文件,在你项目中创建一个Strings的目录,然后里面每种语言一个文件夹,例如en-US,就是美国英语,然后每个文件交接中创建一个Resources.resw 文件,每个文件里面配置语言的key-value
<data name="Btn_Save.Content" xml:space="preserve">
<value>Save</value>
</data>
name就是key 。这里.Content是xaml中用的 例如上面的Txt_LangTip 就要这样配置
<data name="Txt_LangTip.Text" xml:space="preserve"><value>Select Application Language</value></data>
为什么要带.Text呢 因为要设置但是TextBlock 中的Text这个属性,所以需要带上.属性。
而对于后台代码,只需要 初始化一个ResourceLoader
private readonly ResourceLoader _resLoader;
public LanguageSettingPage()
{
InitializeComponent();
_resLoader = new ResourceLoader();
然后,在需要的地方,就可以通过GetString的方式调用了
Title = _resLoader.GetString("Dlg_LangChange_Title"),
