Internationalisierungsoptionen für WinUI 3

WinUI 3 unterstützt die Internationalisierung vollständig. Dennoch erfordert die derzeit zuverlässigste Methode einen Neustart der Anwendung nach einem Sprachwechsel, um eine fehlerfreie Anzeige zu gewährleisten. Obwohl eine dynamische Aktualisierung der Oberflächensprache ohne Neustart technisch machbar ist, wird deren Umsetzung äußerst kompliziert. Ich habe viel Zeit mit der Fehlersuche verbracht und bin bei Sprachwechseln immer wieder auf defekte Oberflächentexte oder Abstürze gestoßen. Nach zahlreichen Tests und Korrekturen habe ich einen stabilen Arbeitsablauf für die Internationalisierung unter WinUI 3 erarbeitet, den ich im Folgenden erläutere.

Fügen Sie zunächst die Logik zur Sprachinitialisierung in den Code-Behind von App.xaml.cs ein. Wenn der Benutzer keine benutzerdefinierte Sprache ausgewählt hat, verwendet die Anwendung die Standardsprache des Betriebssystems. Falls die Systemsprache nicht in der Liste der unterstützten Sprachen enthalten ist, wechselt die Anwendung automatisch zu Englisch.

protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    const string LangSettingKey = "AppLanguageCode";
    // All supported language tags of project
    List<string> supportLangs = new() { "zh-CN", "en-US", "th-TH" };
    string finalLang = "en-US"; // Default language

    try
    {
        var localSetting = ApplicationData.Current.LocalSettings;

        // ① Use saved language if local configuration exists
        if (localSetting.Values.TryGetValue(LangSettingKey, out var savedVal))
        {
            finalLang = NormalizeLang(savedVal?.ToString() ?? "");
        }
        else
        {
            // ② No saved config: read system primary preferred language
            string sysLang = ApplicationLanguages.Languages.FirstOrDefault() ?? "";
            sysLang = NormalizeLang(sysLang);

            // ③ Use system language if supported, otherwise fall back to English
            finalLang = supportLangs.Contains(sysLang) ? sysLang : "en-US";
        }
    }
    catch
    {
        // Ignore exception when running unpackaged, ApplicationData unavailable
    }

    ApplicationLanguages.PrimaryLanguageOverride = finalLang;

    _window = new MainWindow();
    _window.Activate();
}

/// <summary>
/// Standardize culture code: map system returned zh-Hans-CN to 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", // For future Traditional Chinese support
        _ => lang
    };
}Code-Sprache: PHP (php)

Diese Konfiguration lässt sich weiter optimieren. Halten Sie den Code übersichtlich, indem Sie die Liste der unterstützten Sprachen nicht hier fest hinterlegen. Lagern Sie sie stattdessen in einer statischen Hilfsklasse aus, sodass Sie dieselbe Liste überall dort verwenden können, wo Spracheinstellungen verwaltet werden müssen.

    public class Languages
    {
        public static List<string> supportLangs = new() { "zh-CN", "en-US", "th-TH" };
    }Code-Sprache: PHP (php)

Der Hauptzweck des obigen Codeblocks ist die Spracheinstellung beim Start der Anwendung: Zuerst wird die gespeicherte Sprachpräferenz des Benutzers geladen, bei fehlenden benutzerdefinierten Einstellungen wird die Systemsprache verwendet und Englisch dient als letzte Ausweichmöglichkeit.

Eigene Seite für den Sprachwechsel erstellen

Benutzer benötigen eine dedizierte Oberfläche zum Ändern der Anzeigesprache. Daher habe ich eine separate Seite erstellt, die ausschließlich für die Spracheinstellungen zuständig ist.

<?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>
Code-Sprache: HTML, XML (xml)

Der zugehörige C#-Code im Hintergrund lautet wie folgt:

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";
            }

            // Pre-select matched language in dropdown list
            foreach (var item in cbLangSelect.Items)
            {
                if (item is ComboBoxItem cbi && cbi.Tag.ToString() == _currentLang)
                {
                    cbLangSelect.SelectedItem = item;
                    break;
                }
            }
        }

        // Save selected language setting
        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;

            // Load localized text from resw resource file
            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();
        }


    }
}
Code-Sprache: HTML, XML (xml)

Jedes Mal, wenn der Benutzer eine neue Spracheinstellung speichert, wird er zum Neustart der Anwendung aufgefordert, damit alle Oberflächentexte vollständig aktualisiert werden.

Die Lokalisierung unter WinUI 3 gliedert sich in zwei separate Bereiche: Markup in XAML-Dateien und Textabfrage im C#-Hintergrundcode.

Verwenden Sie für XAML-Elemente das Attribut x:Uid wie im folgenden Beispiel:

<TextBlock x:Uid="Txt_LangTip" FontSize="22"/>Code-Sprache: HTML, XML (xml)

Richten Sie anschließend die Ordnerstruktur für Lokalisierungsressourcen ein: Erstellen Sie im Projektstamm einen Ordner namens Strings und legen Sie darin Unterordner mit den jeweiligen Kulturkennungen an, beispielsweise en-US für Amerikanisches Englisch. In jedem Sprachordner befindet sich eine Resources.resw-Datei mit Schlüssel-Wert-Paaren für die Übersetzungen.

  <data name="Btn_Save.Content" xml:space="preserve">
      <value>Speichern</value>
  </data>Code-Sprache: HTML, XML (xml)

Das Feld name dient als Suchschlüssel. Der Anhang .Content verweist auf die zugehörige Steuereigenschaft. Der zuvor erwähnte Eintrag Txt_LangTip wird wie folgt definiert:

<data name="Txt_LangTip.Text" xml:space="preserve"><value>Anwendungssprache auswählen</value></data>Code-Sprache: HTML, XML (xml)

Der Zusatz .Text ist erforderlich, da wir gezielt die Text-Eigenschaft des TextBlock-Steuerelements ansprechen.

Für dynamische Texte im C#-Code initialisieren Sie zuerst eine Instanz von ResourceLoader:

 private readonly ResourceLoader _resLoader;

 public LanguageSettingPage()
 {
     InitializeComponent();
     _resLoader = new ResourceLoader();Code-Sprache: PHP (php)

Nach der Initialisierung können Sie lokalisierte Zeichenfolgen überall im Code mit der Methode GetString abrufen:

Title = _resLoader.GetString("Dlg_LangChange_Title"),Code-Sprache: JavaScript (javascript)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert