يدعم WinUI 3 التدويل بشكل كامل. ومع ذلك، تقتضي الطريقة الأكثر موثوقية حالياً إعادة تشغيل التطبيق بعد تبديل اللغة لضمان عرض سليم. ورغم إمكانية تحديث لغة الواجهة ديناميكياً دون إعادة تشغيل من الناحية الفنية، إلا أن التنفيذ سيصبح معقداً للغاية. لقد قضيت وقتاً طويلاً في استكشاف الأخطاء وإصلاحها، وواجهت مرات عديدة نصوصاً معطلة أو تعطل التطبيق بعد تغيير اللغة. بعد تجارب وتصليحات متعددة، توصلت إلى سير عمل متين لتطبيق التدويل على WinUI 3، وسأقوم بشرحه بالتفصيل أدناه.
أولاً، أضف منطق تهيئة اللغة في الكود الخلفي لملف App.xaml.cs. إذا لم يختار المستخدم لغة مخصصة، سيستخدم التطبيق اللغة الافتراضية لنظام التشغيل. وإذا لم تكن لغة النظام ضمن قائمة اللغات المدعومة، سيعود التطبيق إلى اللغة الإنجليزية.
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 language: PHP (php)
لا يزال بالإمكان تحسين هذا الإعداد. للحفاظ على نظافة الكود، لا تقم بكتابة قائمة اللغات المدعومة بشكل ثابت هنا. بدلاً من ذلك، قم بتجميعها داخل فئة مساعدة ثابتة، لتتمكن من استخدام نفس القائمة في أي مكان تحتاج فيه إلى تعديل إعدادات اللغة.
public class Languages
{
public static List<string> supportLangs = new() { "zh-CN", "en-US", "th-TH" };
}Code language: PHP (php)
الدور الأساسي لكتلة الكود أعلاه هو ضبط لغة التطبيق عند بدء التشغيل: قم أولاً بتحميل تفضيلات اللغة المحفوظة للمستخدم، واستخدم لغة النظام في حالة عدم وجود إعدادات مخصصة، ثم اعتمد اللغة الإنجليزية كخيار احتياطي نهائي.
إنشاء صفحة مخصصة لتبديل اللغات
نحتاج إلى واجهة مخصصة لتمكين المستخدمين من تغيير لغة العرض، لذلك قمت بإنشاء صفحة مستقلة مخصصة لإعدادات اللغة.
<?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 language: HTML, XML (xml)
يليه كود C# المقابل للواجهة الخلفية:
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 language: HTML, XML (xml)
في كل مرة يقوم المستخدم بحفظ تفضيل لغة جديد، نطلب منه إعادة تشغيل التطبيق لضمان تحديث جميع نصوص الواجهة بالكامل.
ينقسم تنفيذ التعريب في WinUI 3 إلى قسمين منفصلين: العلامات داخل ملفات XAML، وقراءة النصوص ضمن كود C# الخلفي.
بالنسبة لعناصر XAML، استخدم السمة x:Uid كما في المثال التالي:
<TextBlock x:Uid="Txt_LangTip" FontSize="22"/>Code language: HTML, XML (xml)
بعد ذلك، قم بتهيئة هيكل مجلدات موارد التعريب: أنشئ مجلدًا رئيسيًا باسم Strings داخل المشروع، ثم أضف مجلدات فرعية تحمل رموز الثقافة المختلفة، مثل en-US للغة الإنجليزية الأمريكية. داخل كل مجلد لغة، أضف ملف Resources.resw يحتوي على أزواج المفتاح والقيمة للترجمات.
<data name="Btn_Save.Content" xml:space="preserve">
<value>حفظ</value>
</data>Code language: HTML, XML (xml)
الحقل name يعمل كمفتاح للبحث. اللاحقة .Content تشير إلى خاصية عنصر التحكم المستهدف. يتم تعريف العنصر Txt_LangTip المذكور سابقًا كما يلي:
<data name="Txt_LangTip.Text" xml:space="preserve"><value>اختر لغة التطبيق</value></data>Code language: HTML, XML (xml)
نضيف .Text هنا لأننا نستهدف خاصية Text الخاصة بعنصر TextBlock تحديدًا.
بالنسبة للنصوص الديناميكية داخل كود C#، قم أولاً بإنشاء مثيل من ResourceLoader:
private readonly ResourceLoader _resLoader;
public LanguageSettingPage()
{
InitializeComponent();
_resLoader = new ResourceLoader();Code language: PHP (php)
بعد الانتهاء من التهيئة، يمكنك استرداد السلاسل المعربة في أي مكان باستخدام الدالة GetString:
Title = _resLoader.GetString("Dlg_LangChange_Title"),Code language: JavaScript (javascript)
