WinUI 3 运行时本地化
WinUI 3 runtime localization
我正在开发 WinUI 3 应用程序,目前遇到本地化问题。尽管我为不同的文化编写了单独的 resw 资源文件并使用 x:Uid
进行了本地化,但我找不到在应用程序运行时更改语言的方法。
设置Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride
仅适用于设置启动语言。
甚至可以在 WinUI 3 中进行运行时本地化吗?
原答案:
我认为您的方向是正确的。如果您尝试在运行时更改语言,请调用将 Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride
设置为新语言“字符串”的方法。但在那之后,你还必须 reload your Page so that the new language takes effect.
private void ReloadLanguage(string languageOverride)
{
// Change the app language
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = languageOverride;
// Be sure to clear the Frame stack so that cached Pages are removed, otherwise they will have the old language.
Frame.BackStack.Clear();
// Reload the page that you want to have the new language
Frame.Navigate(typeof(MainPage));
}
-或-
你必须 call your ResourceLoader 为你 need/want 的 UI 个组件一次刷新一个。
private void RefreshUIText()
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
}
更新答案:
根据 Microsoft online documentation,他们建议您随时更改语言以“从默认 ResourceContext 重新加载字符串”。我知道这并不理想,但它似乎有效。
我得到了下面的示例解决方案:
MainWindow.xaml
<Grid>
<Frame x:Name="MainFrame"/>
</Grid>
MainWindow.xaml.cs
public MainWindow()
{
this.InitializeComponent();
MainFrame.Navigate(typeof(MainPage));
}
MainPage.xaml
<Grid>
<StackPanel>
<TextBlock x:Uid="Greeting" x:Name="Greeting" Text="" Margin="15"/>
<TextBlock x:Uid="Farewell" x:Name="Farewell" Text="" Margin="15"/>
<Button x:Name="SelectLanguageButton" Click="SelectLanguageButton_Click" Content="Select Language" Margin="15"/>
</StackPanel>
</Grid>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
RefreshUIText();
}
private void SelectLanguageButton_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(LanguagePage));
}
private void RefreshUIText()
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForViewIndependentUse();
this.Greeting.Text = resourceLoader.GetString("Greeting/Text");
this.Farewell.Text = resourceLoader.GetString("Farewell/Text");
}
}
LanguagePage.xaml
<Grid>
<StackPanel>
<Button x:Name="EnglishButton" Click="EnglishButton_Click" Content="English" Margin="15"/>
<Button x:Name="FrenchButton" Click="FrenchButton_Click" Content="French" Margin="15"/>
</StackPanel>
</Grid>
LanguagePage.xaml.cs
public sealed partial class LanguagePage : Page
{
public LanguagePage()
{
this.InitializeComponent();
}
private void EnglishButton_Click(object sender, RoutedEventArgs e)
{
ReloadLanguage("en");
}
private void FrenchButton_Click(object sender, RoutedEventArgs e)
{
ReloadLanguage("fr");
}
private void ReloadLanguage(string languageOverride)
{
// Change the app language
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = languageOverride;
// Be sure to clear the Frame stack so that cached Pages are removed, otherwise they will have the old language.
Frame.BackStack.Clear();
// Reload the page that you want to have the new language
Frame.Navigate(typeof(MainPage));
}
}
资源文件和内容,解决方案资源管理器
另外记得在 Package.appxmanifest 文件中添加你的语言声明
我创建了新项目 - 空白应用程序,与 WAP 打包(桌面中的 WinUI 3) 带有最新的项目模板,带有 VS 扩展 Windows APP SDK C# VS2019。正如您所注意到的——我使用的是 VS 2019,社区版。我在下面附上一个项目的 csproj 配置。
主页 window 中有一个导航到主页的框架。主页上只有一个按钮,点击后会转到 LanguagePage。
目标是更改语言、清除导航堆栈并导航回主页。然而,SetAppLanguage
中的各种场景并没有产生想要的结果。
请查看 https://www.py4u.net/discuss/731870 - 尝试了所有方案,对 GUI 没有影响。
然而 Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView();
正在抛出 COMException:'Resource Contexts may not be created on threads that do not have a CoreWindow. (0x80073B27)'
我在这个问题上花了很多时间。这是我真诚的建议:不要试图本地化您的视图。此外,不要尝试在运行时处理对语言的更改。没有人这样做,您永远不会看到投资的投资回报率。
在视图模型中进行所有本地化,并使用 .NET 的 DI 中内置的 StringLocalizer class。首先将字符串本地化器添加到 DI:
this.serviceProvider = new ServiceCollection()
.AddLogging()
.AddLocalization();
然后,在您的 .NET 或 .Net Standard 库中,在您的视图模型中,添加以下初始化:
private readonly IStringLocalizer<LandingViewModel> stringLocalizer;
public MyViewModel(IStringLocalizer<MyViewModel> stringLocalizer)
{
this.stringLocalizer = stringLocalizer;
}
现在,如果您有一些想要显示的文本,比如在按钮上,您将拥有:
public string SignUpText => this.stringLocalizer["SignUp"];
在 XAML 中,您将拥有:
<Button Content="{x:Bind ViewModel.SignUpText}"/>
最后,为 RESX 文件指定与您的视图模型相同的名称。它应该是一个嵌入式资源,这很重要,没有自定义工具:
我正在开发 WinUI 3 应用程序,目前遇到本地化问题。尽管我为不同的文化编写了单独的 resw 资源文件并使用 x:Uid
进行了本地化,但我找不到在应用程序运行时更改语言的方法。
设置Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride
仅适用于设置启动语言。
甚至可以在 WinUI 3 中进行运行时本地化吗?
原答案:
我认为您的方向是正确的。如果您尝试在运行时更改语言,请调用将 Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride
设置为新语言“字符串”的方法。但在那之后,你还必须 reload your Page so that the new language takes effect.
private void ReloadLanguage(string languageOverride)
{
// Change the app language
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = languageOverride;
// Be sure to clear the Frame stack so that cached Pages are removed, otherwise they will have the old language.
Frame.BackStack.Clear();
// Reload the page that you want to have the new language
Frame.Navigate(typeof(MainPage));
}
-或-
你必须 call your ResourceLoader 为你 need/want 的 UI 个组件一次刷新一个。
private void RefreshUIText()
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
}
更新答案:
根据 Microsoft online documentation,他们建议您随时更改语言以“从默认 ResourceContext 重新加载字符串”。我知道这并不理想,但它似乎有效。
我得到了下面的示例解决方案:
MainWindow.xaml
<Grid>
<Frame x:Name="MainFrame"/>
</Grid>
MainWindow.xaml.cs
public MainWindow()
{
this.InitializeComponent();
MainFrame.Navigate(typeof(MainPage));
}
MainPage.xaml
<Grid>
<StackPanel>
<TextBlock x:Uid="Greeting" x:Name="Greeting" Text="" Margin="15"/>
<TextBlock x:Uid="Farewell" x:Name="Farewell" Text="" Margin="15"/>
<Button x:Name="SelectLanguageButton" Click="SelectLanguageButton_Click" Content="Select Language" Margin="15"/>
</StackPanel>
</Grid>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
RefreshUIText();
}
private void SelectLanguageButton_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(LanguagePage));
}
private void RefreshUIText()
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForViewIndependentUse();
this.Greeting.Text = resourceLoader.GetString("Greeting/Text");
this.Farewell.Text = resourceLoader.GetString("Farewell/Text");
}
}
LanguagePage.xaml
<Grid>
<StackPanel>
<Button x:Name="EnglishButton" Click="EnglishButton_Click" Content="English" Margin="15"/>
<Button x:Name="FrenchButton" Click="FrenchButton_Click" Content="French" Margin="15"/>
</StackPanel>
</Grid>
LanguagePage.xaml.cs
public sealed partial class LanguagePage : Page
{
public LanguagePage()
{
this.InitializeComponent();
}
private void EnglishButton_Click(object sender, RoutedEventArgs e)
{
ReloadLanguage("en");
}
private void FrenchButton_Click(object sender, RoutedEventArgs e)
{
ReloadLanguage("fr");
}
private void ReloadLanguage(string languageOverride)
{
// Change the app language
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = languageOverride;
// Be sure to clear the Frame stack so that cached Pages are removed, otherwise they will have the old language.
Frame.BackStack.Clear();
// Reload the page that you want to have the new language
Frame.Navigate(typeof(MainPage));
}
}
资源文件和内容,解决方案资源管理器
另外记得在 Package.appxmanifest 文件中添加你的语言声明
我创建了新项目 - 空白应用程序,与 WAP 打包(桌面中的 WinUI 3) 带有最新的项目模板,带有 VS 扩展 Windows APP SDK C# VS2019。正如您所注意到的——我使用的是 VS 2019,社区版。我在下面附上一个项目的 csproj 配置。
主页 window 中有一个导航到主页的框架。主页上只有一个按钮,点击后会转到 LanguagePage。
目标是更改语言、清除导航堆栈并导航回主页。然而,SetAppLanguage
中的各种场景并没有产生想要的结果。
请查看 https://www.py4u.net/discuss/731870 - 尝试了所有方案,对 GUI 没有影响。
然而 Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView();
正在抛出 COMException:'Resource Contexts may not be created on threads that do not have a CoreWindow. (0x80073B27)'
我在这个问题上花了很多时间。这是我真诚的建议:不要试图本地化您的视图。此外,不要尝试在运行时处理对语言的更改。没有人这样做,您永远不会看到投资的投资回报率。
在视图模型中进行所有本地化,并使用 .NET 的 DI 中内置的 StringLocalizer class。首先将字符串本地化器添加到 DI:
this.serviceProvider = new ServiceCollection()
.AddLogging()
.AddLocalization();
然后,在您的 .NET 或 .Net Standard 库中,在您的视图模型中,添加以下初始化:
private readonly IStringLocalizer<LandingViewModel> stringLocalizer;
public MyViewModel(IStringLocalizer<MyViewModel> stringLocalizer)
{
this.stringLocalizer = stringLocalizer;
}
现在,如果您有一些想要显示的文本,比如在按钮上,您将拥有:
public string SignUpText => this.stringLocalizer["SignUp"];
在 XAML 中,您将拥有:
<Button Content="{x:Bind ViewModel.SignUpText}"/>
最后,为 RESX 文件指定与您的视图模型相同的名称。它应该是一个嵌入式资源,这很重要,没有自定义工具: