Wu Xiuheng
Wu Xiuheng

Reputation: 83

How to Change Application Language at Runtime?

WinUI3 has surprisingly few documentation, and I can't even find how to switch the display language when the app is running

Back to the question, I created multiple languages' resource files, but I don't know how to let users choose the language they want to display.

In MainWindow.xaml

<ComboBox x:Name="LanguangeMode" SelectionChanged="Language_SelectionChanged">
    <ComboBoxItem Content="English"/>
    <ComboBoxItem Content="Simplified Chinese"/>
</ComboBox>

And in MainWindow.xaml.cs

private void Language_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var comboBox = sender as ComboBox;
    var selectedIndex = comboBox.SelectedIndex;

    switch (selectedIndex)
    {
        case 0:
            // Change language to English
            break;
        case 1:
            // Change language to Simplified Chinese
            break;
    }
}

Upvotes: 2

Views: 933

Answers (1)

Andrew KeepCoding
Andrew KeepCoding

Reputation: 13666

This is a minimal example that demonstrates localization. (I also have a sample app repo and its video.)

  1. Create a Strings folder in your project.
  2. Inside the Strings folder, add folders for each language you want to support. You should name each language folder with its corresponding BCP-47 language tag. I use this page as reference for language tags.
  3. Create a resource file named Resources.resw in each language folder.
  4. Populate each resource files with localizations.
  5. Use x:Uid to target controls in XAML or the GetString method from ResourceLoader for localization in C# code.
  • Strings
    • en-us
      • Resources.resw
        • Name: LocalizedButton.Content / Value: Click this
        • Name: en-US / Value: English (United States)
        • Name: es-ES / Value: Spanish (Spain)
    • es-ES
      • Resources.resw
        • Name: LocalizedButton.Content / Value: Haga clic
        • Name: en-US / Value: Inglés (Estados Unidos)
        • Name: es-ES / Value: Español (España)

MainWindow.xaml

<Window
    x:Class="SwitchingLanguageExample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:SwitchingLanguageExample"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid RowDefinitions="Auto,Auto">
        <ComboBox
            Grid.Row="0"
            ItemsSource="{x:Bind LanguageItems, Mode=OneWay}"
            Loaded="ComboBox_Loaded"
            SelectionChanged="ComboBox_SelectionChanged">
            <ComboBox.ItemTemplate>
                <DataTemplate x:DataType="local:LanguageItem">
                    <TextBlock Text="{x:Bind DisplayName}" />
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <!--  You need to set the x:Uid to target a control.  -->
        <Button
            x:Uid="LocalizedButton"
            Grid.Row="1" />
    </Grid>

</Window>

MainWindow.cs.xaml

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Windows.ApplicationModel.Resources;
using System.Collections.ObjectModel;
using System.Linq;
using Windows.Globalization;

namespace SwitchingLanguageExample;

public class LanguageItem
{
    public LanguageItem(string languageTag, string displayName)
    {
        LanguageTag = languageTag;
        DisplayName = displayName;
    }

    public string LanguageTag { get; }

    public string DisplayName { get; }
}

public sealed partial class MainWindow : Window
{
    private ResourceManager resourceManager = new();

    private ResourceLoader resourceLoader = new();

    public MainWindow()
    {
        this.InitializeComponent();

        LanguageItems.Add(new LanguageItem("en-US", this.resourceLoader.GetString("en-US")));
        LanguageItems.Add(new LanguageItem("es-ES", this.resourceLoader.GetString("es-ES")));
    }

    public ObservableCollection<LanguageItem> LanguageItems { get; } = new();

    private void ComboBox_Loaded(object sender, RoutedEventArgs e)
    {
        if (sender is not ComboBox languageTagComboBox)
        {
            return;
        }

        if (LanguageItems
            .Where(x => x.LanguageTag == ApplicationLanguages.PrimaryLanguageOverride)
            .FirstOrDefault() is LanguageItem currentLanguageItem)
        {

            languageTagComboBox.SelectedValue = currentLanguageItem;
        }
    }

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (sender is not ComboBox languageTagComboBox ||
            languageTagComboBox.SelectedValue is not LanguageItem selectedLanguageItem)
        {
            return;
        }

        ApplicationLanguages.PrimaryLanguageOverride = selectedLanguageItem.LanguageTag;
        
        ResourceContext resourceContext = this.resourceManager.CreateResourceContext();
        resourceContext.QualifierValues["Language"] = selectedLanguageItem.LanguageTag;
    }
}

NOTE

Unfortunately, you need to restart the app to see the change of languages. Also, this doesn't work on unpackaged (non-packaged) apps.

That's why I created the WinUI3Localizer. Give it a try. Hope it helps!

  • Switch languages without restarting the app
  • You/users can edit localized strings even after deployment
  • You/users can add new languages even after deployment
  • Use standard Resources.resw

Upvotes: 6

Related Questions