Как перевести игру на юнити
Локализация игр и приложений в Unity. Быстро и удобно
Привет! В этой статье я поделюсь своим опытом локализации игр и приложений в Unity, а также расскажу о своем плагине Simple Localization, который доступен в Asse Store. Уровень статьи — Easy. Кода не будет вообще, он вам не пригодится.
С точки зрения общей концепции все просто. У нас должен быть список словарей для каждого языка с одинаковыми ключами, из которых мы и будем получать локализованные значения. С технической стороны нужно определить:
Формат будет следующий: первая колонка — ключи, все последующие колонки — словари. Первая строка — заголовок. Можно иметь один общий CSV, если текстов в приложении немного, а можно разбить на несколько CSV по какому-либо принципу, например: меню, настройки, достижения и т.д.
Идем дальше. Редактирование локализации в Excel, это, конечно, здорово, но я предлагаю загрузить их в Google Sheets. Тогда редактировать их можно будет из любого места, в любое время и с любого устройства. Но самое главное — локализацию можно будет расшарить переводчикам, и у них не будет никаких сложностей с переводом. Посмотреть на словарь можно по ссылке.
И последний пункт — интеграция с Unity, с uGUI. Тут тоже все просто — на каждый текстовый компонент Text добавим свой компонент LocalizedText, в котором укажем ключ. При запуске этот компонент получит локализованное значение и установит его в Text.
Дальше возникает несколько вопросов:
Скачать можно в Asset Store: Simple Localization.
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 поддерживает множество форматов, самые популярные из них это:
Если вы разрабатываете игру на JavaScript, то правильнее всего будет использовать JSON. Это простой и лёгкий формат, используемый множеством разработчиков в течение долгих лет. Кроме того, он быстр в обработке. Кроме преимуществ для разработчика, он очень лёгок в чтении даже для тех, кто не занимается разработкой. Это важный плюс для будущих переводов и правок.
Многие разработчики по-прежнему работают с XML, и это хороший выбор, если вы предпочитаете работать именно с этим языком разметки. Это не самый эффективный язык и его сложнее читать, так что учтите это при создании игры.
С точки зрения переводов другие варианты значительно более проблематичны, но вам нужно придерживаться того языка, который наиболее удобен. Плотно взаимодействуйте с переводчиком, чтобы как можно больше упростить его работу, потому что это снизит количество ошибок.
4. Определитесь со структурой строк
Подбор самого эффективного способа структурирования строк может стать настоящей проблемой. Для этого процесса нет чётко заданных инструкций. Unity предоставляет разработчику свободу в выборе структуры. Свобода — это, конечно, всегда хорошо, но она и увеличивает вероятность ошибок.
Существует три основных фактора, влияющих на структуру строк:
Для большинства игр (в которых выбор языка сохраняется в самом начале) можно хранить строки в отдельных файлах для каждого языка (например, en.json, es.json, fr.json и т.д.). Это наиболее продуктивный способ разделения строк по языкам, чтобы игре не требовалось обрабатывать ненужные дополнительные файлы.
Затем нужно подумать об идентификаторах строк. Объём этой задачи сильно зависит от количества текстовых строк в игре. Стремитесь предугадывать проблемы при создании ID строк, давая каждой из них уникальный подробный идентификатор, позволяющий с лёгкостью найти нужную строку в будущем.
В основном выбор зависит от личных предпочтений, но не забывайте, что в будущем с вашим кодом могут работать другие разработчики.
Всегда создавайте строки с учётом будущей локализации. Наиболее частые ошибки: разная длина строк в различных языках и отсутствие подходящего перевода для строк. Не позволяйте им снижать качество скрипта, но укорачивание или перефразирование могут помочь в будущем.
Если вы выберете такой подход, процесс сохранения и загрузки локализованных строк станет гораздо проще. Вы не только снизите таким образом рабочую нагрузку, но и уменьшите риск возникновения ошибок.
5. Создавайте большинство компонентов локализации в Unity
Unity позволяет создавать компоненты, что значительно уменьшает объём разрабатываемого вручную кода. Это также снижает риск возникновения ошибок и экономит время.
Подробно о компонентах можно почитать на странице ресурсов Unity. Однако в этой статье мы сосредоточимся только на нескольких задачах:
Большинству игроков достаточно один раз выбрать язык и закончить на этом. Один из вариантов: определить местоположение пользователя и выбрать по умолчанию местный язык. Однако, возможно, придётся добавить экран с запросом подтверждения языка при первом запуске игры. Например, не для всех американцев английский язык родной.
Способ выбора дизайна и реализации этой возможности больше относится и к UX, и к локализации. Здесь важно сохранить выбранное игроком значение (если оно было выбрано) и сохранить его как новое значение по умолчанию. После этого вам не придётся задавать один и тот же вопрос при каждом запуске игры.
Чтобы сделать это в Unity, можно создать компонент Master для назначения языка по умолчанию. Если пользователь решает сменить настройку языка, то новый язык назначается компоненту и обрабатывается как язык по умолчанию.
6. Локализация визуальных элементов в Unity
Этого не избежать, и локализация визуальных элементов игры может стать пыткой. Первое, о чём нужно подумать — это шрифты. Важен не только их внешний вид, но и поддерживаемые ими языки. Вот какие аспекты нужно рассмотреть:
Это зависит от количества языков, которые вы хотите поддерживать. Поиск шрифтов с диакритическими символами (для испанского, французского, итальянского и т.д.) не очень сложен. Но вы замучаетесь искать один шрифт, поддерживающий, например, несколько европейских языков и азиатские системы отображения. И даже если вы его найдёте, размер файла будет очень велик. Поэтому не бойтесь подбирать отдельные шрифты для разных языков, если вам нравятся их стили.
Конечно, не все тексты должны быть обязательно заданы в коде. Некоторые текстовые элементы представлены в графике. Кроме того, существуют другие различные визуальные элементы, о которых тоже нужно подумать.
Большинство элементов текстовой графики вообще не требует локализации. Например, имена персонажей остаются одинаковыми во всех языках (если вы не будете их локализовать). Поэтому всю графику с их именами (например, бейджи, значки игроков и т.д.) можно оставить неизменной.
Самое важное — не пропустить текстовую графику, влияющую на геймплей. Это может быть что-то простое, вроде элемента UI внутри мини-игры, но вы будете жалеть о том, что упустили такие мелкие детали.
Как локализовать текстовую графику в Unity
Определившись с текстовой графикой, которую нужно локализовать (и с той, которую нужно оставить в покое), с помощью Unity вы сможете с лёгкостью переключаться между типами графики на основе выбранного пользователем языка. Есть три способа, каждый из которых имеет свои плюсы и минусы:
Можно достичь такого же визуального уровня, создавая отдельную локализованную графику и вызывая её при необходимости, но это наименее эффективный подход. Если вы не будете аккуратны, игра будет работать слишком медленно.
Ещё один вариант — полностью заменить графику текстовыми строками и элементами UI. Они могут выглядеть не так хорошо, как графика, но это самый экономный с точки зрения ресурсов подход, позволяющий максимизировать скорость работы игры. Также его можно встроить в стандартный процесс локализации, передав переводчику тексты вместе с другими локализуемыми строками.
7. Используйте AssetBundle движка Unity
Бандлы AssetBundle в Unity позволяют создавать пакеты файлов, загружаемые пользователями только при необходимости. Это значит, что можно значительно уменьшить общий размер игры, в то же время предоставив полные ресурсы для любой аудитории.
Например, пользователи будут загружать только тексты на французском, если этот язык выбран основным в игре. В противном случае им не нужны эти файлы, которые будут храниться на серверах, ожидая скачивания.
Это не только значительно повышает скорость благодаря снижению количества загружаемых ресурсов, но и делает игры меньше и быстрее, что позволяет скачивать их в первую очередь. Но самое лучшее, что вам не приходится идти на компромиссы в отношении файлов и ресурсов, создаваемых для локализации. Можно предоставлять игры любой нужной аудитории и при этом знать, что пользователей не будут ограничивать ненужные им ресурсы.
Итак, это была инструкция для начинающих по локализации игр в Unity. Плохие новости в том, что невозможно выполнить её в одиночку – вам необходимы профессиональные переводчики. Однако, есть и хорошие новости: Unity делает управление процессом локализации гораздо проще.
Но движок всё-таки не может научить вас делать локализацию правильно, так что обратитесь к тем, кто поможет вам адаптировать игры под иностранную аудиторию.
Интеграция текста в Unity
Появившись в 2005 году, среда разработки Unity постепенно завоевала огромную популярность. Поддержка более двух десятков платформ (персональных компьютеров, игровых консолей, мобильных устройств, интернет-приложений), визуальная среда разработки и модульность пришлись по вкусу всем — как инди-разработчикам, так и большим опытным командам. Мы расскажем вам о нескольких неочевидных технических проблемах локализации проектов в Unity, чтобы когда-нибудь перед вами в самый неподходящий момент не возникла необходимость основательно переделывать проект.
Шрифты
С чего начинается внутриигровой текст? Конечно, со шрифта.
Стандартным средством работы со шрифтами в Unity является компонент UI Text. Однако в 2018 году в Unity появился новый компонент: TextMesh Pro — и нет причин им не пользоваться.
В TextMesh Pro работа со шрифтами реализована через элементы Font Asset.
Если вы будете создавать отдельный Font Asset для каждого языка и копировать в него все символы соответствующего этому языку шрифта, то увеличите объем сборки и снизите быстродействие игры. Ваши игроки это точно не оценят, поэтому процесс требует оптимизации. Решение простое: объединить языки в Font Asset’ы по системе письменности (латиница, кириллица и т. п.) и в дальнейшем комбинировать эти группы.
Для начала рассмотрим простой случай: языки с алфавитной письменностью.
Создадим латинский Font Asset и включим в него все символы расширенной таблицы ASCII. Затем создадим один Font Asset с кириллицей. Подключим кириллический Font Asset к латинскому как Fallback (т. е. дополнительный набор, к которому игра обращается при отсутствии нужного символа в основном наборе). Можно подключить неограниченное количество элементов Fallback, поэтому все языки Европы умещаются всего в нескольких FontAsset’ах!
Алгоритм, по которому игра ищет нужный символ в наборах (например, при пользовательском вводе), выглядит следующим образом:
Языки с иероглифической письменностью требуют иной стратегии.
Вот пример для японского:
Алгоритм поиска выглядит так:
Для упрощенного китайского:
Для наглядности изобразим отношения подмножеств иероглифов на диаграмме:
*Table of General Standard Chinese Characters
Параметры Sampling Point Size и Padding
С параметром Sampling Point Size тесно связан параметр Padding. Он определяет ряд визуальных эффектов текста: интервал между символами в тексте, смещение тени или сияния символов, толщину контура символов и т. д. Рекомендуется выбирать значение Padding, лежащее в пределах 7–10 % от Sampling Point Size. Так, для Sampling Point Size = 72 лучше выбрать Padding = 6.
Подключая Font Asset в качестве Fallback к основному Font Asset, убедитесь, что соотношение Sampling Point Size / Padding в подключаемом Fallback’е равно или кратно этому же соотношению в основном FontAsset — иначе символы из разных наборов будут отрисовываться по-разному.
Например, в Primary Font Asset мы задали соотношение Sampling Point Size / Padding = 72/6. Тогда для элемента Fallback выберем соотношение Sampling Point Size / Padding = 48/4 (или даже 36/3).
Подробная информация о создании элементов Font Asset приведена здесь.
Словари
Разобравшись со шрифтами, перейдем к смыслу ваших внутриигровых текстов.
Чтобы игроки в Германии имели шанс понять, что написано на экране, по меньшей мере нужно, чтобы оригинал и перевод соответствовали друг другу. Такие соответствия собираются в отдельные текстовые файлы, называемые в локализации «словарями». Информация в словарях организована в виде пар «ключ: значение». Ключом может быть ID строки или даже сам исходный текст, а значением должен быть перевод этой строки на требуемый язык.
В самом начале работы над проектом нужно ответить на фундаментальный вопрос — какой формат должен иметь словарь? Unity поддерживает около десятка форматов текстовых файлов, но наибольшее распространение у локализаторов получили пять: JSON, XML, YAML, CSV и PO. На последних двух остановимся подробнее.
Формат CSV
Простейший формат для словаря — CSV (Comma-Separated Values). В таком файле хранятся данные, разделенные запятой (или точкой с запятой). Универсальность этого формата позволяет работать с этими файлами в любом табличном процессоре, а также загружать их в специализированные средства автоматизированного перевода (memoQ, Trados и т. п.).
В первом столбце словаря следует расположить ключи, а в остальных —значения:
Если ваш проект не предполагает десятков тысяч слов и вы допускаете фанатскую помощь в локализации, то хорошим выбором для вас станет платформа Google Spreadsheets. Синхронизацию онлайн-словарей в Google Spreadsheets и текста в проекте можно автоматизировать с помощью бесплатного плагина Simple Localization.
Формат Portable Object
Файлы человеко-читаемого формата PO (Portable Object) предусмотрены стандартом gettext — библиотекой проекта GNU для интернационализации. Отличие этой библиотеки в том, что в ней в качестве идентификаторов строк используются сами исходные строки на английском языке, а не замысловатые конструкции. Это несколько облегчает работу, если внутриигровые тексты вы изначально пишете на английском. Кроме того, в библиотеке gettext есть поддержка множественного числа — пользу такой функции для локализации трудно переоценить.
Каждая запись в файле PO содержит связь между оригинальным фрагментом текста и соответствующим ему переводом. Как правило, один файл PO заводится на один язык перевода. Типовая запись в файле PO выглядит так:
#: ссылка на исходный код программы
# | msgid предыдущая строка (на английском)
msgid исходная строка (на английском)
msgstr перевод строки
Подробное объяснение элементов файла PO можно найти здесь.
Важной частью локализации является файл формата POT (Portable Object Template) — заготовка файла PO для перевода на другой язык. Файлы POT используются для создания новых файлов PO в редакторе и для обновления файлов PO при добавлении новых переводов. Файлы POT имеют такую же структуру, что и файлы PO, только строка для переведенного текста пустая.
Переведенные строки не нужно добавлять в файлы PO напрямую — следует обновлять файлы PO из файлов POT. Для этого вам нужен специальный текстовый редактор. Самым популярным редактором файлов PO является Poedit.
Порядок действий выглядит примерно так:
Подробную информацию о локализации с помощью файлов PO и листинги скриптов можно найти здесь.
Теперь вы знаете несколько подводных камней и течений локализации в Unity — значит, она вам уже не так страшна.
Как перевести игру на юнити
Привет начинающим и не очень разработчикам игр на Unity, и вы не задумывались о том, что вероятнее всего вашу игру нужно будет переводить на другие языки? Встретился с этим вопросом недавно и решил проблему способом, о котором написано ниже, интересно узнать, а не костыльно ли получилось?
Вот как решил проблему я:
Итак, наша абстрактная игра будет переведена на несколько языков: для примера на Русский и Английский.
Для этого я создаю небольшой класс «Localization» В котором задаю перечисление языков и статическую переменную, содержащую один из элементов выше указанного перечисления. Статическая эта переменная потому что переведена будет вся игра, и создавать экземпляра нашего класса будет не нужно.Класс так же статический.
Вот мой код класса «Localization»:
Сам скрипт в игре никуда ставить не нужно, просто оставляем его в ассетах.
Теперь мы имеем простую систему, по которой уже можно переводить все другие объекты в игре.
Простой пример: отрывок скрипта HealthBar-а:
Таким образом можно переводить вообще всё: даже текстуры другие ставить (что полезно, согласитесь.)
Полагаю, проблем с изменением такой переменной не возникнет, перед игрой делаем 2 кнопки с названием языка, какую игрок выберет на такой игра и будет переведена. Меня правда напрягает, что выбор языка происходит прямо в момент действия с текстом, но я не замечал что то плохое в работе такой системы.
А как думаете вы? Возможно, есть варианты проще или практичней? Если это так, то вы всегда можете написать об этом ниже. Ну а если всё хорошо, то FrankyDoll был рад вам помочь!
Система локализации в Unity с точки зрения разработчика
Автор: Роман Ильин · 21 Окт 2020
Про что статья
Мы сделали систему локализации. Рассказываем как работает и в чем смысл делать свою систему, а не брать готовую.
Когда-то мы с Александром Штаченко писали статью на эту тему http://progamedev.net/localization/ (с упором на общие моменты). В этой статье больше про наше решение будет.
Кому статья будет полезна: тем кто собирается разрабатывать свою систему локализации (или писать на неё ТЗ), тем кто выбирает готовую систему локализации для своего проекта и не знает на что смотреть, тем кто хочет починить процессы, связанные с локализацией, но пока не понимает на что обратить внимание и как именно чинить.
С чего всё началось
В 2005 году мы отдали на локализацию локкит игры «Магия Крови». Переводили в сумме на 13 языков четырьмя командами локализации. В процессе конечно же появились правки и пришлось синхронизировать разные версии локкитов от разных команд перевода. То что мы вообще её перевели и выпустили — частично заслуга крутанов от нашего издателя Deep Silver, которые параллельно сами делали LQA, и вообще с ними было очень комфортно работать.
Кратко опишу с какими проблемами мы столкнулись:
Постановка задачи
В итоге когда в своей студии я решил сделать систему локализации, то постарался учесть все эти проблемы на этапе подготовки ТЗ. Мы выписали что нам нужно уметь делать (“типовые сценарии”) и что нам точно не понадобится (“точно не нужно”). Параллельно мы изучили все существующие на тот момент системы локализации для Unity и частично для веб, чтобы не изобретать велосипед, и только потом начали делать свою.
Для кого эта тулза и какие задачи она решает
Система локализации которую мы делали — прежде всего для разработчиков. Она НЕ для переводчиков. Поэтому в ней нет памяти переводов, подсчета повторов, расчета стоимости и других функций, которыми пользуются переводчики.
Также эта тулза не занимается доставкой контента (загрузка на CDN, версии билдов и т.п.), это задача другой системы.
Что нам не понадобится
Пример компонентного подхода:
Пример подхода с добавлением из кода:
Типовые задачи
Псевдо-локализация
Псевдо-локализация — это метод тестирования локализации вашего приложения на ранних этапах разработки, до того как вы действительно начнете делать перевод на другие языки. Суть в генерации машинного перевода и подстановке его в качестве текущего. Позволяет обнаружить проблемы, которые могут возникнуть при после вставки реального перевода.
Типичные проблемы, которые так можно решать:
Желательно, чтобы система локализации позволяла решать большую часть этих проблем, а также допускала возможность использования псевдо-локализации на любом этапе.
Машинный перевод у нас очень легко получить с помощью функции =googletranslate в выгрузке. Также предусмотрен импорт строк как нефинальных и исправление множества мелких ошибок, которые возникают при машинном переводе (например, вставка лишних пробелов или замена подчеркиваний).
Для тестирования интерфейсов добавлен “самый длинный” язык, что позволяет протестировать интерфейсы один раз вместо нескольких.
Для шрифтов есть отдельная утилита проверки на то, есть ли нужные глифы в них.
Пайплайн работы с переводами со стороны разработчика
Избежать примерно половины проблем с которыми мы столкнулись при локализации «Магии крови» можно двумя простыми действиями: добавить версионность текстов и отделить хранящиеся в игре тексты от отдаваемых на перевод.
Подходы: редактирование с выгрузкой и без неё
Мы используем второй подход. Любые изменения в базовом языке лок-кита (с которого переводится всё) обязательно выгружаются на перевод или проверку и (после проверки/правок переводчиком) загружаются обратно. У каждой строки есть версия перевода, которая увеличивается при изменениях текста базового языка. Это также решает проблему нескольких версий лок-кита и их синхронизации.
Также мы добавили возможность загрузки перевода как “временного”: мы можем выгрузить базовый язык, перевести его гугл-транслейтом на 10 разных языков, импортировать в проект как “временную” версию перевода и играть с плохим переводом, при выгрузке “того что нужно перевести” будет каждый раз выгружаться весь список этих строк. В колонке es-old будет “неактуальная” (или просто предыдущая) версия испанского перевода, переводчик может перевести нормально и вставить правильное значение.
Ключи локализации и генерация кода
Помимо простой работы с ключами мы используем генерацию C#-кода (для unity3d) чтобы было удобнее работать с локализацией из кода. Для этого у каждой строки есть флаг Static. Если флаг выставлен, то будет генерация метода в классе. Отсутствие таких строк вызовет ошибку времени компиляции, таким образом мы проверяем что не удалили и не переименовали важную строку (например, в интерфейсе).
Бывают два вида строк: статик и обычные. Обычные доступны только по ключу-техимени (GetTextById(«…»)). Для статик генерируется код, и можно обращаться к ним ещё и как к методу (соответственно если в коде написано LL.interface_block_window_button_reload() а ключа такого нет, то не соберется билд просто).
Все ключи-техимена имеют осмысленные имена и разделены точками. В редакторе сделана группировка (folding) по точкам. По точкам автоматом разбивается на группы (с вложенностью). Например, ключи interface.* будут в одном месте. Внутри interface. будет группировка по окнам, например interface.window_shop.* и все ключи, относящиеся к этому окну будут вместе.
Для временных ключей мы заранее заводим один статик LL.not_localized(«…») и всё так пишем. Очень просто потом в коде искать и заменять нелокализованные тексты.
Для каждой строки есть возможность добавлять комментарии для переводчиков и тех кто работает с текстом. Например, делать линки на другие строки (чтобы понимали о каком предмете идет речь в диалоге), ограничивать размер в символах или просто написать “это сообщение выводится, когда нет достаточного кол-ва софт-валюты”. При генерации кода эти подсказки также попадают в код, как подсказки методов. А при выгрузке локкита в столбец комментариев.
Для каждого ключа есть:
Языки
Поддержка импорта-экспорта в гуглодоки.
Можно выгрузить перевод (целиком или только непереведенное) в гуглодок, поправить там и импортировать обратно.
Важный момент: нельзя руками поправить перевод. Вообще никак. Можно только выгрузить, поправить и импортнуть. Все правки переводов только через импорт-экспорт делаются. Это позволяет избежать большого кол-ва проблем при работе над постоянно изменяющимся проектом. Ситуаций когда один раз перевели и больше ничего не меняется я не встречал ни разу.
Экспорт можно сделать для одного или нескольких языков. Импорт по одному или несколько сразу.
В выгрузке указывается версия ключей для базового языка (последняя на момент выгрузки), старая версия переводов, место для нового перевода (если не надо переводить, то там сразу будет копия старого текста), подсказки и комментарии.
Не так давно гугл поменял API и старые методы работы с гуглотабличками частично перестали работать (стали возвращать пустые данные). Мы уже перевели всё на новый API, если у вас похожая проблема, то просто перейдите на новый API.
Поддержка параметров в тексте локализации.
Можно вставлять параметры вида , параметры с одинаковым именем считаются за один. Код для статиков генерируется. В сгенерированный класс сразу можно будет передавать параметры, проверка на кол-во аргументов и подсказки добавляются автоматически.
Что при экспорте можно выбрать
При экспорте в гугл-таблице для каждого не-базового языка будет 2 столбца: old_en и en
В первом старая версия перевода, во второй надо написать новую (если не поменялась то просто скопировать и импортнуть). Иногда бывают незначительные изменения типа лишнего пробела. И перевод остаётся прежним, переводчику в этом случае достаточно проверить что старая версия подходит.
Что у нас получилось (описание тулзы)
Как открыть редактор локализации
Вкладки в редакторе
Вкладка Языки
На этой вкладке можно добавлять новые языки и настраивать их видимость.
Базовый язык для перевода
Это язык на котором пишутся все тексты. С него идет перевод на другие языки. В нем самая актуальная версия текстов. Менять его не следует.
Язык по-умолчанию для приложения
В коде есть автоопределение языка. Если подходящего нет, то будет выбран этот. Как правило, это английский. Например у пользователя выбран язык системы туркменский, а у нас есть переводы только на русский и английский. Будет выбран язык по-умолчанию в этом случае.
Языки для перевода
Это языки на которые можно переводить (включая базовый).
У каждого языка есть галочка “разрешить к показу пользователю”. Если она не стоит, то этого языка не будет в списке доступных пользователю языков. Используется например чтобы подготовить перевод, но он ещё не финальный и мы хотим чтобы в игре были только русский и английский, но не было французского.
Также тулза умеет возвращать “самый длинный” язык. В этом случае из всех языков (не важно стоит галочка или нет) выбирается самый длинный перевод и подставляется в виде текста.
Вкладка Локализация
Страницы (листы в гглотабличке)
В этой вкладке содержатся все локализуемые тексты.
Все ключи разбиты по “страницам”, каждая страница попадает на отдельный лист в гуглотабличке при выгрузке.
Можно переносить ключи и группы ключей между страницами, это сделано для удобства работы с ключами (например, имена монстров на странице monsters и т.п.).
Страницы можно удалять, добавлять, создавать и переносить ключи между страницами (из контекстного меню сразу для группы ключей). Каждая страница лежит в отдельном xml-файле.
Также есть специальный чекбокс “эта страница заполняется из кода”, это было сделано для одного из внешних проектов, подробно разбирать в статье не буду.
Фильтры
Ключи на странице для удобства можно отфильтровать. в поле “Фильтр” вводится текст и остаются только ключи, которые содержат введенный текст в названии ключа или в одном из переводов.
Показывать языки
Кнопки позволяют скрыть ненужные языки (столбцы) для удобства работы.
Ключи локализации
ТехИмя ключа локализации
У всех ключей-техимен локализации есть осмысленное имя. Имя может состоять из латинских букв, цифр, знаков подчеркивания и точек.
Точки служат для разбивки ключей на группы. Например, interface.window_shop.*
можно будет свернуть и развернуть все ключи начинающиеся на interface, или все ключи window_shop внутри группы интерфейс. Это удобно для поиска и группировки однотипных ключей.
Элементы управления ключом локализации
Кнопка link key позволяет к комментариям текущего ключа прицепить ссылки на другие ключи, которые упоминаются в тексте. Например, текст инфла “повышает скорость атаки на 20%”, можно прицепить к нему ссылку на “скорость атаки”, чтобы сразу в комментариях видеть как переводили это слово. При выгрузке для переводчиков там можно выбрать что показывать — названия ключей или их текущий перевод (и на какой язык перевод). Если прилинкованы ключи, то вместо трех точек на кнопке пишется кол-во прилинкованных ключей.
Правка текста ключей
При нажатии на кнопку рядом с русским текстом, открывается вот такое окно. Можно поправить текст базового языка. Тексты переводов править нельзя, это специально сделано для защиты от очень умных. Вся правка переводов идёт через выгрузку локкита и импорт переведенного локкита.
Параметры в ключах
В тексте ключа могут содержаться параметры. Параметры служат для подстановки в ключ других значений.
Параметры обрамляются фигурными скобками <> и должны содержать осмысленное имя. Из названия параметра должно быть понятно что туда передавать из кода, а не просто param1 param2. Из-за особенностей работы с гуглотаблицами (при автоматическом переводе на некоторые языки с помощью =googletranslate() удалялись куски в фигурных скобках) было решено названия параметров обрамлять ещё подчеркиваниями и слова в названии также разделять подчеркиваниями. Не использовать пробелы и большие буквы. Можно использовать в названии параметров только маленькие буквы латинского алфавита, цифры и подчеркивания. В противном случае автоматический перевод нужно будет долго править руками, так как он переводит и ключи.
Кол-во и имена параметров должны совпадать во всех языках. Если они не совпадают, тулза считает это ошибкой перевода и такие ключи попадут при выгрузке в список.
При генерации кода названия параметров будут подставлены в метод автоматически и описание метода сгенерировано с полным текстом. Если метод присутствует, а ключ удален, то собрать клиент не получится, будет выдана ошибка.
Дополнительно мы ввели внутри правила именования параметров:
В коде оно всё равно выводится правильно, но это давало больше контекста переводчикам и программистам и уменьшало кол-во вопросов от последних.
Вкладка Google Docs
Общий принцип работы тулзы
Все тексты базового языка правятся в тулзе. Потом делается выгрузка нужных текстов для перевода в гуглотаблицу. Когда тексты переведены (гуглтранслейтом или переводчиком), то переводы импортируются обратно в тулзу. Править переводы внутри тулзы нельзя! Это сделано специально для защиты от особо умных. Можно только выгрузить, поправить в табличке и импортировать обратно.
Авторизация
Для работы с гуглотаблицами нужно авторизоваться, используя свой гугловский аккаунт. Выгруженные документы можно пошарить переводчикам.
Экспорт локализации
Базовый язык
Просто показывает базовый язык, для информации.
Язык перевода и Дополнительные языки
Выбираем язык на который хотим переводить. Для этого во вкладке языков должно быть добавлено минимум два языка. Базовый и ещё один. В списке будут доступны только те языки, которые пользователь добавил во вкладке “Языки”.
Если нужно выгрузить сразу несколько языков, то остальные выгружаются проставлением галочек в разделе “Дополнительные языки”. Например, у нас есть русский и нормальный перевод на английский. А мы хотим переводить на немецкий. Мы можем указать язык перевода “немецкий”, а дополнительно (для удобства переводчика) выгрузить ещё и английский в дополнительных языках. Они все попадут в табличку.
Частичный экспорт
Если этот чекбокс не стоит, то выгружаются вообще все ключи которые есть в локките (полный локкит). Если чекбокс стоит, то выгружаются не все ключи, а только те, которые надо исправить.
В этот список попадают ключи, версия перевода которых меньше чем версия базового языка. Т.е. изменившиеся ключи и ключи без перевода вообще.
Экспорт ошибок
При включенном чекбоксе “частичный экспорт” в выгрузку попадают не все ключи, а только те что без перевода или версия которых устарела. Если включить чекбокс “экспорт ошибок”, то туда добавляются ещё и ключи с ошибками (например, несовпадающие имена и кол-во тегов, превышение размера в символах и т.п.).
Чекбокс “for all addition” проверяет ошибки ещё и для дополнительных языков, а не только для языка перевода (они тоже попадут в выгрузку).
Экспорт не финальных
При включенном чекбоксе “экспорт нефинальных” в выгрузку попадают также все ключи, для которых при импорте не был проставлен чекбокс “финальный перевод”.
Экспорт линкованных ключей
Тут можно выбрать вид, в котором линкованные ключи попадут в комментарии. Доступно три варианта: Без ref-ключей (будут только комменты, написанные вручную), Ref-ключи в комментариях (помимо коммента будет список ключей), Ref-значения в комментариях (будет подставлен перевод прилинкованных ключей, сбоку можно выбрать язык из которого будет взят перевод)
Имя файла
Генерируется автоматически. Подставляется partial если это частичный экспорт, проставляется дата экспорта (для удобства, не используется при импорте).
Импорт переводов
В нижней части окна есть список файлов, относящихся к данному проекту у вас на гугл-диске (фильтр по имени). Напротив каждого файла есть две кнопки: “посмотреть”(открыв файл в браузере) и импортировать (открывает окно импорта).
Все языки / Язык перевода
Чекбокс “все языки”. Когда включен, импортирует переводы не только для выбранного языка, но и для всех дополнительных.
Когда выключен, то появляется выпадающий список с языками, доступными для импорта.
Разрешить замену
По умолчанию заменяются только переводы ключей, версия перевода которых больше версии перевода в тулзе (только новые), старые не изменяются. Это сделано чтобы случайно не затереть нужный при работе с полным локкитом.
Если чекбокс включен, то заменяются также ключи с версией РАВНОЙ версии в тулзе.
Кнопка Импортировать
Импортирует переводы с выбранными параметрами
Вкладка Настройки
Общие настройки
Ширина столбца ключей — в пикселах. Настраивается, чтобы видеть ключи целиком.
Ширина столбца переводов — в пикселах. Настраивается, чтобы видеть тексты целиком. Но рядом с текстом есть кнопка всегда, чтобы посмотреть его удобно с разбиением на строки.
Сохранять по кнопке — если выключить, то будет сохранять автоматически после каждого изменения. Удобно для небольших проектов.
Не исправлять пробелы — отключает часть фиксов (удаление лишних пробелов в начале и в конце, правки пробелов в ключах подстановки и т.п.), лучше пусть исправляет.
Удаленные ключи
Тут будет список ключей которые недавно были удалены. Их можно восстановить или очистить список.
Разное
Кнопка “Исправить ошибки” позволяет исправить ошибки ручного редактирования xml (не все, только некоторые). Лучше не правьте руками xml.
Generate class LL (вкладка-кнопка)
Генерирует код для статической локализации. В PixelWars используется только один такой ключ: not_localized.
Кнопка Save
Отключается в настройках. При большом кол-ве текстов автосохранение после каждого изменения тормозит. Для маленьких проектов мы оставили возможность автосохранения, для больших сохраняем руками по кнопке. Кнопку нужно нажимать после каждого редактирования текстов, иначе они не сохранятся.
Пример чеклиста работы с текстами
(был написан для одной из студий которая лицензировала тулзу)
Добавление новых текстов (вики и код)
Название (тех-имя) ключей задают гд.
Оно должно быть осмысленным. Название ключей на английском, не надо писать “posoh_s_zolotymi_sharikami_na_rukoyati”.
Если нужен новый ключ — согласуйте с гд!
Для всех новых интерфейсов обязательно указывается в вики какие ключи используются (группа, без деталей, например interface.window_shop.*). Если статьи с этим интерфейсом нет, то указывается в таске.
В название ключа добавляются префиксы, поясняющие что это (например, btn_ для кнопок, caption_ для заголовков окна, label_ для заголовков раздела, text_ для просто текстов и т.п.). Тут главное чтобы было понятно что это за ключ и что он делает из его названия.
Создание новых ключей (в тулзе)
1) добавляем ключи (вечером раз в день)
опционально (если требуется срочно “хоть какой-то перевод” т.е. Pseudo-Localization):
1.1) выгружаем сразу partial (убрав галку про нефинальные! поставив галку “экспорт ошибок”)
1.2) переводим как гуглтранслейт, импортим как нефинальные (со снятой галочкой “финальный перевод”)
1.3) выгружаем ещё раз partial (убрав галку про нефинальные! поставив галку “экспорт ошибок”), если есть ошибки (в тегах как правило), то исправляем их, импортим как нефинальные! (со снятой галочкой “финальный перевод”). Повторяем пункт 1.3 пока не исчезнут ошибки (не останется ключей в частичной выгрузке)
2) выгружаем партиал поставив галку «включая нефинальные» и “экспорт ошибок”, отдаем переводчику.
3) когда переводчик перевела:
импортируем как финальные (галочка “финальный первод” стоит, галочка “разрешить замену” — нет).
3.1 выгружаем ещё раз partial (убрав галку про нефинальные! поставив галку “экспорт ошибок”), если там есть ошибки (хоть какие-то ключи попали), то отдаём переводчику их поправить, дожидаемся правок и импортируем с установленными галочками “финальный перевод”, “разрешить замену”. Повторяем пункт 3.1 пока ошибки не исчезнут.
Изменение уже добавленных текстов
1) изменяем русский текст в тулзе
2) выгружаем партиал поставив галку «включая нефинальные», “экспорт ошибок”, отдаем переводчику
3) как она отдаст импортим как финальные: включены галочки (“финальный перевод”), “разрешить замену”. повторяем пункты 2, 3 пока не будет пустая дока в партиал.
Дополнительно (best practices)
Что происходит когда нужного ключа нет
В этом случае возвращается техимя ключа (мы ещё обрамляли его звездочками в этом случае). Таким образом вместо “нет перевода” или “заголовок пустой” QA могут сразу сказать какого ключа нет и понять что с ним не так (название в коде не совпадает или просто не добавили ключ).
Помимо этого в лог выводится ошибка, а в релизе в систему аналитики отправляется эвент с именем ключа (это не часть системы локализации, но очень удобно).
Вёрстка текста
Поскольку мы работаем с юнити и TextMeshPro, то поддержка rich text и кастомных смайлов там есть “из коробки”. Дополнительно ничего делать не надо.
Туда же относятся неразрывность (не отрывать символ валюты от цифр) и прочие вещи. Всё уже есть в TMP!
Подсветка терминов в тексте
“прикольно было бы сделать как в Tyrany — там все термины подсвечиваются в тексте и попапчик при наведении райзится с пояснением”
Это не задача локализации, плюс уже реализовано тегами в TextMeshPro. Делается элементарно. Искать термины по названию и добавлять подсказки не надо по понятным причинам.
Локализация графики
В статье мы не стали касаться локализации графики, так как все это делают по-разному. Общий принцип там такой: все локализуемые фразы переводятся как обычный текст, потом вставляются руками на текстуры (если это например граффити), нужные текстуры по выбранному языку подгружаются.
Также мы делали шейдер текстовых декалей для размещения надписей на стенах (в мобильном проекте). Но это ничем не отличается от обычных надписей в интерфейсе и рассматривать отдельно смысла мало.
Как лучше называть ключи и параметры
Техимена ключей
Общий принцип — а как вам удобнее их будет группировать потом?
Для интерфейсов мы обычно делали общую группу “interface.”
В ней группы для каждого окна (interface.settings.), внутри для вкладок окна (interface.settings.sound. ) и т.п.
Для статов отдельная группа stats.:
stats.strength_name = “Шанс критического урона”
stats.strength_description = “Влияет на вероятность нанести критический урон”
Так всё что относится к одному стату будет в выгрузке и редакторе находиться рядом.
Для персонажей например
Кол-во уровней фолдинга можно увеличивать переименованием нужных ключей (заменой подчеркивания на точку).
В коде мы стараемся формировать название ключа автоматически из техимени где это возможно. Например: “characters.npc.”+ +”_name”.
для квестов и диалогов квеста скорее всего название ключа будет содержать и квест и “кто говорит”.
dialogs.q_stupid_quest_coyotes.d_01_intro.d_001_merchant_male_hero_female = “Привет, великая воительница, я хотел бы попросить тебя принести 10 шкур койотов и фапотьку!11”
dialogs.q_stupid_quest_coyotes.d_01_intro.d_002_hero_female_merchant_male = “И тебе привет, купец!”
quests.q_stupid_quest_coyotes.quest_name = “Шкуры и фапотька”
В диалогах важно соблюдать порядок фраз (просто добавьте номера фразам, это можно сделать даже автоматически в некоторых случаях). Также нас часто просили указывать пол говорящего и того к кому обращаются помимо имен говорящих. Сделать это можно в комментариях или в названии ключа — как удобнее.
По возможности храните одинаковые сущности на отдельных листах. Тогда проще будет искать их. Называйте листы осмысленно, например “quests” или “interface”.
Техимена параметров подстановки
Общий принцип — должен быть понятен контекст.
Старайтесь называть одни и те же параметры единообразно, чтобы программистам не приходилось дублировать код.
Охотник выпускает в цель две пламенные стрелы. Каждая из них наносит <_attack_damage_>единиц огненного урона и поджигает противника на <_influence_duration_fractional_>сек.
Горящий противник теряет <_hp_decrease_>единиц здоровья раз в <_period_fractional_>сек.
Не промахивается. Без критических попаданий.
Канонир бросает гранату, которая наносит <_attack_percent_>единиц электрического урона всем целям в радиусе <_aoe_area_radius_fractional_>м. На месте взрыва образуется грозовое облако. Все противники, попавшие в облако, получают на <_damage_increace_percent_>% больше урона в течении <_influence_duration_fractional_>сек.
Склонения, род и прочие сложные штуки
Кратко: вам это скорее всего не нужно!
В чем сложность подстановок
Делать автосборку названий довольно сложно. Давайте разберем на примерах:
Предположим, что мы хотим чтобы название (пока только в именительном падеже!) указывало на статы и прочие характеристики предмета (как в диабло).
Название состоит из: “определение”(прилагательное) + “тип предмета”(существительное) + “идентификатор принадлежности”(существительное)
И прилагательное и идентификатор принадлежности зависят от рода/числа.
Красный меч/Красная секира/Красные стрелы
la feu DU dragon — огонь дракона
la feu DE LA terre — огонь земли
la feu DES maudits — огонь проклятых
Также меняется порядок слов во многих языках (корейский, французский, испанский):
во французском определение (префикс) будет стоять после обозначаемого слова в этом случае, например:
la feu délétère de la terre — гибельный/смертоносный огонь земли, дословно: огонь смертоносный земли
в ит: la fiamma disastrosa de la terra
Также одно и то же слово в разных языках может быть разного рода! Так исторически сложилось.
Заметьте, это пример только в именительном падеже без склонений!
Так что если есть возможность вписать название в текст без подстановок — сделайте это и не морочьте голову переводчикам! Если нет, то придется выстраивать довольно сложную систему. Подумайте: точно ли оно вам надо? Не проще ли назвать предметы сразу как надо и не заморачиваться с такими штуками?
Пример реализации с помощью нашей системы
Возьмем простейший случай: название собирается в зависимости от класса и статов из префикса, существительного и постфикса. Используется отдельно, не подставляется в диалоги и не склоняется.
Тогда для большинства актуальных языков мы будем использовать одну из четырех групп:
Заведём отдельный ключ “naming_format”, в котором будет формула сборки текста.
Примеры того что там может быть в статах
[prefix_secondarystat|masculine] +[item_name] + [postfix_rarityclass] [prefix_class_attack_element_name] +[item_name] + [postfix_secondarystat|masculine]
Вместо плюсов там будет либо порбел либо артикли либо ещё что-то.
У нас будет 4 таких ключа (или можно заранее договориться что все предметы одного класса в этот слот только в мужском или только в женском роде, тогда будет меньше ключей).
Дальше в коде парсится ключ форматирования и собирается из составных частей. Префиксы типа английского a/an можно сразу добавить к названию в этом случае.
Группу рода мы будем указывать отдельно где-то, например в отдельном ключе или тегом, который вырежем.
Это пока только для одного словосочетания!
Пример сборных названий предметов из нашей игры:
Аналогично для склонений/падежей (в каких-то языках их нет, в каких-то их больше чем в русском).
Ещё есть изменение формы слова от кол-ва предметов. С ними чуть попроще. Для числительных существует 19 групп, в каждой свои правила. Ознакомиться можно по ссылке:
Можно задать эти правила для каждого языка, записать в виде switch и пользоваться.
Общий вывод: если хочется использовать такие сложные формы подстановок, готовьтесь к куче проблем и плохо читаемому тексту (есть ещё и диалекты, слова-исключения и т.п.).
Пример готового решения для подобных штук:
Теперь оцените насколько удобно будет переводчикам с этим работать и ещё раз задумайтесь — нужно оно вам или нет?
Скорее всего, если это не Diablo (т.е. у вас нет 100500 миллионов разных предметов генерируемых) и у вас нет отдельной команды для этого — оно вам не нужно. Если есть, то можно по аналогии с тем что я выше описал сделать, но это не на 5 минут задача, требующая обязательной проверки носителями языка.
Мы использовали такой подход:
Префикс и постфикс выбирали в зависимости от редкости, наличия элемента, основного и вторичного статов (из них выбирали самый влияющий). У элемента был приоритет перед всем остальным.
Склонения («вам выпал обычный меч» или «вас ударили обычным мечом») мы не делали, так как это в разы увеличивало объемы локализации и сложность.
Про стоимость разработки
Поскольку тулза локализации получилась довольно удобной, мы в итоге решили продавать лицензии на неё.
Мы работали исключительно с юрлицами, предоставляя лицензию в формате «на любое число проектов для одного юрлица». Все обновления мы раздавали бесплатно (всё равно сами используем её во всех наших проектах, нам не сложно). В итоге все довольны, нам удобно, некоторые “хотелки” мы потом добавляли бесплатно (и сами используем часть из них).
Такой формат позволил в итоге окупить разработку системы локализации со всеми итерациями примерно за 3 года без отрыва от производства своих продуктов.
Что в планах улучшить
Перевод на новую систему UIElements
Мы уже перевели большую часть внутренних редакторов на UIElements и GraphView, там и отображение удобнее и код редактора писать проще. В планах сделать версию системы локализации на UIElements (и полностью перейти на неё).
Замена локализации для пользовательских переводов
Возможность пользователю положить файл с переводом части ключей, чтобы они использовались вместо основного перевода. Мы хотим это использовать для фанатских переводов игры (естественно, с проверкой соответствия ключей нашим).
Основная локализация будет храниться в одном файле, модерам без тулсета не очень удобно работать с этим, а мы хотим добавить поддержку неофициальных переводов не ломая основную систему.
Поддержка эмодзи
У нас в данный момент нет необходимости использовать эмодзи в локализации, но на будущее планируем сделать замену эмодзи с кодами разных сервисов отправки.
Получение списка символов
Получение множества символов для генерации текстур фонтов (в планах есть, пока сделали по чарсетам языки целиком). Также есть отдельная утилита для проверки шрифтов на то, все ли символы в них есть нужные или нет.
Standalone версия
Версия не в виде редактора, а в виде отдельного приложения. Думаем над этим, но пока не было необходимости.
Поддержка Unity Localization
Пока находится в превью. В планах (далеких) добавить совместимость, когда пакет выйдет из превью, если в этом будет смысл.
Там есть полезные фичи, но всё в R&D, так что пока не хочется тратить на это время.
Интеграция с системами Text To Speech
Планируем через какое-то время добавить возможность генерации озвучки диалогов для черновой озвучки игры. Это может быть удобно для препродакшна, так как финальная озвучка делается обычно в самом конце, а надиктовывать голосом самим черновую долго.
Мы уже делали такое в 2012, хотим теперь использовать какой-то из готовых ассетов с бОльшим числом поддерживаемых TTS-движков, чтобы можно было выбрать голоса. В идеале с поддержкой эмоциональной окраски.
В реалтайме генерировать озвучку в теории тоже можно, но мы не видим в этом смысла, так как TTS озвучка — это плейсхолдер, а не финальное решение для продакшена.
Прочие хотелки
(нам пока не нужно такое, но может вам нужно, если будете делать свою систему с нуля)
Ссылки по теме
https://habrahabr.ru/post/237725/ Локализация приложений для китайского рынка
https://habrahabr.ru/company/miip/blog/324496/ Особенности локализации игр на иностранные рынки
http://wnfx.ru/pravila-lokalizatsii-prilozheniy-v-kitae/ Правила локализации приложений в Китае: деньги, связи и App Store
Когда-то мы с Александром Штаченко писали статью на тему локализации http://progamedev.net/localization/
Какие готовые ассеты можно использовать в Unity, если не хочется делать свою систему?
Самым навороченным считается L2 Localization. Нас не устроил сам пайплайн, так что пришлось делать свою.






