7 советов по локализации инди-игры в Unity
Unity — один из самых популярных игровых движков среди независимых разработчиков. Это мощный инструмент, открывающий доступ в игровую индустрию даже самым мелким издателям и разработчикам-одиночкам.
Проблема независимого пути в том, что нужно всегда пытаться соответствовать стандартам и нагрузке больших коллективов. Unity облегчает задачу, упрощая процесс разработки, чтобы с ней мог справиться один человек.
Это относится и к локализации, благодаря которой вы можете познакомить со своей игрой весь мир. Однако нужно быть осторожным, ведь локализация игры — сложный процесс. Давайте рассмотрим наилучший способ выполнить её в Unity.
1. Используйте расширения Smart Localization и I2 Localization (но аккуратно)
Smart Localization (бесплатная и платная версии)
Хорошим началом локализации проекта Unity будет выбор готового расширения под названием Smart Localization, разработанного janeTech. У расширения есть две версии: бесплатная и платная версия Pro.
Вот что можно доверить Smart Localization:
- Создание структуры папок для разных языков.
- Импорт и экспорт файлов
I2 Localization (45$)
Среди платных ассетов определённо полезным будет I2 Localization, разработанный игровой студией Inter Illusion.

Наиболее удобными функциями этого ассета являются синхронизация с электронными таблицами Google и автоматическое отображение текста справа налево для арабского.
«I2 Localization в целом прекрасный инструмент для локализации. [. ] Первое и главное — это возможность импорта данных непосредственно из Таблиц Google даже после выпуска игры. Это чрезвычайно полезно, потому что большинство компаний-локализаторов отдаёт результаты в файле Excel, который можно быстро перенести в Таблицы Google и импортировать все данные.
Вторая функция, которую я люблю, позволяет обрабатывать hardcoded-текст в коде. Вместо того, чтобы создавать конструкции из циклов или switch, можно использовать единственную строку для перевода текста: I2.Loc.ScriptLocalization.Get(»»);».
Оба расширения популярны среди разработчиков Unity (в особенности бесплатная версия Smart Localization, по понятным причинам). Это полезные инструменты, но применяйте их аккуратно. Ни одно расширение не решит всех вопросов локализации, и уж точно не выполнит процесс локализации за вас.
2. Наймите профессиональных переводчиков
От этого никуда не уйти, если вы серьёзно настроены продавать свою игру на иностранных рынках. Вам нужны профессиональные переводчики видеоигр, и чем раньше вы начнёте с ними работать, тем лучше.
Подготовьте первый черновик переводов ещё до начала разработки.
Вы сэкономите кучу времени, если займётесь кодингом игры после того, как процесс локализации будет выполнен. Уделите особое внимание длине слов и предложений в каждом переводе по сравнению с английской версией (или другим базовым языком). Так вы сможете внести в дизайн необходимые правки или снова обратиться к переводчику и поработать над альтернативами.
Если вы займётесь локализацией после завершения разработки, то это обернётся кошмаром.
3. Выберите правильный формат текстовых строк
После начала разработки первое, что нужно сделать с точки зрения локализации — выбрать способ форматирования текстовых строк. Здесь вы делаете выбор не только с точки зрения разработки: это определит, насколько просто или сложно будет добавлять новые языки в игру в будущем или изменять существующие переводы.
Unity поддерживает множество форматов, самые популярные из них это:
- JSON
- XML
- YAML
- CSV
Если вы разрабатываете игру на JavaScript, то правильнее всего будет использовать JSON. Это простой и лёгкий формат, используемый множеством разработчиков в течение долгих лет. Кроме того, он быстр в обработке. Кроме преимуществ для разработчика, он очень лёгок в чтении даже для тех, кто не занимается разработкой. Это важный плюс для будущих переводов и правок.
Многие разработчики по-прежнему работают с XML, и это хороший выбор, если вы предпочитаете работать именно с этим языком разметки. Это не самый эффективный язык и его сложнее читать, так что учтите это при создании игры.
С точки зрения переводов другие варианты значительно более проблематичны, но вам нужно придерживаться того языка, который наиболее удобен. Плотно взаимодействуйте с переводчиком, чтобы как можно больше упростить его работу, потому что это снизит количество ошибок.
4. Определитесь со структурой строк
Подбор самого эффективного способа структурирования строк может стать настоящей проблемой. Для этого процесса нет чётко заданных инструкций. Unity предоставляет разработчику свободу в выборе структуры. Свобода — это, конечно, всегда хорошо, но она и увеличивает вероятность ошибок.
Существует три основных фактора, влияющих на структуру строк:
- Язык
- Идентификаторы (ID) строк
- Текст
Для большинства игр (в которых выбор языка сохраняется в самом начале) можно хранить строки в отдельных файлах для каждого языка (например, en.json, es.json, fr.json и т.д.). Это наиболее продуктивный способ разделения строк по языкам, чтобы игре не требовалось обрабатывать ненужные дополнительные файлы.
Идентификаторы строк
Затем нужно подумать об идентификаторах строк. Объём этой задачи сильно зависит от количества текстовых строк в игре. Стремитесь предугадывать проблемы при создании ID строк, давая каждой из них уникальный подробный идентификатор, позволяющий с лёгкостью найти нужную строку в будущем.
В основном выбор зависит от личных предпочтений, но не забывайте, что в будущем с вашим кодом могут работать другие разработчики.
Всегда создавайте строки с учётом будущей локализации. Наиболее частые ошибки: разная длина строк в различных языках и отсутствие подходящего перевода для строк. Не позволяйте им снижать качество скрипта, но укорачивание или перефразирование могут помочь в будущем.
Если вы выберете такой подход, процесс сохранения и загрузки локализованных строк станет гораздо проще. Вы не только снизите таким образом рабочую нагрузку, но и уменьшите риск возникновения ошибок.
5. Создавайте большинство компонентов локализации в Unity
Unity позволяет создавать компоненты, что значительно уменьшает объём разрабатываемого вручную кода. Это также снижает риск возникновения ошибок и экономит время.
Подробно о компонентах можно почитать на странице ресурсов Unity. Однако в этой статье мы сосредоточимся только на нескольких задачах:
- Возможность смены языка пользователями
- Сохранение выбранного языка
- Автоматический выбор языка при перезапуске игры
- Загрузка правильной строки для каждого значения
Большинству игроков достаточно один раз выбрать язык и закончить на этом. Один из вариантов: определить местоположение пользователя и выбрать по умолчанию местный язык. Однако, возможно, придётся добавить экран с запросом подтверждения языка при первом запуске игры. Например, не для всех американцев английский язык родной.
Способ выбора дизайна и реализации этой возможности больше относится и к UX, и к локализации. Здесь важно сохранить выбранное игроком значение (если оно было выбрано) и сохранить его как новое значение по умолчанию. После этого вам не придётся задавать один и тот же вопрос при каждом запуске игры.
Чтобы сделать это в Unity, можно создать компонент Master для назначения языка по умолчанию. Если пользователь решает сменить настройку языка, то новый язык назначается компоненту и обрабатывается как язык по умолчанию.
6. Локализация визуальных элементов в Unity
Этого не избежать, и локализация визуальных элементов игры может стать пыткой. Первое, о чём нужно подумать — это шрифты. Важен не только их внешний вид, но и поддерживаемые ими языки. Вот какие аспекты нужно рассмотреть:
- Стиль
- Языковая поддержка
- Размеры шрифтов
- Размеры файлов
Это зависит от количества языков, которые вы хотите поддерживать. Поиск шрифтов с диакритическими символами (для испанского, французского, итальянского и т.д.) не очень сложен. Но вы замучаетесь искать один шрифт, поддерживающий, например, несколько европейских языков и азиатские системы отображения. И даже если вы его найдёте, размер файла будет очень велик. Поэтому не бойтесь подбирать отдельные шрифты для разных языков, если вам нравятся их стили.
Конечно, не все тексты должны быть обязательно заданы в коде. Некоторые текстовые элементы представлены в графике. Кроме того, существуют другие различные визуальные элементы, о которых тоже нужно подумать.
Текстовая графика
Большинство элементов текстовой графики вообще не требует локализации. Например, имена персонажей остаются одинаковыми во всех языках (если вы не будете их локализовать). Поэтому всю графику с их именами (например, бейджи, значки игроков и т.д.) можно оставить неизменной.
Однако, значимые имена, в которых, например, есть метафоры или игра слов, тоже, возможно, потребуют локализации, в противном случае некоторые игроки не смогут оценить шутку. Конечно же, нужно подумать не только об именах персонажа, но и о названиях уровней, оружия и игровых предметов.
Самое важное — не пропустить текстовую графику, влияющую на геймплей. Это может быть что-то простое, вроде элемента UI внутри мини-игры, но вы будете жалеть о том, что упустили такие мелкие детали.
Как локализовать текстовую графику в Unity
Определившись с текстовой графикой, которую нужно локализовать (и с той, которую нужно оставить в покое), с помощью Unity вы сможете с лёгкостью переключаться между типами графики на основе выбранного пользователем языка. Есть три способа, каждый из которых имеет свои плюсы и минусы:
- Создание атласов в упаковщике спрайтов (Sprite Packer)
- Создание отдельной графики и вызов её при необходимости
- Замена графики текстом и элементами UI
Можно достичь такого же визуального уровня, создавая отдельную локализованную графику и вызывая её при необходимости, но это наименее эффективный подход. Если вы не будете аккуратны, игра будет работать слишком медленно.
Ещё один вариант — полностью заменить графику текстовыми строками и элементами UI. Они могут выглядеть не так хорошо, как графика, но это самый экономный с точки зрения ресурсов подход, позволяющий максимизировать скорость работы игры. Также его можно встроить в стандартный процесс локализации, передав переводчику тексты вместе с другими локализуемыми строками.
7. Используйте AssetBundle движка Unity
Бандлы AssetBundle в Unity позволяют создавать пакеты файлов, загружаемые пользователями только при необходимости. Это значит, что можно значительно уменьшить общий размер игры, в то же время предоставив полные ресурсы для любой аудитории.
Например, пользователи будут загружать только тексты на французском, если этот язык выбран основным в игре. В противном случае им не нужны эти файлы, которые будут храниться на серверах, ожидая скачивания.
Это не только значительно повышает скорость благодаря снижению количества загружаемых ресурсов, но и делает игры меньше и быстрее, что позволяет скачивать их в первую очередь. Но самое лучшее, что вам не приходится идти на компромиссы в отношении файлов и ресурсов, создаваемых для локализации. Можно предоставлять игры любой нужной аудитории и при этом знать, что пользователей не будут ограничивать ненужные им ресурсы.
Итак, это была инструкция для начинающих по локализации игр в Unity. Плохие новости в том, что невозможно выполнить её в одиночку – вам необходимы профессиональные переводчики. Однако, есть и хорошие новости: Unity делает управление процессом локализации гораздо проще.
Но движок всё-таки не может научить вас делать локализацию правильно, так что обратитесь к тем, кто поможет вам адаптировать игры под иностранную аудиторию.
Русификатор для любой игры сделанной на движке Unity
Часто, а особенно последнее время, мы встречаем игры, где русский язык отсутствует как класс. Если игра сделана на движке Unity, то это не проблема. Собственно данным способом можно перевести на любой язык эту игру, причем с любого другого. Только одно, но, эти языки должен знать наш любимый Google Translator.
Ну да не буду тянуть, давайте русифицируем игру на Unity.
- Надо скачать архив XUnity.AutoTranslator-BepIn-5x- .zipздесь .
- Затем еще архив BepInEx_x64_5.4.9.0.zipздесь (обратите внимание, в названии архива есть хы 64 или хы 86, это указывает на разрядность вашей ОСь, оперативной системы, для Unix там тоже есть).
- Распаковываем прямо в корень игры.
- Запускаем нашу игру.
- Выходим из игры, не сворачиваем, а именно выходим.
- Идем по пути \BepInEx\config\AutoTranslatorConfig.ini, заходим внутрь, в смысле открываем данный файл на редактирование.
В файле изменяем следующие настройки:
- Language=ru (на какой язык переводить);
- FromLanguage=en (язык в игре или с какого переводить);
Что еще можно поменять в файле:
- MaxCharactersPerTranslation=2500 (максимально можно поставить 2500 отвечает за длину захвата текста);
- IgnoreWhitespaceInDialogue=true (обычно надо смотреть, если с true работает норм, то это айс, если в переводе исчезли пробелы, то ставим false);
- OverrideFont= (тут можно свой шрифт прописать для перевода, он должен быть установлен в вашей ОСь);
- OverrideFontTextMeshPro= (отвечает за замену шрифтов в играх с TextMeshPro, как узнать есть в игре эта загадочная хрень, сделали все как надо, но в игре вместо русского кракозябры, признак наличия этой хрени, а значит этот параметр нам в помощь, подрубаем шрифт с криллицей).
Теперь запускаем игру и наслаждаемся магией перевода от Google Translator, правда он часто на алиэкспресском говорит, но, когда мы занимаемся нехорошим делом нас не остановить!
Еще немного о плагине, что мы поставили, в игре им можно управлять, собственно, вот:
- ALT + 0: включить интерфейс XUnity AutoTranslator. (Это ноль, а не O);
- ALT + T: чередовать переведенные и не переведенные версию всех текстов, предоставляемых этим плагином;
- ALT + R: перезагрузить файлы переводов. Полезно, если вы изменяете текстовые и текстурные файлы на лету. Не гарантируется работа для всех текстур;
- ALT + U: ручной захват. Захват по умолчанию не всегда подхватывает текст. Плагин попытается сделать поиск вручную;
- ALT + F: если настроен OverrideFont, будет переключаться между переопределенным шрифтом и шрифтом по умолчанию;
- ALT + Q: перезагрузите плагин, если он был выключен.
На этом все, ставим и наслаждаемся алиэкспресским от Google Translator. Добра вам и успеха!
Localizing Unity Games with the Official Localization Package
Unity is arguably one of the most popular off-the-shelf engines for independent game developers. Breakout indies like Cuphead, Overcooked, Hollow Knight, Ori and the Blind Forest, and Monument Valley all have Unity at the heart of their technology. Even some AAA goliaths like Blizzard’s Hearthstone are made with the engine.
If you’re making commercial games with Unity, and have been kind enough to land on our little article here, you’re probably looking at expanding your game’s global reach through internationalization (i18n) and localization (l10n). So how do you go about internationalizing and localizing a Unity game?
You could roll your own solution, use an open-source library, or maybe pay for a package from the Unity Asset Store. Another option: the good people at Unity Technologies have been hard at work on a first-party localization package. It’s in preview as we write this, but it’s not far from being released according to the Unity team, so we think it’s one to consider.
In this article, we’ll go through how to use the official Unity package to localize our games. We’ll build a small demo, primarily focused on UI and text, and proceed to install, set up, and utilize the package to localize this demo.
Our Demo Project
Our demo starts with some UI that represents some messages we might typically display in a game.
Here’s a look at our hierarchy. Nothing too crazy going on here: we’re using TextMeshPro (TMP) for our text UI rendering.
Resource » Grab the Unity project from our GitHub repo. The start branch has the demo as it is here, before localizing. The main branch has the completed project after localization.
Versions of Unity & Packages Used
Here are the versions of Unity and packages we’re using in this article:
- Unity 2019.4.19f1 (official Unity i18n package) ’s RTL Text Mesh Pro 3.2.4 (for right-to-left rendering of TMPro components)
Resource » We’re using the Pixel Art GUI Elements provided by the talented Mounir Tohami. Two Google Fonts are utilized in our project as well: Jost for Latin alphabets (English and French) and Cairo for Arabic.
A Note On Addressables
The Unity localization package is built on Addressables, a system that allows us to load assets asynchronously, locally or from the network. Covering addressables is a bit outside the scope of this guide, and the localization package is designed so we don’t need to understand addressables fully before we start localizing. In those cases where we need to interact with the addressable system directly, we’ll be sure to mention it.
Installation and Setup
Ok, let’s install the localization package. In Unity’s main menu, we’ll go to Window ➞ Package Manager.
You’ll be utterly shocked to realize that this opens the Package Manager window. On this window, let’s click the plus sign and select Add package from git URL. In the ensuing text field, we’ll enter com.unity.localization and click the Add button to install the package.
Creating the Localization Settings Asset
Once the package is installed we’ll need to create our project’s localization settings. We can do this by navigating to Edit ➞ Project Settings ➞ Localization and clicking the Create button.
This will both create the settings asset and activate it in our project. If you’re organizing your Unity project by asset types, you might want to create a Localization folder to keep your settings assets file, as well as future localization assets we’ll be creating.
Adding Supported Locales
Let’s generate the locales our game will support. We can always change this later, but for now, we’ll support Arabic (ar), English (en), and French (fr). After making sure we’re at the Edit ➞ Project Settings ➞ Localization window, we can click the Locale Generator button to create our locale assets.
We’ll be presented with a list of locales; we can check the ones we want to support and click Generate.
This will create locale assets for us, which we can place in our Localization folder.
Active Locale Resolution
The localization package will attempt to resolve the active locale at runtime depending on the Locale Selectors order in our Localization Settings.
By default, the package will:
- look for a locale specified with a command-line flag (this could be useful for automated testing, for example), and if that fails
- attempt to determine the operating system locale (System Locale) and use that, and if that fails
- use an explicitly-set locale, which we need to provide as our default locale.
✋ Heads up » The package will fall back on more generalized locales if it needs to. For example, if the locale resolution settles on en-CA (Canadian English) as the active locale, and doesn’t find that exact locale in the list of supported locales, it will attempt to fall back to the more general en if en is supported.
Setting the Default Locale
We can specify the default locale the package will use when it can’t determine the locale another way by going expanding the Specific Locale Selector section under Locale Selectors. From there, we can click the search target circle at the end of the Locale Id field and select one of our supported locales.
We’ll select English for our project. Now, if all other locale-resolution strategies fail, our game will default to English as the default runtime locale.
Note » You can alter the order of the resolution strategies by dragging their rows in the Localization Settings window. We’ll use this later to force a default locale instead of using the one set in the user’s operating system when testing our production builds.
Managing Translations
The official localization package will have us creating string table collections and populating them with translatable strings that we can then use in our components.
Creating a Strings Table Collection
To create a new collection, we can go to Window ➞ Asset Management ➞ Localization Tables and click the New Table Collection button.
After selecting which locales will be covered by the table, we can give our table a name and click Create String Table Collection. I’ve called my table UI and, when prompted, opted to save it under Localizations/Table Collections/UI . A handful of files related to this table will now live in that folder.
Note » You may have noticed a Create Asset Table Collection button on the Localization Tables window. This is because the official localization package can localize not only strings, but textures, audio, ScriptableObjects, and more. Check out the official Quick Start Guide for more info.
Adding Translated Strings
With our strings table collection in place, we can now start adding our translations to it.
Clicking Add New Entry creates a new row in our table. We should give our row a Key , which we’ll use to refer to this entry in our components. And we can add a translation string for each of our supported locales.
Note » You can open localized table collections at any time by going to Window ➞ Asset Management ➞ Localization Tables.
Right-to-Left Text
Before we go further, I want to make a short stop and tackle right-to-left (RTL) text rendering using TextMeshPro in Unity. TMP currently has no official support for RTL. The Unity team are working on it, but in the meantime, we have to use third-party packages for RTL rendering. I’ve opted to use Peyman Narimani’s open-source RTL Text Mesh Pro since it worked well for me. Let’s go over how to use it in our project.
Note » If you’re not supporting a RTL language in your game, feel free to skip this section.
Installing RTL Text Mesh Pro
To get started with RTL Text Mesh Pro (RTLTMP), we can head over to the library’s releases page and grab the latest release. The .unitypacakge file associated with the release makes for easy installation into our project.
Note » As I write this v3.3 is the latest stable release. However, there’s an issue with this release that causes Arabic numbers to be rendered right-to-left. While Arabic is a right-to-left language, its numbers are written left-to-right. So I’ve stuck with v3.2.4, which worked fine for me. By the time you read this, the RTL number issue may have been fixed in more recent releases.
✋ Heads up » If you are using v3.2.4 of RTLTMP, make sure to update this line of code to match our repo to avoid compile errors in newer versions of Unity.
With the .unitypackage file on hand, we can head over to Unity and go to Assets ➞ Import Package ➞ Custom Package. We can then select the .unitypackage file, keep all the folders and files checked, and click Import. This should install the package, creating a new folder in our project called RTLTMPro .
The RTL Text Mesh Pro Component
Ok, let’s add our RTLTMP components so that we can get RTL text rendered in our game. In our hierarchy, we can right-click the game object we want to add our component to, and select one of the new UI/* — RTLTMP components.
You’ll notice that the RTLTMP package has added a corresponding RTL component for each native TextMeshPro component. Let’s add a Text — RTLTMP component.
That’s about it. The new text component can be used exactly like a normal TextMeshPro component. We just need to make sure to provide an RTL font asset under the Font Asset field. RTLTMP comes with some RTL font assets that we can use in our projects. They reside in Assets/RTLTMPro/Fonts and support at least Arabic and Farsi. We also need to add our RTL text to the RTL Text Input Box.
Works like a charm. “What about localization,” I hear you asking? Localizing RTLTMP components is exactly like localizing TextMeshPro components, and we’ll cover that next.
Note » Instead of using the font assets that come with RTLTMP, we could make our own. I’ve created a font asset based on the Cairo Google font and added it to our GitHub repo. I should mention that I found creating my own usable RTL font to be a bit tricky, and needed to tweak the font asset settings to make it render with the Arabic characters looking correctly connected (kind of ). If you want me to dive deeper into custom RTL font creation, let me know in the comments below.
Localizing TextMesh Pro Text
We’ve done enough setup methinks. Let us localize, fellow devs. First, we’ll create either a TMP or RTLTMP component, depending on whether or not we’re supporting RTL text (see the previous section if you are). We localize the component by adding a Localize String Event component to the game object.
The Localized String Event component is provided by the official Unity localization package. It allows us to use a translation entry from one of our string table collections, providing it to one of our other components. We do this by hooking into the Update String event of the component.
First, we’ll make sure we have a translation in our previously created string table collection. We can head over to Window ➞ Asset Management ➞ Localization Tables and make sure that the Selected Table Collection is the one we created previously (I called mine UI ).
We can then click the Add New Entry button at the bottom of the window, and enter a Key and translation for our entry. I’m adding a new_ability_discovered key to my table.
Now we can head back over to our hierarchy and provide the key we just added to the String Reference field on our Localized String Event component.
We should also add an item to the Update String list. This works like a normal Unity event: we drag the game object that we want to update to the object field. In our case, this is the object that houses our TMP component. We then use the function dropdown to select TextMeshPro ➞ Text (or RTLTextMeshPro ➞ Text).
Now, when the locale changes (or when the localization system initializes), our TMP text will render its text in the active locale. We can run our game and use the debugging locale switcher in the top-right of the Game view to test this.
Our first translation. Take pride, friends. As per usual with Unity, there’s a bit of setup and learning to get localization working, but the system is quite powerful and flexible as we’ll see.
Note » A handy shortcut: instead of adding the Localized String Event component manually, we can also right-click the TMP (or RTLTMP) component and select Localize. This adds the localizing component and wires it update event automatically. We just have to select our translation key and we’re off and running.
Interpolation
We often want to include dynamic text in our translated strings. Something like “Axion55 stole the flag!”, where “Axion55” is a username that can change at runtime. Let’s see how we can use Smart Strings to achieve this with Unity localization.
We’ll add a new entry to our string table collection.
I’m adding a string that reads “
We can use the Debug toggle next to a translation to see if we’ve formatted our text correctly for the Smart Strings system. We’ll get syntax highlighting in debug mode that should indicate whether our text is correct or not.
Now we can provide the actual value to our Localized String Event component so that it will be used at runtime. First, let’s create a trivial MonoBehaviour to house our value.
Next, let’s wire this to our Localized String Event component.
We can add the Values script as a component to our game object and drag it into the Format Arguments collection in our Localized String Event component. Of course, we also need to make sure that we’ve selected the correct key in the String Reference field of our Localized String Event. Now our TMP component will show our translations with the Values.Character value interpolated.
Note » The string in the value-providing component must have the exact same name as the variable in our translation string ( Character in the previous example).
This gives us basic interpolation, but it won’t update the TMP text if Values.Character changes at runtime. We’ll explore how to update translated text when its variable dependencies change when we add more sections to this article in the coming weeks, so check back soon.
✋ Heads up » If you’re using RTLTMP (see above), make sure to select the Force Fix option on the component if your text begins with left-to-right text. Otherwise all the text the component renders will be left-to-right.
Resource » Unity’s localization package uses a fork of the popular C# Smart Strings library for its dynamic string formatting. Smart Strings is a drop-in replacement for the native .NET string.Format(). This means that any format strings that we can use with string.Format can also be used with Smart Strings. We go into this a bit later when we cover number and date formatting.
Plurals
“You have found a golden swords!” Oops. We can do better with our plurals. Luckily, Smart Strings have excellent support for dynamic plural strings. Let’s add a new key to our string table collection to see this in action.
We’re interpolating a count value in our translations. Let’s take a look at the English format and break it down.
ComboPointCount is the integer value that we’ll use to determine the plural format to use. English has two plural formats: one and other. We can add these to our translation in order, separated by a | character. <> is a placeholder that will be swapped out for the value of ComboPointCount at runtime. And we use the optional :plural: designation to make it clear what the intention of our format is. This will render as follows in English.
French, like English, has two plural forms, so its format is similar to the English one. Arabic, however, has six plural forms: zero, one, two, few, many, and other. As the figure above demonstrates, we provide those forms as we do in English, in order and separated by a | . Our Arabic translation then renders like so:
Notice that Smart Strings is smart enough to know that Arabic has six plural forms. We don’t have to do anything other than provide those forms.
✋ Heads up » For each translation, make sure to provide all the language’s plural forms, or you’ll get errors when the localization library can’t find the form corresponding to the given count.
Of course, to get this rendering we need to add our new key to a Localized String Event that updates a TMP component. And just like we did in the previous Interpolation section, we must also provide this component with a modified Values MonoBehaviour that looks like the following.
Resource » The Unicode CLDR charts are an excellent listing of per-language plural rules for your perusal.
Number Formatting
Smart Strings can also be used to interpolate localized numbers. By default, numbers will get formatted per the rules of their locale. A new entry in our string table collection can help demonstrate.
In addition to the normal
Note that we’re seeing the currency, thousands separator, and decimal separator in each locale. English (en) defaults to US English, so its currency is formatted as US dollars. French (fr) defaults to France French, so it gives us Euros. Arabic (ar) defaults to Saudi Arabian Arabic, so its currency is displayed as Saudi Riyals.
Resource » We have complete control over the formatting of our numbers because we can use all .NET format specifiers with Smart Strings. In the example above we’ve used a standard numeric format string to specify currency. We can also use custom numeric format strings to exert more granular control over our number formatting.
Date Formatting
Similar to number formatting, we can control date formats with Smart Strings as well. Let’s add a new entry to our string table collection that displays a date.
d MMM is a custom date format specifier that results in the numeric day of the month, followed by the abbreviated name of the month, in the given date. We can update our Values MonoBehaviour with a Date value and wire everything up to a Localized String Event to see the translated rendering.
The above dates are presented in the calendars of their respective locales. English and French are using the Gregorian calendar whereas Arabic is using the Hijri calendar. This is because English (en), French (fr) and Arabic (ar) use the USA, France, and Saudi Arabic locales by default.
Resource » In addition to custom date formats, we of course also have standard date formats.
Previewing & Building
We’ve already touched upon the locale game view menu dropdown that we can use to preview different translations in play mode. This can be quite handy when developing.
Note » You can turn the locale game view menu dropdown on or off in Unity preferences under Localization.
What about standalone builds? Well the simplest solution to preview translations in standalone builds is to force a locale from our Locale Settings.
Setting the Locale Id in the Specific Locale Selector and moving the selector to the top of the list will ensure that our set locale will resolve as the active one at runtime.
Because the localization package uses addressables, we have to build our addressables groups before we can get our updated translations in our standalone builds. To do this, we head over to Window ➞ Asset Management ➞ Addressables ➞ Groups. From there, we can click Build ➞ New Build ➞ Default Build Script to build our addressables groups.
We can now build for our target platform to test our translations for production.
✋ Heads up » During my research I experienced a known issue with translations not appearing when I was using the addressables package v1.16.16. Reverting the package back to v1.16.15 seemed to resolve the issue.
Fallback
Sometimes we will have missing translations in our projects. There a few ways to deal with this, and we can set our chosen strategy in Localization Settings.
The Missing Translation State field can be set to show a warning message instead of the translated string (default). This warning will appear in production as well. Another option is to Print Warning, which will show the warning in the console and render an empty string for the translation.
We can also check the Use Fallback checkbox to use locale fallbacks for the whole project. This will cause a translation missing in say, French, to “fall back” to its English counterpart. If we go this route we need to make sure to set our fallback locales on each local we want to fall back. Selecting one of the locale assets in our project reveals its details in the Inspector. From there we can find the Metadata collection and add a Fallback locale to it.
Now when we have a missing French translation, its less-cool English cousin will be shown to the player instead.
Note » We don’t have to set the Fallback option on a per-project level. We can choose to set it on individual Localized String Events instead.
GG WP
We hope you’ve enjoyed this guide to using the official Unity localization package to localize your Unity games. Kudos to the Unity team for constantly developing the engine and empowering developers to make awesome games. And we’re not done! Stay tuned in the coming weeks as we add more sections to this article. I’m especially looking forward to the sections around scripting and the localization package.
Resource » Get the project we’ve built here from our GitHub repo.
And if you’re looking for a professional localization platform for your growing team, check out Phrase. Built by developers for developers, Phrase features a powerful API, flexible CLI, GitHub/Bitbucket/GitLab sync, webhooks, machine translation, and a rich web-based translation console for your translation team. Check out all of Phrase’s features and sign up for a free 14-day trial to let Phrase do the heavy lifting in your localization process, keeping you focused on the creative code you love.
Продолжаем уроки! Создание локализации на Unity
Всем привет! Создание уроков по Unity продолжается, на этот раз разбираем тему создания локализации. Приятного просмотра!
Прошлый урок:
1. Обращение к UI элементам (Text, Image и т.д. ) — это довольно затратный метод. Менять кучу текстовых объектов в апдейте просто ради смены языка — это бессмысленная трата ресурсов. Сотня-другая таких объектов и одна только смена языка будет отжирать 25-50% производительности.
Решений тут два: первое и самое простое — вызывать проверку языка только один раз при старте сцены. При смене языка сцену нужно будет перезапустить.
Второй вариант — подписать метод смены языка на определенное событие через корутины. Проверка смены языка будет вызываться лишь один раз, при нажатии на определенную кнопку. Смысла в этом особого нету — лишний код ради функции, которую игрок за всю игру активирует единожды.
Поэтому оптимально будет сделать данный функционал только в главном меню. Если так уж нужна смена языка "на горячую" и без перезапуска, то лучше привязать элементы главного меню именно к нажатию кнопки, но никак не плодить кучу Update() там, где это не нужно.
2. Сам метод работы с локализацией удобоварим, если у тебя текста на пару десятков объектов. В ином случае, ты замучаешься работать с таким объемом окошек и объектов. Лучший метод для работы с текстом — вешать в скрипт объекта только его ID. В объекте должен быть только персональный ключ и всё. А весь остальной функционал нужно вызывать из некого синглтона, в котором и находятся все методы для работы с текстом.
То есть, ровно так же, как ты создал статическую переменную со значением текущего языка, ты создаешь целый статический класс, с методами и текстовыми массивами. В эти методы и обращается твой текстовый объект при старте. Он отсылает свой ID и получает по нему текст, который к себе применит.
Это обязательно нужно делать, потому что текстовых файлов у тебя может быть тысячи и при смене методов работы с локализацией, тебе нужно будет перенастроить их ВСЕ. Поэтому их функционал не должен содержать никаких уникальных данных, кроме одного — ключа, ID, который определяет, что именно это за слово или текст. А вот синглтон у тебя один. И менять его ты можешь как и сколько хочешь, без ущерба для своих объектов.
3. Сами текстовые данные лучше хранить в отдельном текстовом файле. Какая там будет верстка и формат — вопрос открытый. Кому-то гугл-таблицы нравятся, а кому-то html-формат — самое оно. Но это актуально, если у тебя объем текста выше 30 слов и далеко не пара языков на выбор.