
Привет! Я Роза, Flutter Dev Friflex. Недавно на CrossConf рассказывала о том, что такое система управления переводами и как подключить ее к проекту на Flutter. В этой статье — краткое сравнение популярных сервисов локализации и разбор подключения TMS по шагам.
Представим ситуацию: у вас проект с огромным количеством ключей и языков. Команда тоже немаленькая, все активно вносят изменения в переводы. И все это живет в .arb-файлах.
Сначала кажется, что все под контролем. Но чем больше проект, тем сложнее согласованно править строки и передавать файлы между разработчиками. Появляются дубликаты ключей, теряются переводы, накапливается масса ручных операций. Вообще непонятно, кто, где и что поменял.
И вот в какой-то момент закономерно возникает вопрос: может быть, пора подключать TMS? Почему бы и нет.
TMS — это не огромная таблица с переводами и не папка с сотней файлов. Это централизованная платформа, которая управляет всем процессом локализации: хранением ключей и версионностью, ролями и правами, работой с переводчиками и автоматизацией. Во многих TMS можно подключать и внешних переводчиков, которых предоставляет сама платформа.
Когда именно задумываться о таком переходе? В Японии есть слово для теплой ностальгии — «нацукаси». Если ваша локализация вызывает скорее фрустрацию, чем эту эмоцию, это уже звоночек. Ну а если без метафор, самое время смотреть в сторону централизованного решения, когда:
- Локализацией занимаются несколько человек; 
- Языков становится больше двух-трех и вы планируете расширяться; 
- Нужна прозрачная статистика и контроль за статусом переводов; 
- Важно точно контролировать, кто и что может редактировать; 
- Надоели ручные выгрузки и загрузки; 
- Потребовались машинный перевод, Translation Memory или глоссарии для консистентности; 
- Переводчикам не хватает контекста, где используется строка; 
- Архитектура сложная и сочетает общие и специфичные переводы. 
Какие есть сервисы
На рынке большой выбор: Lokalise, Phrase, Crowdin, Localizely и Transifex — все закрывают базовые задачи. В целом они поддерживают OTA, машинный перевод, интеграции (включая Figma) и автоматизацию процессов.

Но многое зависит от тарифа, поэтому смотреть только на цену не лучшее решение: важно понимать, что именно включено. На лимитах ключей хорошо видны различия: у Lokalise — 5 000, у Transifex — 50 000, у Localizely — 500 на стартовом плане, а у Phrase и Crowdin безлимит появляется на более дорогих тарифах.


С форматами ситуация комфортная: обычно поддерживается больше десяти — Kotlin, Swift, Flutter, табличные форматы и другие. На этом фоне Crowdin выделяется особенно: там поддерживается больше сотни форматов. Честно, когда я открыла список, незнакомых пунктов было так много, что я немного растерялась.

У некоторых платформ есть свои фишки. В Lokalise, например, можно схватывать значения ключей прямо со скриншотов, чтобы переводчики видели контекст использования. Еще есть поиск дубликатов ключей — очень помогает держать базу в порядке.

Отдельная тема — Translation Memory. По сути, это база всех переведенных фраз с оригиналами, которая ускоряет работу и поддерживает единый стиль по проектам. Обычно TM создается автоматически на каждый проект и пополняется всеми сделанными переводами. При желании можно включить режим, когда сохраняются только одобренные варианты, так база будет чище.
Можно завести одну общую TM сразу для нескольких проектов. Механика проста: TMS загружает исходный файл и разбивает его на сегменты, для каждого сегмента ищет совпадения в ТМ. Если находит полное совпадение — exact match (100%) — остается подтвердить. Если совпадение частичное — fuzzy match (70–99%) — достаточно чуть подредактировать. После подтверждения перевод попадает обратно в TM и в следующий раз уже подсказывается автоматически.

Про OTA. Если вы подумали «Obviously Totally Ambiguous» — нет, это не оно! Это over the air. А если серьезно, OTA — это переводы, которые прилетают по воздуху. Да, звучит слегка несолидно, но польза очень практическая.
Представьте: в приложении ошибка в тексте, а заметили вы это уже после попадания в сторы. Стандартный путь выглядел бы так: зайти в .arb, найти нужный ключ, поправить перевод, перегенерировать файлы, запушить в GitHub, пройти ревью, отдать тестировщикам, отправить новую версию в сторы.
С OTA все это сокращается примерно в три раза: вы заходите в сервис локализации, меняете перевод, выпускаете релиз именно под этот перевод — и пользователи уже видят корректный текст. Технически это механизм, который позволяет приложению подгружать переводы с сервера. Чуть-чуть магии вне Хогвартса.
И тут вы можете подумать: это, конечно, круто, но безопасно ли? OTA действительно доставляет переводы в приложение в реальном времени, но это не значит, что любой человек может их поменять.
OTA управляется только через сервис локализации, где есть четкое разделение ролей: кто может редактировать переводы, публиковать их в релиз и имеет доступ к OTA-дистрибуции. То есть нажать кнопку и отправить в прод могут только пользователи с нужными правами. Все изменения логируются, можно откатить версию. Плюс в прод обычно попадают только опубликованные версии, но все зависит от выбранного сервиса локализации.
Как подключить TMS к Flutter-приложению, на примере Localizely
Начинается все просто: регистрируемся, создаем проект, выбираем базовый язык и целевые локали, приглашаем команду и импортируем текущие .arb-файлы с ключами. Дальше подключаем Flutter-проект: используем intl_utils, настраиваем идентификатор проекта и API-токен. Работаем через две команды: одна отправляет .arb в Localizely, другая — подтягивает переводы обратно.
Загрузка ARB-файла в Localizely
dart run intl_utils:localizely_upload_main \
  --project-id <PROJECT_ID> --api-token <API_TOKEN> \
  --arb-dir <ARB_DIR> --main-locale <MAIN_LOCALE> --branch <BRANCH> \
  --[no-]upload-overwrite --[no-]upload-as-reviewed \
  --upload-tag-added <UPLOAD_TAG_ADDED> \
  --upload-tag-updated <UPLOAD_TAG_UPDATED> \
  --upload-tag-removed <UPLOAD_TAG_REMOVED>Загрузка ARB-файла с Localizely (скачивание в проект)
dart run intl_utils:localizely_download \
  --project-id <PROJECT_ID> --api-token <API_TOKEN> \
  --arb-dir <ARB_DIR> --branch <BRANCH> \
  --download-empty-as <DOWNLOAD_EMPTY_AS> \
  --download-include-tags <DOWNLOAD_INCLUDE_TAGS> \
  --download-exclude-tags <DOWNLOAD_EXCLUDE_TAGS>Следующий шаг — OTA. Подключаем библиотеку для OTA и указываем идентификатор релиза или дистрибутива, чтобы система соотносила набор переведенных строк с версией приложения. С этого момента тексты становятся доступны по воздуху: пользователи видят обновления без установки новой версии.
Чтобы полностью автоматизировать поток, привязываем репозиторий к Localizely. Конфигурация хранится в localizely.yml в репозитории: там описано, какие файлы переводов импортировать (pull) из GitHub в Localizely и какие экспортировать (push) обратно. 
В разделе Integrations включаем автоматический push/pull и добавляем веб-хук, чтобы после каждого пуша изменения сразу попадали в TMS. В результате GitHub отслеживает файлы локализации, Localizely получает и распространяет свежие ключи и переводы, а OTA доставляет их в приложение.
В итоге
TMS — мощный инструмент. Но у него есть обратная сторона: стоимость подписки, которая может быть чувствительной для маленьких команд; сложность внедрения и интеграции в существующий CI/CD; избыточность для небольших проектов на одном-двух языках, где связка .arb и GitHub — более простой и экономичный вариант.
Если вам интересно сравнение платформ или хочется увидеть еще примеры интеграции с Flutter — дайте знать в комментариях!
 
          