Интернационализация игры и интерфейса
Автоматический перевод, вычисленный текст, замены ресурсов, шрифты, RTL и проверка запуска.
Интернационализация разделяет поиск сообщений, выбор языка игроком, отображение текста и локализованные ресурсы. Правильная строка перевода ещё не доказывает правильность шрифта, вёрстки или ресурса. Проверяйте эти уровни отдельно.
Подготовить проект
- Импортируйте и зарегистрируйте каталоги RU/EN по инструкции подключения переводов.
- Используйте постоянные ключи интерфейса. Задавайте контекст, если слово имеет разные значения; сохраняйте заполнители в каждом переводе.
- Выбирайте только среди языков, которые входят в игру. Применяйте сохранённый выбор после чтения настроек; иначе определяйте язык по локали ОС с явным резервным вариантом. Полный алгоритм для RU/EN есть в руководстве по локалям.
- Предоставьте переключатель языка. TranslationServer.SetLocale меняет текущий язык, но не сохраняет выбор.
Храните переводы в CSV или PO. Не заменяйте каталоги отдельными if/else для каждой надписи.
Автоматический, вычисленный и пользовательский текст
| Тип текста | Подход |
|---|---|
| Постоянная подпись Label/Button | Сохраните ключ в Text и включите автоматический перевод |
| Счётчик, форматированный результат или составленное предложение | Найдите полный шаблон, при необходимости выберите форму числа, подставьте значения и обновляйте по уведомлению о смене перевода |
| Имя игрока, чат, внешний текст | Отключите автоматический перевод и показывайте полученный текст |
Label сохраняет исходный ключ в Text, хотя его внутренний переведённый текст меняется. Не считайте Text готовым отображаемым переводом. Отключение автоматического перевода может наследоваться от предка; режим Always позволяет переопределить это для отдельной Entity.
Полный локализованный интерфейс
Создайте VBoxContainer и прикрепите LocalizedHud.cs ниже. Зарегистрируйте таблицы с PLAY_KEY и ключами множественных форм ITEM/ITEMS. PLAY_KEY должен переводиться как Play/Играть; для ITEM/ITEMS используйте таблицу множественных форм CSV.
using Reckfell;
public partial class LocalizedHud : VBoxContainer
{
public Label PlayLabel { get; private set; } = null!;
public Label PlayerLabel { get; private set; } = null!;
public Label CountLabel { get; private set; } = null!;
public int ItemCount { get; set; } = 5;
public override void _Ready()
{
PlayLabel = new Label { Text = "PLAY_KEY" };
PlayerLabel = new Label
{
AutoTranslateMode = AutoTranslateModeEnum.Disabled,
Text = "PLAY_KEY"
};
CountLabel = new Label { AutoTranslateMode = AutoTranslateModeEnum.Disabled };
AddChild(PlayLabel);
AddChild(PlayerLabel);
AddChild(CountLabel);
RefreshCount();
}
public override void _Notification(int what)
{
if (what == NotificationTranslationChanged && CountLabel != null)
RefreshCount();
}
public void RefreshCount()
{
string form = TranslationServer.TranslatePlural("ITEM", "ITEMS", ItemCount).ToString();
CountLabel.Text = string.Format(form, ItemCount);
}
public void SetGameLocale(string locale)
{
TranslationServer.SetLocale(locale);
}
}Вызовите SetGameLocale("en"), затем SetGameLocale("ru"). Первая строка меняется с Play на Играть; вторая остаётся буквально PLAY_KEY, имитируя имя игрока, совпавшее с ключом; счётчик меняется с 5 items на 5 предметов. После изменения ItemCount вызывайте RefreshCount. Вместо диагностического имени передавайте настоящий пользовательский текст.
TranslatePlural выбирает шаблон, string.Format подставляет число. Не склеивайте отдельно переведённые фрагменты: переводчику может понадобиться другой порядок слов. Полное сообщение с заполнителями должно находиться в каталоге.
Контекст должен попасть в поиск
Для автоматического перевода Control задайте TranslationContext до присваивания Text. Для вычисленного текста передайте контекст непосредственно в TranslationServer.Translate. Изменение одного TranslationContext сейчас не пересчитывает существующий буфер перевода Label. После смены контекста вызовите label.PropagateNotification((int)Entity.NotificationTranslationChanged), где label — существующий Label. Повторное присваивание прежнего значения Text само по себе обновление не вызывает.
Локализованные ресурсы
В Project Settings → Localization → Remaps выберите исходный ресурс, добавьте альтернативы и назначьте им локали. В игровом коде продолжайте загружать исходный путь. Загрузка альтернативы напрямую обходит выбор для оригинала.
Настройка project.reckfell ниже показывает замену ресурсов Gradient. При закрытом редакторе объедините её с существующим разделом internationalization:
[internationalization]
locale/translation_remaps={"asset://Locale/palette.rdata": PackedStringArray("asset://Locale/palette-en.rdata:en", "asset://Locale/palette-ru.rdata:ru")}Сначала создайте все три ресурса Gradient. Загружайте asset://Locale/palette.rdata. При смене локали загруженный ресурс с заменой перечитывается: кешированный объект может сохранить идентичность, изменив содержимое. Если подходящей альтернативы для локали нет, используется оригинал. Резервный язык текста автоматически не выбирает альтернативный ресурс: подготовьте подходящий оригинал.
Для локализованных изображений и озвучки настройте замены в редакторе и проверьте конкретные потребители. Перечитывание ресурса не доказывает перезапуск звука или обновление каждой скопированной переменной в вашем коде. Размеры, длительность и ссылки альтернатив должны подходить использующему их элементу.
Шрифты и вёрстка
Используйте актуальные ресурсы Font/FontFile и Font.Fallbacks, а не DynamicFont. Задавайте общую типографику через Theme, например DefaultFont, вместо замены у каждого Control. Подготовьте шрифты для настоящего текста, включая пользовательский ввод, язык которого может отличаться от интерфейса. Добавление резервного ресурса не доказывает покрытие символов: проверьте нужные знаки и соблюдайте лицензии шрифтов.
Label.Language влияет на обработку текста; он не меняет локаль TranslationServer и не выбирает другой каталог. TextDirection управляет направлением текста, Control.LayoutDirection — направлением раскладки интерфейса. Это разные настройки. Для путей и других структурированных строк может понадобиться StructuredTextBidiOverride вместо обычного порядка абзаца.
Для RTL проверяйте настоящий смешанный арабский/иврит, числа и латиницу, порядок фокуса, значки и используемые контейнеры. Явное направление RTL наследуется потомками, если не переопределено. Оно не зеркалит всю систему координат игры и не заменяет выбор перевода. Не каждую иллюстрацию с направлением нужно переворачивать.
Разрешайте контейнерам расти, а надписям — переноситься там, где это нужно; проверяйте минимальный размер окна. Для проверки длины используйте псевдолокализацию, учитывая ограничения заполнителей C# и множественных форм. Латинский текст с диакритикой не заменяет проверку китайского, японского, корейского или RTL.
TranslationServer.FormatNumber/ParseNumber преобразуют символы поддерживаемых систем счисления, но не задают полные правила валют, единиц и культурного форматирования. Отделяйте формат чисел от выбора каталога. Для языков со словарным разбиением строк проверьте internationalization/locale/include_text_server_data и экспортированную сборку с нужной поддержкой TextServer; не переносите результат редактора на экспорт без проверки.
Проверить запуск и настройки выпуска
internationalization/locale/test принудительно задаёт локаль запуска. Сбросьте значение перед выпуском, если игра должна выбирать язык игрока. Параметр командной строки может переопределить тестовую настройку:
& "C:\path\Reckfell Engine.console.exe" --path "C:\path\Game" --language ruЗамените оба пути на установленный исполняемый файл и проект. Код, который позже вызывает SetLocale, всё ещё может изменить язык.
Для локализованного названия приложения application/config/name_localized хранит соответствия локалей и названий. Проверяйте метаданные экспортированного приложения на целевой платформе: перевод Label внутри игры не подтверждает название в системе или магазине.
Приёмка и диагностика
| Ошибка | Первая проверка |
|---|---|
| Видно ключ | Регистрация, точный ключ/контекст, активная локаль и резервный язык |
| Обычная подпись обновилась, счётчик — нет | Обработчик уведомления и повторное форматирование шаблона |
| Имя игрока неожиданно перевелось | AutoTranslateMode этого элемента |
| Текст поменялся, локализованный ресурс — нет | Исходный путь загрузки, альтернативы и кешированное состояние потребителя |
| Строка правильная, но есть квадраты, обрезка или неверное направление | Отдельно покрытие шрифта, обработка текста и вёрстка |
| Язык сбросился после перезапуска | Сохранённый выбор и тестовая настройка запуска |
В движке проверены точный пример интерфейса, текстовые буферы Label, наследование перевода, обновление контекста, отличие локали от Language, замены загруженного Gradient и язык командной строки. Также проверены явные флаги RTL и API резервных шрифтов FontFile. Это не подтверждает отображение символов, зеркальную вёрстку, отсутствие обрезки, воспроизведение изображений/звука, сохранение выбора, работу в редакторе или экспорт. Для них нужны отдельные проверки приёмки.