Table of Contents

Локализация интерфейса игры

В этом руководстве меню проходит путь от английского текста в коде до игры, которая говорит на языке игрока и позволяет его переключать: ключи в разметке, один файл .po на язык, настройка языка, текст, построенный в коде, и слой для переводов сообщества.

Вам понадобится страница, загруженная из разметки (Первый экран). Страница Локализация описывает части; здесь они собираются вместе. Страница настроек — та, что в руководстве Игровое меню.

1. Используйте ключи в разметке

Замените каждый видимый текст на {Localize Key}. Ключи — имена на ваш выбор; Menu.Play читается лучше, чем английская фраза, и переживает её переформулировку:

<!-- A main menu whose texts are keys; the combo box picks the language. The data context is a LanguageSetting. -->
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Width="280">
  <TextBlock x:Name="Title" FontSize="32" Margin="0,0,0,16" Text="{Localize Menu.Title}" />
  <Button x:Name="Play" Margin="0,0,0,8" Content="{Localize Menu.Play}" />
  <TextBlock Margin="0,16,0,4" Text="{Localize Settings.Language}" />
  <ComboBox x:Name="Language" ItemsSource="{Binding Languages}" SelectedItem="{Binding Selected, Mode=TwoWay}" />
</StackPanel>

2. Напишите файлы переводов

Создайте рядом с игрой папку Localization с одним файлом gettext на язык: en.po и ru.po:

# Localization/en.po
msgid "Menu.Title"
msgstr "My Game"

msgid "Menu.Play"
msgstr "Play"

msgid "Settings.Language"
msgstr "Language"
# Localization/ru.po
msgid "Menu.Title"
msgstr "Моя игра"

msgid "Menu.Play"
msgstr "Играть"

msgid "Settings.Language"
msgstr "Язык"

Скопируйте файлы в вывод сборки. Переводчики открывают их в Poedit (или в сервисе вроде Weblate или Crowdin), поэтому дайте им файлы и объяснение смысла ключей; ваш код им не нужен. Игрок может добавить de.po в папку и получить новый язык без новой сборки.

3. Включите локализатор

Game.UseIcyUI(ui => ui
    .ConfigureAssets()
    .UsePoLocalization("Localization", CultureInfo.GetCultureInfo("en")));  // Localization/en.po, ru.po, ...

en — язык по умолчанию: ключ, которого нет в ru.po, показывает английский текст, а не сам ключ. Пока вы не зададите язык, используется язык системы игрока.

4. Добавьте настройку языка

Поле со списком на странице настроек задаёт Culture конфигурации; все тексты {Localize} меняются сразу, а числа, привязанные в интерфейсе, переключаются на формат новой культуры:

/// <summary>The Settings page's language choice. Choosing a language switches every localized text at once.</summary>
public sealed partial class LanguageSetting : ObservableObject
{
    private readonly IcyConfiguration configuration;
    private string selected;

    public LanguageSetting(IcyConfiguration configuration)
    {
        this.configuration = configuration;
        selected = NameOf(configuration.Culture);
    }

    /// <summary>The languages the game ships, as the player sees them (not translated).</summary>
    public IReadOnlyList<string> Languages { get; } = ["English", "Русский"];

    public string Selected
    {
        get => selected;
        set
        {
            if (SetProperty(ref selected, value))
                configuration.Culture = CultureInfo.GetCultureInfo(value == "Русский" ? "ru" : "en");
        }
    }

    private static string NameOf(CultureInfo culture) => culture.TwoLetterISOLanguageName == "ru" ? "Русский" : "English";
}

Дайте настройке собственный контекст данных на странице настроек, как руководство по игровому меню делает для остальных настроек. Показывайте каждый язык его собственным названием, не переведённым, чтобы игрок, попавший не на тот язык, мог найти свой. Сохраните выбор вместе с остальными настройками игрока и при запуске задавайте Culture из него.

5. Текст, построенный в коде

score.Localize(nameof(TextBlock.Text), "Hud.Score");

Этот текст следует за языком так же, как разметка. Для строки, которую вы форматируете сами, вызовите Configuration.Localize("Hud.Score").

6. Переводы сообщества

Чтобы игроки могли переопределять или добавлять строки из папки Mods/Localization, соедините в цепочку два локализатора. Язык по умолчанию задавайте только последнему:

var mods = new PoLocalizer(configuration.Assets, "Mods/Localization");   // no default: only the player's language
var game = new PoLocalizer(configuration.Assets, "Localization", CultureInfo.GetCultureInfo("en"));
configuration.Assets.Localizer = new CompositeLocalizer(mods, game);

7. Шрифты

Языку нужен шрифт с его буквами. Если в шрифте по умолчанию нет глифов кириллицы или CJK, текст показывается квадратами. Как выбрать шрифт, покрывающий ваши языки, см. Ресурсы и шрифты.

Что вы построили

Меню без текста в коде и разметке, файл перевода на каждый язык, настройка, переключающая язык во время игры, и папка, в которую игроки могут добавлять свои переводы.

Примечание

Текст с аргументами ("Score: {0}") не подставляется за вас: локализуйте строку формата через Configuration.Localize и форматируйте её в коде.

Дальше