Rogapp
Как сделать переключение языка в приложение на .NET MAUI
Рабочий код

Локализация в .NET MAUI с динамическим переключением языка

Что делаем?
  • Добавим поддержку нескольких языков с помощью .resx файлов
  • Реализуем класс LocalizationResourceManager
  • Сделаем UI, который реагирует на смену языка
  • Сделаем кнопку для переключения между ru и en
Структура проекта
PersonalApp/
│
├── App.xaml / App.xaml.cs
├── MainPage.xaml / MainPage.xaml.cs
├── MauiProgram.cs
├── Resources/
│   ├── Localization/
│   │   ├── AppResources.resx          ← Английский (по умолчанию)
│   │   └── AppResources.ru.resx       ← Русский
│
└── Localization/
    └── LocalizationResourceManager.cs
.resx файлы — ключи и переводы
Resources/Localization/AppResources.resx (английский):
<?xml version="1.0" encoding="utf-8"?>
<root>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="HelloText" xml:space="preserve">
    <value>Hello, world!</value>
  </data>
  <data name="ButtonText" xml:space="preserve">
    <value>Click me</value>
  </data>
</root>
Resources/Localization/AppResources.ru.resx (русский):
<?xml version="1.0" encoding="utf-8"?>
<root>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="HelloText" xml:space="preserve">
    <value>Привет, мир!</value>
  </data>
  <data name="ButtonText" xml:space="preserve">
    <value>Нажми меня</value>
  </data>
</root>
Не добавляй эти файлы вручную в <ItemGroup>. MAUI уже сам подключает их как EmbeddedResource.
Класс LocalizationResourceManager.cs
Этот синглтон хранит ResourceManager, текущую культуру и нотификацию об изменениях:
csharp
using System.ComponentModel;
using System.Globalization;
using System.Resources;

namespace PersonalApp.Localization;

public class LocalizationResourceManager : INotifyPropertyChanged
{
    public static LocalizationResourceManager Instance { get; } = new();

    public ResourceManager ResourceManager { get; set; }

    public CultureInfo CurrentCulture { get; private set; } = CultureInfo.CurrentUICulture;

    public event PropertyChangedEventHandler PropertyChanged;

    public string this[string key] => ResourceManager?.GetString(key, CurrentCulture) ?? key;

    public void SetCulture(CultureInfo culture)
    {
        CurrentCulture = culture;
        CultureInfo.DefaultThreadCurrentCulture = culture;
        CultureInfo.DefaultThreadCurrentUICulture = culture;

        // Обновим привязки
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
    }
}
Подключение локализации в MauiProgram.cs
Namespace в ResourceManager(...) должен точно совпадать с именем .resx файла.
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using PersonalApp.Localization;
using System.Globalization;
using System.Resources;

namespace PersonalApp
{
    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();

            builder
                .UseMauiApp<App>()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                });

            // Добавляем сервис локализации
            builder.Services.AddSingleton(LocalizationResourceManager.Instance);

            // Указываем .resx-файл (убедись в правильном пути и namespace)
            var resourceManager = new ResourceManager("PersonalApp.Resources.Localization.AppResources", typeof(MauiProgram).Assembly);
            LocalizationResourceManager.Instance.ResourceManager = resourceManager;

            return builder.Build(); // ← должен быть последним!

        }
    }
}
Пример использования:
MainPage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="PersonalApp.MainPage"
             Title="Главная">

    <VerticalStackLayout Padding="20">
        <Label Text="{Binding [HelloText]}"
               FontSize="24"
               HorizontalOptions="Center" />

        <Button Text="{Binding [ButtonText]}"
                HorizontalOptions="Center" />

        <Button Text="Сменить язык"
                Clicked="OnChangeLanguageClicked"
                BackgroundColor="#00CFC5"
                TextColor="White"
                Margin="20,40,20,0"
                HorizontalOptions="Center" />
    </VerticalStackLayout>
</ContentPage>
MainPage.xaml.cs
using Microsoft.Maui.Controls;
using PersonalApp.Localization;
using System.Globalization;
using System.Diagnostics;

namespace PersonalApp;

public partial class MainPage : ContentPage
{
    private string _currentLang = "ru";

    public MainPage()
    {
        InitializeComponent();

        // Подключаем ViewModel напрямую к менеджеру локализации
        BindingContext = LocalizationResourceManager.Instance;

        try
        {
            LocalizationResourceManager.Instance.SetCulture(new CultureInfo(_currentLang));
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[MainPage] Ошибка локализации: {ex}");
        }
    }

     // Переключение языка по нажатию
    private void OnChangeLanguageClicked(object sender, EventArgs e)
    {
        _currentLang = _currentLang == "ru" ? "en" : "ru";
        LocalizationResourceManager.Instance.SetCulture(new CultureInfo(_currentLang));

        Debug.WriteLine($"Язык переключён на {_currentLang}");
        Debug.WriteLine($"HelloText: {LocalizationResourceManager.Instance["HelloText"]}");
        Debug.WriteLine($"ButtonText: {LocalizationResourceManager.Instance["ButtonText"]}");
    }

}
App.xaml.cs
using PersonalApp.Localization;
using System.Globalization;

namespace PersonalApp
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();

            try
            {
                LocalizationResourceManager.Instance.SetCulture(new CultureInfo("ru"));
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[App.cs] Ошибка локализации: {ex}");
            }

            MainPage = new MainPage(); // НЕ AppShell — упростим
        }
    }

}
✅ Результат
  • Интерфейс отображается сначала на русском
  • Нажатие на кнопку «Сменить язык» мгновенно переключает UI на английский (и обратно)
  • Работает на Android, iOS, MacCatalyst
💡 Что можно улучшить:
  • Сохранять текущий язык в Preferences
  • Автоматически определять язык по CultureInfo.CurrentUICulture
  • Добавить выпадающий список языков или иконки флагов
  • Сделать AppShell с локализованными элементами меню