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 文件指定与您的视图模型相同的名称。它应该是一个嵌入式资源,这很重要,没有自定义工具: