Подготовка игры к локализации — важная часть разработки игр.
Мы работаем над игрой "Cat Movies!" в движке Unreal Engine 4. Это экономическая стратегия, в которой достаточно много текста, и его мы планируем переводить на различные языки. Как и многие другие (но это не точно, и, надеюсь, что это не так), мы решили отложить этап настройки локализации на более поздние итерации разработки и, как оказалось, зря.
Локализация в UE4 реализована шикарно, и если помнить, что достаточно весь текст, который будет переводиться, хранить в Ftext (Text в Blueprint'ах) полях, то в целом, с выхватом текста из игры нет никаких проблем. Достаточно открыть Localization Dashboard, потыкать пару кнопок — и вуаля.
И, не смотря на всю простоту этого действа, мы все же столкнулись с рядом проблем, из-за чего пришлось часть кода перелопачивать.
Дополнено от 16.10.19: Форматирование текста.
Дополнено от 13.09.20: Локализация ассетов.
Ребята из Epic Games упростили сборку текста до максимума, сводя все к одному клику и дальнейшему переводу.
Работает это все очень просто — для локализации используется тип данных FText (Text в Blueprint'ах), в который сохраняется текст, и этот текст в дальнейшем собирается системой локализации и предоставляется для перевода.
Как это работает?
FText — это не стандартный тип данных, который хранит в себе данные. Он, конечно, хранит в себе данные, но не те, которые мы ожидаем.
FText — это указатель. Он указывает на то, в какой таблице хранится текст. То есть, когда мы присваиваем переменной этого типа какой либо текст, то текст сохраняется в виртуальной таблице, а сама переменная теперь хранит имя таблицы и ключ, по которому в этой таблице можно найти текст.
Таким образом, получается, что сам текст хранится где-то в другом месте (тонкости реализации этого мы не будем рассматривать, так как нам это не особо-то и интересно), а при переключении локализации по нужному адресу происходит подмена текста (ну, или я так хочу думать).
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/dfc/93c/ad8/dfc93cad81ebaac7809005f5ddda65c0.jpg)
Когда запускается сбор текста, то система локализации собирает все Text — переменные из всех блюпринтов, виджетов и таблиц, и выкатывает один огромный список текста, который можно экспортировать в *.po и переводить.
Наша игра имеет большой набор виджетов, через которые игрок будет контролировать почти весь игровой процесс. У нас есть много названий (например, отделов или этапов создания фильмов или каких-то навыков, бонусов и т.д.), которые используются в различных виджетах, между собой совсем не связанных. Есть описания каких-то объектов (например, описание бонусов), и это тоже используется не однократно в различных не связанных виджетах.
И вот тут начинается сложность. Если мы будем в каждом виджете заново писать названия отделов, то в какой-то момент в одном из виджетов название отделов будет написано не так. Осложняется это дело тем, что сами «описания» (например, описание отдела) в большом кол-ве знаков сложно отследить, чтобы везде были одинаковыми (естественно, мы так не делали). Еще больше веселья в том, что у нас большая часть виджетов используется, как шаблон, в который залетают данные из различных источников, и исходя из того, какой это был источник, меняются названия и тексты внутри кода.
Мы облегчили себе задачу, создав Data Table (таблицы данных), в которых мы начали хранить данные конкретных типов. Например, таблица отделов, которая содержит в себе название, описание, максимальный уровень, кол-во сотрудников на каждый уровень, и т.д. и т.п.
Казалось бы, можно было на этом остановиться, однако возникала сложность в том, что данные в таблице постоянно менялись, что-то переписывалось, что удалялось по мере роста кода, и бывали случаи, когда слетала полностью вся таблица, и нам приходилось откатываться, выдергивать данные, возвращаться в текущее состояние и вставлять потерянные данные обратно.
Все стало куда печальнее, когда я решил залезть в локализацию и наконец-то опробовать ее от и до, чтобы понимать, все ли мы верно делаем.
Я вытянул весь текст из игры и понял, что в коде, не смотря на то, что мы стремились избегать повторения, оказалось огромное количество повторяемых элементов текста.
Перевод — дело человеческое. Если будет возможность ошибиться, человеки обязательно ошибутся. И чтобы этого избежать или хотя бы минимизировать, нужно сводить все тексты к единому шаблону. То есть, вывести куда-то в одно место, откуда текст будет браться во всех частях кода. И который будет переведен лишь единожды, чтобы свести риски ошибок до минимума. Казалось бы, можно использовать DataTable, но и там кроется ряд проблем — чтобы сохранить просто названия чего-то, нам нужно создавать целые таблицы, которые будут хранить эти названия.
Поковырявшись в документации Epic Games, я обратил внимание на String Tables (далее «строковые таблицы»). Оказалось, это идеальный вариант — хранить текст в отдельной специальной для текстов таблице, которая создана именно для того, чтобы подключаться в FText — переменным. То есть, мы можем создать таблицу, которая будет хранить в себе текст. И этот текст мы можем подключать к любой переменной — будь то переменная в таблице данных, переменная в виджете, переменная в коде — все сводится к одному месту, где хранится текст.
Строковые Таблицы позволяют избегать повторения текста в проекте по нескольку раз чуть более, чем полностью, таким образом избегая ошибок.
Строковые таблицы создаются в движке, как и таблицы данных в разделе «miscellaneous»:
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/42e/e26/607/42ee266076bfca6f67f2259e3dc35c47.jpg)
Заполняются очень легко — каждая новая строка должна иметь уникальный ключ, который придется придумывать самостоятельно. А сам текст уже может быть любым. Так же, в таблице можно указать отличное название пространства текста от названия таблицы, но, по нашему опыту, это не обязательно.
После того, как строковая таблица создана, текст теперь можно подключать к FText — переменной:
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/3da/70a/b12/3da70ab12906a8e27428eb5acd468088.jpg)
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/b83/18f/969/b8318f96985ce0aeed9e43720b2c69e0.jpg)
Таким образом, мы свели текст к одной строковой таблице, из которой его очень легко выдернуть. Чтобы получить это меню настройки текста, достаточно рядом с переменной текста нажать на стрелочку вниз.
Теперь нам остается только собрать весь текст и начать с ним работать. Для этого нам необходимо запустить Localization Dashboard и начать настройки локализации. Запустить таблицу можно через меню Window->Localization Dashboard.
И перед вами откроется примерно такое окно:
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/909/1b6/652/9091b66522dc3d9d81762362435e7c7e.jpg)
В этом окне нужно обязательно указать цель (модуль), из которого будет выдергиваться текст. В нашем случае, это игра — Game.
Далее, нужно указать, откуда именно будет в модуле будет выдергиваться текст. В нашем случае, это только блюпринты, так как в сурсах мы не храним текст. Поэтому нужно указать только «Gather from Packages» и указать, в каких папках и какие файлы нам необходимо рассматривать, чтобы искать тексты.
Так же нам необходимо указать, какие языки будут использоваться для перевода и какой язык будет нативным (основным). Очень рекомендую, если вы пишите и говорите на русском языке — указывать русский язык (или любой другой ваш основной язык). Это связано с тем, что если вы не знаете хорошо английский язык, то указав его основным, вы усложняете себе перевод на английский с «английского». Поэтому, лучше заранее указать ваш язык, как основной, и все тексты писать на вашем родном языке, чтобы потом облегчить себе и другим переводы.
Так же в UE4 есть шикарная возможность создавать переводы прямо в движке, не экспортируя тексты для сторонних программ. Для этого нужно собрать весь актуальный текст в игре, нажав на кнопку №1. И после этого запустить редактор (кнопка №2):
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/0d4/e8f/862/0d4e8f8623131a49733f130e90f5f07d.jpg)
Откроется окно редактирования перевода на нужный вам язык.
При сборке проекта обязательно нужно указать языки, которые в эту сборку должны войти, а так же какой набор языков должен поддерживать ваш проект.
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/cee/817/eb8/cee817eb8fa63d50e74e11467f4be797.jpg)
В нашем случае, Internationalization Support установлен на All. То есть, наш проект будет поддерживать все типы языков от сложных иероглифов до простых английских букв. А вообще, есть 5 пакетов:
Однако в случаях, когда важен каждый байт в проекте (пакет All весит 15мбайт, а EFIGS 2мбайта), стоит более внимательно отнестись к тому, какой пакет нужно выбрать.
Переключение текста происходит в Runtime, то есть вам не нужно перезагружать игру, не нужно париться на тему оптимизации переключения — все делается легко и просто через метод "SetCurrentCulture", где текстом нужно указать, на какой язык вы хотите переключиться.
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/368/ae6/007/368ae600760d21c3236384ae5cf8072b.jpg)
И вот здесь есть некоторая такая загвоздочка. Дело в том, что разных странах есть свои ответвления языка, так, например, есть основной русский язык (ru), а есть белорусский (ru-BY), казахстанский (ru-KZ), молдавский (ru-MD), украинский (ru-UA) языки, которые попадают под ветку русского языка. Поэтому, при выборе какого-то языка, который не является основным, это нужно учитывать и указывать корректный язык. Если выбрать просто основной, то при переключении достаточно указать «ru».
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/fcf/884/1c8/fcf8841c8f1b2d6138e2a2b358f22cd3.jpg)
Если в самом тексте указать фигурные скобки, а в них указать название данных, то в дальнейшем, можно использовать подстановку этих самых данных в текст.
Например: «Вы желаете изучить технологию {Tech_Name}?»
И, в дальнейшем, в BP можно использовать ноду «Format Text», которая будет учитывать сам текст и какие там указаны параметры и создавать дополнительные пины для подключения этих самых данных:
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/6b7/dcf/388/6b7dcf3885f6f7f9f248f20013d7618a.jpg)
Теперь в текст будет встроена дополнительная информация, которую можно корректировать, не корректируя сам текст. Например, можно вписывать названия отделов или технологий, можно указывать уровни или что-то еще.
Все ассеты по умолчанию отображаются и используются на всех языках одинаково. Однако мы можем для какого-то конкретного языка указать проекту использовать обособленный ассет, который специально создан для него. Например, виджеты, в которых в зависимости от языка может меняться какая-то логика или полностью поведение — некоторые языки читаются справа налево, и печатать их слева направо не совсем корректно, а локализованные объекты уже могут вести себя по разному в зависимости от языка.
Это же касается и текстур, эффектов, моделей, аудио, видео — любых ассетов, которые вы используете в работе над своим проектом.
Не нужно делать какие-то супер-сложные действия для работы с локализованными ассетами, достаточно указать, что этот ассет будет использовать другую версию себя для конкретного языка — движок создаст копию ассета в папке с локализацией, и мы уже можем ее обновлять, изменять или полностью переписывать.
Для этого нажмите по любому ассету в проекте ПКМ -> Asset Localization -> Create Localized Asset -> (выбрать язык).
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/d02/82c/7bf/d0282c7bf0b51f7084b30311746bd6c3.jpg)
После создания новой копии ассет можно найти в специализированной папке для локализации. Если лень искать — можно кликнуть ПКМ по основному объекту в проекте и через меню локализации выбрать редактирование нужной вам версии.
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/5e5/dbd/3ca/5e5dbd3cad8a8ec113c5557e8f6633e6.jpg)
Там же можно и перейти к ассету в браузере. Все очень удобно и практично.
После того, как я собрал всю эту информацию вместе, я осознал, что мы с самого начала не корректно подходили к созданию текста в игре и очень много сделали лишней работы. Конечно, мы не перерабатывали код месяцами, а уделили этому максимум 1.5 часа, но все же было бы приятней знать принципы работы локализации в UE4 заранее и учитывать их при построении архитектуры проекта.
То же самое касается и Сохранения и Загрузки в играх. Это оказалось не такой уж и простой задачей в условиях стратегии, где каждая мелочь должна фиксироваться там, где она стоит/лежит/имеет определенное состояние. Но об этом я напишу как-нибудь в другой раз. А сейчас вы можете продолжить наблюдать за нашей игрой в нашей группе VK и в Twitter'е =)
Мы работаем над игрой "Cat Movies!" в движке Unreal Engine 4. Это экономическая стратегия, в которой достаточно много текста, и его мы планируем переводить на различные языки. Как и многие другие (но это не точно, и, надеюсь, что это не так), мы решили отложить этап настройки локализации на более поздние итерации разработки и, как оказалось, зря.
Локализация в UE4 реализована шикарно, и если помнить, что достаточно весь текст, который будет переводиться, хранить в Ftext (Text в Blueprint'ах) полях, то в целом, с выхватом текста из игры нет никаких проблем. Достаточно открыть Localization Dashboard, потыкать пару кнопок — и вуаля.
И, не смотря на всю простоту этого действа, мы все же столкнулись с рядом проблем, из-за чего пришлось часть кода перелопачивать.
Дополнено от 16.10.19: Форматирование текста.
Дополнено от 13.09.20: Локализация ассетов.
Как хранить текст
Ребята из Epic Games упростили сборку текста до максимума, сводя все к одному клику и дальнейшему переводу.
Работает это все очень просто — для локализации используется тип данных FText (Text в Blueprint'ах), в который сохраняется текст, и этот текст в дальнейшем собирается системой локализации и предоставляется для перевода.
Как это работает?
FText — это не стандартный тип данных, который хранит в себе данные. Он, конечно, хранит в себе данные, но не те, которые мы ожидаем.
FText — это указатель. Он указывает на то, в какой таблице хранится текст. То есть, когда мы присваиваем переменной этого типа какой либо текст, то текст сохраняется в виртуальной таблице, а сама переменная теперь хранит имя таблицы и ключ, по которому в этой таблице можно найти текст.
Таким образом, получается, что сам текст хранится где-то в другом месте (тонкости реализации этого мы не будем рассматривать, так как нам это не особо-то и интересно), а при переключении локализации по нужному адресу происходит подмена текста (ну, или я так хочу думать).
![image](https://habrastorage.org/getpro/habr/post_images/dfc/93c/ad8/dfc93cad81ebaac7809005f5ddda65c0.jpg)
Когда запускается сбор текста, то система локализации собирает все Text — переменные из всех блюпринтов, виджетов и таблиц, и выкатывает один огромный список текста, который можно экспортировать в *.po и переводить.
Наша игра имеет большой набор виджетов, через которые игрок будет контролировать почти весь игровой процесс. У нас есть много названий (например, отделов или этапов создания фильмов или каких-то навыков, бонусов и т.д.), которые используются в различных виджетах, между собой совсем не связанных. Есть описания каких-то объектов (например, описание бонусов), и это тоже используется не однократно в различных не связанных виджетах.
И вот тут начинается сложность. Если мы будем в каждом виджете заново писать названия отделов, то в какой-то момент в одном из виджетов название отделов будет написано не так. Осложняется это дело тем, что сами «описания» (например, описание отдела) в большом кол-ве знаков сложно отследить, чтобы везде были одинаковыми (естественно, мы так не делали). Еще больше веселья в том, что у нас большая часть виджетов используется, как шаблон, в который залетают данные из различных источников, и исходя из того, какой это был источник, меняются названия и тексты внутри кода.
Мы облегчили себе задачу, создав Data Table (таблицы данных), в которых мы начали хранить данные конкретных типов. Например, таблица отделов, которая содержит в себе название, описание, максимальный уровень, кол-во сотрудников на каждый уровень, и т.д. и т.п.
Казалось бы, можно было на этом остановиться, однако возникала сложность в том, что данные в таблице постоянно менялись, что-то переписывалось, что удалялось по мере роста кода, и бывали случаи, когда слетала полностью вся таблица, и нам приходилось откатываться, выдергивать данные, возвращаться в текущее состояние и вставлять потерянные данные обратно.
Все стало куда печальнее, когда я решил залезть в локализацию и наконец-то опробовать ее от и до, чтобы понимать, все ли мы верно делаем.
Я вытянул весь текст из игры и понял, что в коде, не смотря на то, что мы стремились избегать повторения, оказалось огромное количество повторяемых элементов текста.
Перевод — дело человеческое. Если будет возможность ошибиться, человеки обязательно ошибутся. И чтобы этого избежать или хотя бы минимизировать, нужно сводить все тексты к единому шаблону. То есть, вывести куда-то в одно место, откуда текст будет браться во всех частях кода. И который будет переведен лишь единожды, чтобы свести риски ошибок до минимума. Казалось бы, можно использовать DataTable, но и там кроется ряд проблем — чтобы сохранить просто названия чего-то, нам нужно создавать целые таблицы, которые будут хранить эти названия.
Поковырявшись в документации Epic Games, я обратил внимание на String Tables (далее «строковые таблицы»). Оказалось, это идеальный вариант — хранить текст в отдельной специальной для текстов таблице, которая создана именно для того, чтобы подключаться в FText — переменным. То есть, мы можем создать таблицу, которая будет хранить в себе текст. И этот текст мы можем подключать к любой переменной — будь то переменная в таблице данных, переменная в виджете, переменная в коде — все сводится к одному месту, где хранится текст.
Строковые Таблицы позволяют избегать повторения текста в проекте по нескольку раз чуть более, чем полностью, таким образом избегая ошибок.
Строковые таблицы создаются в движке, как и таблицы данных в разделе «miscellaneous»:
![image](https://habrastorage.org/getpro/habr/post_images/42e/e26/607/42ee266076bfca6f67f2259e3dc35c47.jpg)
Заполняются очень легко — каждая новая строка должна иметь уникальный ключ, который придется придумывать самостоятельно. А сам текст уже может быть любым. Так же, в таблице можно указать отличное название пространства текста от названия таблицы, но, по нашему опыту, это не обязательно.
После того, как строковая таблица создана, текст теперь можно подключать к FText — переменной:
![image](https://habrastorage.org/getpro/habr/post_images/3da/70a/b12/3da70ab12906a8e27428eb5acd468088.jpg)
![image](https://habrastorage.org/getpro/habr/post_images/b83/18f/969/b8318f96985ce0aeed9e43720b2c69e0.jpg)
Таким образом, мы свели текст к одной строковой таблице, из которой его очень легко выдернуть. Чтобы получить это меню настройки текста, достаточно рядом с переменной текста нажать на стрелочку вниз.
Локализация
Теперь нам остается только собрать весь текст и начать с ним работать. Для этого нам необходимо запустить Localization Dashboard и начать настройки локализации. Запустить таблицу можно через меню Window->Localization Dashboard.
И перед вами откроется примерно такое окно:
![image](https://habrastorage.org/getpro/habr/post_images/909/1b6/652/9091b66522dc3d9d81762362435e7c7e.jpg)
В этом окне нужно обязательно указать цель (модуль), из которого будет выдергиваться текст. В нашем случае, это игра — Game.
Далее, нужно указать, откуда именно будет в модуле будет выдергиваться текст. В нашем случае, это только блюпринты, так как в сурсах мы не храним текст. Поэтому нужно указать только «Gather from Packages» и указать, в каких папках и какие файлы нам необходимо рассматривать, чтобы искать тексты.
Так же нам необходимо указать, какие языки будут использоваться для перевода и какой язык будет нативным (основным). Очень рекомендую, если вы пишите и говорите на русском языке — указывать русский язык (или любой другой ваш основной язык). Это связано с тем, что если вы не знаете хорошо английский язык, то указав его основным, вы усложняете себе перевод на английский с «английского». Поэтому, лучше заранее указать ваш язык, как основной, и все тексты писать на вашем родном языке, чтобы потом облегчить себе и другим переводы.
Так же в UE4 есть шикарная возможность создавать переводы прямо в движке, не экспортируя тексты для сторонних программ. Для этого нужно собрать весь актуальный текст в игре, нажав на кнопку №1. И после этого запустить редактор (кнопка №2):
![image](https://habrastorage.org/getpro/habr/post_images/0d4/e8f/862/0d4e8f8623131a49733f130e90f5f07d.jpg)
Откроется окно редактирования перевода на нужный вам язык.
Сборка
При сборке проекта обязательно нужно указать языки, которые в эту сборку должны войти, а так же какой набор языков должен поддерживать ваш проект.
![image](https://habrastorage.org/getpro/habr/post_images/cee/817/eb8/cee817eb8fa63d50e74e11467f4be797.jpg)
В нашем случае, 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", где текстом нужно указать, на какой язык вы хотите переключиться.
![image](https://habrastorage.org/getpro/habr/post_images/368/ae6/007/368ae600760d21c3236384ae5cf8072b.jpg)
И вот здесь есть некоторая такая загвоздочка. Дело в том, что разных странах есть свои ответвления языка, так, например, есть основной русский язык (ru), а есть белорусский (ru-BY), казахстанский (ru-KZ), молдавский (ru-MD), украинский (ru-UA) языки, которые попадают под ветку русского языка. Поэтому, при выборе какого-то языка, который не является основным, это нужно учитывать и указывать корректный язык. Если выбрать просто основной, то при переключении достаточно указать «ru».
![image](https://habrastorage.org/getpro/habr/post_images/fcf/884/1c8/fcf8841c8f1b2d6138e2a2b358f22cd3.jpg)
Добавление в текст данных других данных в Blueprint'ах.
Если в самом тексте указать фигурные скобки, а в них указать название данных, то в дальнейшем, можно использовать подстановку этих самых данных в текст.
Например: «Вы желаете изучить технологию {Tech_Name}?»
И, в дальнейшем, в BP можно использовать ноду «Format Text», которая будет учитывать сам текст и какие там указаны параметры и создавать дополнительные пины для подключения этих самых данных:
![image](https://habrastorage.org/getpro/habr/post_images/6b7/dcf/388/6b7dcf3885f6f7f9f248f20013d7618a.jpg)
Теперь в текст будет встроена дополнительная информация, которую можно корректировать, не корректируя сам текст. Например, можно вписывать названия отделов или технологий, можно указывать уровни или что-то еще.
Локализация ассетов.
Все ассеты по умолчанию отображаются и используются на всех языках одинаково. Однако мы можем для какого-то конкретного языка указать проекту использовать обособленный ассет, который специально создан для него. Например, виджеты, в которых в зависимости от языка может меняться какая-то логика или полностью поведение — некоторые языки читаются справа налево, и печатать их слева направо не совсем корректно, а локализованные объекты уже могут вести себя по разному в зависимости от языка.
Это же касается и текстур, эффектов, моделей, аудио, видео — любых ассетов, которые вы используете в работе над своим проектом.
Не нужно делать какие-то супер-сложные действия для работы с локализованными ассетами, достаточно указать, что этот ассет будет использовать другую версию себя для конкретного языка — движок создаст копию ассета в папке с локализацией, и мы уже можем ее обновлять, изменять или полностью переписывать.
Для этого нажмите по любому ассету в проекте ПКМ -> Asset Localization -> Create Localized Asset -> (выбрать язык).
![image](https://habrastorage.org/getpro/habr/post_images/d02/82c/7bf/d0282c7bf0b51f7084b30311746bd6c3.jpg)
После создания новой копии ассет можно найти в специализированной папке для локализации. Если лень искать — можно кликнуть ПКМ по основному объекту в проекте и через меню локализации выбрать редактирование нужной вам версии.
![image](https://habrastorage.org/getpro/habr/post_images/5e5/dbd/3ca/5e5dbd3cad8a8ec113c5557e8f6633e6.jpg)
Там же можно и перейти к ассету в браузере. Все очень удобно и практично.
Заключение
После того, как я собрал всю эту информацию вместе, я осознал, что мы с самого начала не корректно подходили к созданию текста в игре и очень много сделали лишней работы. Конечно, мы не перерабатывали код месяцами, а уделили этому максимум 1.5 часа, но все же было бы приятней знать принципы работы локализации в UE4 заранее и учитывать их при построении архитектуры проекта.
То же самое касается и Сохранения и Загрузки в играх. Это оказалось не такой уж и простой задачей в условиях стратегии, где каждая мелочь должна фиксироваться там, где она стоит/лежит/имеет определенное состояние. Но об этом я напишу как-нибудь в другой раз. А сейчас вы можете продолжить наблюдать за нашей игрой в нашей группе VK и в Twitter'е =)