Мы работаем над игрой "Cat Movies!" в движке Unreal Engine 4. Это экономическая стратегия, в которой достаточно много текста, и его мы планируем переводить на различные языки. Как и многие другие (но это не точно, и, надеюсь, что это не так), мы решили отложить этап настройки локализации на более поздние итерации разработки и, как оказалось, зря.
Локализация в UE4 реализована шикарно, и если помнить, что достаточно весь текст, который будет переводиться, хранить в Ftext (Text в Blueprint'ах) полях, то в целом, с выхватом текста из игры нет никаких проблем. Достаточно открыть Localization Dashboard, потыкать пару кнопок — и вуаля.
И, не смотря на всю простоту этого действа, мы все же столкнулись с рядом проблем, из-за чего пришлось часть кода перелопачивать.
Как хранить текст
Ребята из Epic Games упростили сборку текста до максимума, сводя все к одному клику и дальнейшему переводу.
Работает это все очень просто — для локализации используется тип данных FText (Text в Blueprint'ах), в который сохраняется текст, и этот текст в дальнейшем собирается системой локализации и предоставляется для перевода.
Как это работает?
FText — это не стандартный тип данных, который хранит в себе данные. Он, конечно, хранит в себе данные, но не те, которые мы ожидаем.
FText — это указатель. Он указывает на то, в какой таблице хранится текст. То есть, когда мы присваиваем переменной этого типа какой либо текст, то текст сохраняется в виртуальной таблице, а сама переменная теперь хранит имя таблицы и ключ, по которому в этой таблице можно найти текст.
Таким образом, получается, что сам текст хранится где-то в другом месте (тонкости реализации этого мы не будем рассматривать, так как нам это не особо-то и интересно), а при переключении локализации по нужному адресу происходит подмена текста (ну, или я так хочу думать).
Когда запускается сбор текста, то система локализации собирает все Text — переменные из всех блюпринтов, виджетов и таблиц, и выкатывает один огромный список текста, который можно экспортировать в *.po и переводить.
Наша игра имеет большой набор виджетов, через которые игрок будет контролировать почти весь игровой процесс. У нас есть много названий (например, отделов или этапов создания фильмов или каких-то навыков, бонусов и т.д.), которые используются в различных виджетах, между собой совсем не связанных. Есть описания каких-то объектов (например, описание бонусов), и это тоже используется не однократно в различных не связанных виджетах.
И вот тут начинается сложность. Если мы будем в каждом виджете заново писать названия отделов, то в какой-то момент в одном из виджетов название отделов будет написано не так. Осложняется это дело тем, что сами «описания» (например, описание отдела) в большом кол-ве знаков сложно отследить, чтобы везде были одинаковыми (естественно, мы так не делали). Еще больше веселья в том, что у нас большая часть виджетов используется, как шаблон, в который залетают данные из различных источников, и исходя из того, какой это был источник, меняются названия и тексты внутри кода.
Мы облегчили себе задачу, создав Data Table (таблицы данных), в которых мы начали хранить данные конкретных типов. Например, таблица отделов, которая содержит в себе название, описание, максимальный уровень, кол-во сотрудников на каждый уровень, и т.д. и т.п.
Казалось бы, можно было на этом остановиться, однако возникала сложность в том, что данные в таблице постоянно менялись, что-то переписывалось, что удалялось по мере роста кода, и бывали случаи, когда слетала полностью вся таблица, и нам приходилось откатываться, выдергивать данные, возвращаться в текущее состояние и вставлять потерянные данные обратно.
Все стало куда печальнее, когда я решил залезть в локализацию и наконец-то опробовать ее от и до, чтобы понимать, все ли мы верно делаем.
Я вытянул весь текст из игры и понял, что в коде, не смотря на то, что мы стремились избегать повторения, оказалось огромное количество повторяемых элементов текста.
Перевод — дело человеческое. Если будет возможность ошибиться, человеки обязательно ошибутся. И чтобы этого избежать или хотя бы минимизировать, нужно сводить все тексты к единому шаблону. То есть, вывести куда-то в одно место, откуда текст будет браться во всех частях кода. И который будет переведен лишь единожды, чтобы свести риски ошибок до минимума. Казалось бы, можно использовать DataTable, но и там кроется ряд проблем — чтобы сохранить просто названия чего-то, нам нужно создавать целые таблицы, которые будут хранить эти названия.
Поковырявшись в документации Epic Games, я обратил внимание на String Tables (далее «строковые таблицы»). Оказалось, это идеальный вариант — хранить текст в отдельной специальной для текстов таблице, которая создана именно для того, чтобы подключаться в FText — переменным. То есть, мы можем создать таблицу, которая будет хранить в себе текст. И этот текст мы можем подключать к любой переменной — будь то переменная в таблице данных, переменная в виджете, переменная в коде — все сводится к одному месту, где хранится текст.
Строковые Таблицы позволяют избегать повторения текста в проекте по нескольку раз чуть более, чем полностью, таким образом избегая ошибок.
Строковые таблицы создаются в движке, как и таблицы данных в разделе «miscellaneous»:
Заполняются очень легко — каждая новая строка должна иметь уникальный ключ, который придется придумывать самостоятельно. А сам текст уже может быть любым. Так же, в таблице можно указать отличное название пространства текста от названия таблицы, но, по нашему опыту, это не обязательно.
После того, как строковая таблица создана, текст теперь можно подключать к FText — переменной:
Таким образом, мы свели текст к одной строковой таблице, из которой его очень легко выдернуть. Чтобы получить это меню настройки текста, достаточно рядом с переменной текста нажать на стрелочку вниз.
Локализация
Теперь нам остается только собрать весь текст и начать с ним работать. Для этого нам необходимо запустить Localization Dashboard и начать настройки локализации. Запустить таблицу можно через меню Window->Localization Dashboard.
И перед вами откроется примерно такое окно:
В этом окне нужно обязательно указать цель (модуль), из которого будет выдергиваться текст. В нашем случае, это игра — Game.
Далее, нужно указать, откуда именно будет в модуле будет выдергиваться текст. В нашем случае, это только блюпринты, так как в сурсах мы не храним текст. Поэтому нужно указать только «Gather from Packages» и указать, в каких папках и какие файлы нам необходимо рассматривать, чтобы искать тексты.
Так же нам необходимо указать, какие языки будут использоваться для перевода и какой язык будет нативным (основным). Очень рекомендую, если вы пишите и говорите на русском языке — указывать русский язык (или любой другой ваш основной язык). Это связано с тем, что если вы не знаете хорошо английский язык, то указав его основным, вы усложняете себе перевод на английский с «английского». Поэтому, лучше заранее указать ваш язык, как основной, и все тексты писать на вашем родном языке, чтобы потом облегчить себе и другим переводы.
Так же в UE4 есть шикарная возможность создавать переводы прямо в движке, не экспортируя тексты для сторонних программ. Для этого нужно собрать весь актуальный текст в игре, нажав на кнопку №1. И после этого запустить редактор (кнопка №2):
Откроется окно редактирования перевода на нужный вам язык.
Сборка
При сборке проекта обязательно нужно указать языки, которые в эту сборку должны войти, а так же какой набор языков должен поддерживать ваш проект.
В нашем случае, Internationalization Support установлен на All. То есть, наш проект будет поддерживать все типы языков от сложных иероглифов до простых английских букв. А вообще, есть 5 пакетов:
- English (чистый английский).
- EFIGS (English, French, Italian, German, and Spanish)
- EFIGSCJK (То же, что и выше + Chinese, Japanese, and Korean )
- CJK (Chinese, Japanese, and Korean).
- All (Все языки).
Однако в случаях, когда важен каждый байт в проекте (пакет All весит 15мбайт, а EFIGS 2мбайта), стоит более внимательно отнестись к тому, какой пакет нужно выбрать.
Переключение локализации
Переключение текста происходит в Runtime, то есть вам не нужно перезагружать игру, не нужно париться на тему оптимизации переключения — все делается легко и просто через метод "SetCurrentCulture", где текстом нужно указать, на какой язык вы хотите переключиться.
И вот здесь есть некоторая такая загвоздочка. Дело в том, что разных странах есть свои ответвления языка, так, например, есть основной русский язык (ru), а есть белорусский (ru-BY), казахстанский (ru-KZ), молдавский (ru-MD), украинский (ru-UA) языки, которые попадают под ветку русского языка. Поэтому, при выборе какого-то языка, который не является основным, это нужно учитывать и указывать корректный язык. Если выбрать просто основной, то при переключении достаточно указать «ru».
Заключение
После того, как я собрал всю эту информацию вместе, я осознал, что мы с самого начала не корректно подходили к созданию текста в игре и очень много сделали лишней работы. Конечно, мы не перерабатывали код месяцами, а уделили этому максимум 1.5 часа, но все же было бы приятней знать принципы работы локализации в UE4 заранее и учитывать их при построении архитектуры проекта.
То же самое касается и Сохранения и Загрузки в играх. Это оказалось не такой уж и простой задачей в условиях стратегии, где каждая мелочь должна фиксироваться там, где она стоит/лежит/имеет определенное состояние. Но об этом я напишу как-нибудь в другой раз. А сейчас вы можете продолжить наблюдать за нашей игрой в нашей группе =)
Комментарии (7)
ufna
05.10.2019 10:35+1> Локализация в UE4 реализована шикарно
Увы, нет. Количество багов, костылей и «особенностей» с этим связанных — зашкаливает. В последней версии стало лучше (наконец-то перестали теряться ключи), но путь к этому был полон боли.MrBrooks Автор
05.10.2019 10:49Я полноценно столкнулся с этим уже в 4.22, до этого только баловались, прикидывали, примеряли. А сейчас потребовалось уже конкретно решить вопрос с локализацией, и на этой версии опробовали полноценно.
sidebail
06.10.2019 08:54Автор, огромное спасибо за такое мини пособие, никогда не трогал локалайз в UE4, был только в планах, но теперь буду знать!
Ну и, чёрт возьми, не могу пройти мимо команды по UE4 и не попроситься поволонтёрствовать, хоть тестером, хоть переводчиком (с инглишем я на ты), вот мой линкед если интересно — https://www.linkedin.com/in/vladimir-vatsurin/
Резюме всё же надо расширять!
P.s. заранее приношу извинения за такой пиар в коментах
doti
Подскажите, UE4 может сразу делать приложения под iOS?
Насколько надо переделывать ваше, что бы выпустить на телефоне?
MrBrooks Автор
Интересный вопрос.
UE4 под iOS может без проблем.
На счет нашего проекта — все зависит от производительности мобилки. На данный момент мы делаем игру под ПК. Под мобилку нужно будет даунгрейдить объекты, менять тип текстурирования, возможно, переделывать какие-то эффекты =)