Локализация через CSV
Таблицы UTF-8, контекст, русские множественные формы и обновление Label.
Таблица CSV хранит ключи сообщений в первом столбце, а локали — в заголовке. Reckfell создаёт ресурс .translation для каждого языка. Подключите эти ресурсы по инструкции настройки перевода.
Таблица для импорта
Сохраните Locale/ui.csv в UTF-8. В примерах используются запятые и файл без маркера порядка байтов. Экспортируйте настоящий CSV из таблицы: переименование XLSX в .csv не меняет формат.
keys,en,ru,_note
PLAY,Play,Играть,Main menu
ONLY_EN,English fallback,,Intentionally missing in ru
QUOTE,"He said ""Hello, friend"".","Он сказал «Привет, друг».",CSV quoting
LINES,Line one\nLine two,Строка один\nСтрока два,Escaped newline- Первая ячейка заголовка служит подписью. en и ru обозначают локали; сохраняйте идентификаторы точно и без пробелов по краям.
- Заголовок с подчёркиванием в начале, например _note, обозначает столбец комментариев, который не импортируется.
- Регистр ключей учитывается. Пара ключ/контекст должна быть уникальной. Не рассчитывайте на перезапись повторяющихся строк.
- Заключайте поле с разделителем, кавычкой или настоящим переносом строки в двойные кавычки. Кавычку внутри поля записывайте двумя кавычками.
- Пустая ячейка перевода пропускается; поиск может перейти к резервному языку.
Строка QUOTE сохраняет и запятую, и кавычки внутри текста. При стандартных настройках LINES после импорта содержит настоящий перенос строки.
Настройки импорта
Выберите CSV в Content Browser, измените настройки Import и примените Reimport.
| Настройка | Значения и действие |
|---|---|
| delimiter | 0: запятая; 1: точка с запятой; 2: табуляция. Значение должно соответствовать файлу |
| compress | 0: Disabled; 1: Auto. Auto оптимизирует простые таблицы; при фактическом использовании контекста или множественных форм остаётся обычный ресурс Translation |
| unescape_keys | По умолчанию false: последовательности с обратной косой чертой в ключах сохраняются |
| unescape_translations | По умолчанию true: обрабатываются последовательности вроде \n. Отключите, если обратная косая черта должна остаться в тексте |
Изменение параметра не меняет исходный CSV. Reimport применяет настройку и пересоздаёт языковые ресурсы. Считайте .translation, созданные из CSV, результатом импорта: редактируйте CSV, а не эти ресурсы.
Различать значения одного слова
Добавьте столбец ?context. Ниже — полная отдельная таблица:
keys,?context,en,ru
Open,verb,Open,Открыть
Open,state,Open,ОткрытоВнутри метода TranslationServer.Translate("Open", "state").ToString() вернёт Открыто при локали ru. Контекст — часть идентификатора сообщения: неизвестный контекст не выбирает произвольную строку с другим контекстом. Для автоматического перевода Control используйте его свойство TranslationContext; для вычисляемого текста передавайте контекст явно.
Выбрать множественную форму перед подстановкой числа
Сохраните полную таблицу как Locale/forms.csv и зарегистрируйте оба созданных ресурса вместе с ресурсами ui:
keys,?plural,?context,en,ru
Open,,verb,Open,Открыть
Open,,state,Open,Открыто
ITEM,ITEMS,,{0} item,{0} предмет
,,,{0} items,{0} предмета
,,,,{0} предметовПервая строка группы задаёт ключ единственного числа и исходный ключ множественного. В строках продолжения оставьте ключ, ?plural и ?context пустыми. Формы идут в порядке правила локали: у английского их две, у русского — три. Не копируйте английский текст в третью ячейку только ради заполнения таблицы.
TranslatePlural("ITEM", "ITEMS", n) выбирает форму, но не подставляет n. При ru число 1 выбирает {0} предмет, 2 — {0} предмета, 5 и 11 — {0} предметов, 21 — {0} предмет. После выбора отформатируйте строку. Заполнитель {0} должен оставаться корректным в каждом переводе.
При необходимости своего правила строка ?pluralrule задаёт выражение nplurals/plural для языка. Здесь достаточно встроенных правил ru/en; не переопределяйте их без причины.
Label с обновлением при смене языка
Прикрепите полный LocaleDemo.cs к Label. В массиве переводов проекта должны быть forms.en.translation и forms.ru.translation. Вызывайте SetGameLocale("ru") или SetGameLocale("en") из переключателя языка. После изменения ItemCount вызывайте RefreshText.
using Reckfell;
public partial class LocaleDemo : Label
{
public int ItemCount { get; set; } = 5;
public override void _Ready()
{
AutoTranslateMode = AutoTranslateModeEnum.Disabled;
RefreshText();
}
public override void _Notification(int what)
{
if (what == NotificationTranslationChanged && IsInsideTree())
RefreshText();
}
public void RefreshText()
{
// TranslatePlural selects a form; it does not insert the number.
string form = TranslationServer.TranslatePlural("ITEM", "ITEMS", ItemCount).ToString();
Text = string.Format(form, ItemCount);
}
public void SetGameLocale(string locale)
{
TranslationServer.SetLocale(locale);
}
}Автоматический перевод здесь отключён: Text уже содержит вычисленный результат. Скрипт обращается к TranslationServer явно. Label.Language задаёт язык обработки текста, а не глобальную локаль игры. Поэтому SetGameLocale вызывает именно TranslationServer.SetLocale.
Диагностика импорта
| Симптом | Действие |
|---|---|
| Языковые ресурсы не появились | Проверьте UTF-8, заголовки локалей, разделитель и сообщения импортера |
| Вся строка попала в одно поле | Выберите фактический разделитель файла и повторите импорт |
| Видно буквально \n или появился неожиданный перенос | Проверьте unescape_translations; кавычки CSV и обработка обратной косой черты — разные механизмы |
| Неправильная или отсутствующая множественная форма | Проверьте строки продолжения, локаль, порядок форм и сохранность заполнителей |
| Во время игры виден ключ | Подключите созданные ресурсы; проверьте регистр, контекст и резервный язык |
В движке проверены импорт, кавычки, Unicode, обработка обратной косой черты, разделитель «точка с запятой», сжатие, контекст, формы ru/en и точный пример C#. Работа с интерфейсом редактора, входной файл с табуляцией, переопределение правил в CSV, отображение шрифтов и экспорт этими тестами не проверялись.