Lingo.dev CLI переводит строковые ресурсы Android (strings.xml) через настроенный движок локализации. Формат android CLI понимает нативно: элементы <resources>, <string>, <string-array> и <plurals> обрабатываются корректно — структура XML сохраняется, а категории множественного числа для каждой целевой локали формируются автоматически.
Это руководство охватывает локализацию Android-приложения от начала до конца: настройка CLI, локальный перевод и автоматизация в CI — чтобы переводы обновлялись при каждом пуше.
Демо-репозиторий
Чтобы следовать примерам из статьи, клонируйте lingodotdev/android-app-localization-example или создайте форк. В репозитории — рабочий Android-проект со строковыми ресурсами, конфигурация Lingo.dev CLI и переводы для каждой целевой локали.
Как работает локализация Android#
Android использует соглашение о каталогах ресурсов, при котором для каждой локали создаётся отдельный каталог values-[locale]/. Во время выполнения система загружает нужный strings.xml в зависимости от языковых настроек устройства.
app/src/main/res/
values/ # Default (source) strings
strings.xml
values-es/ # Spanish
strings.xml
values-fr/ # French
strings.xml
values-ja/ # Japanese
strings.xmlТипичный strings.xml содержит три типа элементов:
<resources>
<!-- Simple strings -->
<string name="app_name">My App</string>
<string name="welcome_message">Welcome back!</string>
<!-- String arrays -->
<string-array name="planets">
<item>Mercury</item>
<item>Venus</item>
<item>Earth</item>
</string-array>
<!-- Plurals -->
<plurals name="items_count">
<item quantity="one">%d item</item>
<item quantity="other">%d items</item>
</plurals>
</resources>CLI разбирает все три типа элементов, переводит их содержимое через движок локализации и записывает файлы для каждой локали в соответствующие каталоги values-[locale]/.
Что понадобится#
Создайте движок локализации
Каждый запуск CLI обрабатывает контент через движок локализации — это конфигурация, которая задаёт языковую модель, глоссарий, тональность бренда и правила. Создайте его в панели Lingo.dev.
Проверьте Node.js
CLI требует Node.js версии 22 или выше:
node -vУстановить CLI
Установите CLI глобально — это добавит команду lingo:
npm install -g @lingo.dev/cliВойти в систему
Авторизуйтесь с помощью одноразового пароля:
lingo loginВ CI используйте ключ API — передайте --api-key или задайте LINGO_API_KEY.
Подготовьте Android-проект
В проекте должен быть файл strings.xml по умолчанию в каталоге app/src/main/res/values/. Android Studio создаёт его при создании нового проекта. О настройке каталогов ресурсов подробнее — в руководстве по локализации Android.
Настройте CLI#
Запустите lingo init в корне проекта — будет создан файл .lingo/config.json с исходной и целевыми локалями и шаблонами путей. Затем выполните lingo link, чтобы привязать организацию и движок. Результат выглядит так:
{
"orgId": "org_...",
"engineId": "eng_...",
"sourceLocale": "en",
"targetLocales": ["es", "fr", "de", "ja"],
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android"
}
]
}Шаблон указывает на каталог ресурсов по умолчанию — values/ без квалификатора, именно туда Android помещает исходные строки. Код локали здесь не нужен.
Почему `format` задаётся явно
CLI автоматически определяет формат по расширению файла, но расширение .xml неоднозначно — поэтому для файлов ресурсов Android нужно явно указать "format": "android" в записи files.
Несколько файлов ресурсов
Если строки в проекте разбиты по нескольким файлам, например strings.xml и arrays.xml, добавьте отдельную запись files для каждого:
{
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android"
},
{
"pattern": "app/src/main/res/values/arrays.xml",
"format": "android"
}
]
}Добавьте .lingo/config.json в репозиторий.
Каталоги локалей и квалификаторы#
Android хранит язык по умолчанию в каталоге values/ без квалификатора — поэтому в исходном пути нет кода локали. CLI это учитывает: он воспринимает простой values/ как исходную локаль и добавляет целевой квалификатор для всех остальных локалей.
| Локаль | Каталог ресурсов |
|---|---|
en (исходная) | values/ |
es | values-es/ |
pt-BR | values-pt-rBR/ |
zh-Hans | values-b+zh+Hans/ |
Стоит разобраться с региональными локалями и локалями с указанием письменности: квалификатор ресурсов — это не просто тег BCP 47. Android поддерживает два формата: устаревший «язык-регион» (values-pt-rBR/) и BCP 47 с префиксом b+ (values-b+pt+BR/, API 24 и выше). Каталог с именем values-pt-BR/ будет просто проигнорирован — строки есть, но не загрузятся никогда.
Если задать "format": "android", CLI сам подберёт нужный формат: устаревший там, где он подходит для локали, и b+ — для письменностей, трёхбуквенных языков и числовых регионов.
Переход со старой настройки
В ранних версиях CLI локаль должна была присутствовать в исходном пути, и раньше мы рекомендовали символическую ссылку values-en -> values, чтобы совместить две схемы. Начиная с @lingo.dev/cli 1.12.0 это больше не нужно — укажите шаблон на values/strings.xml и удалите символическую ссылку.
Переводите локально#
Запустите CLI. При первом запуске — или при добавлении новой целевой локали — используйте --backfill-missing, чтобы перевести все существующие строки:
lingo push --backfill-missingCLI читает исходный strings.xml, определяет непереведённые записи по состоянию запуска, переводит дельту через движок локализации и записывает результаты в целевые директории values-[locale]/. Откройте любой целевой файл, чтобы проверить переводы.
При следующих запусках lingo push переводит только то, что изменилось:
lingo pushЧтобы ограничить запуск конкретными файлами, передайте glob-шаблон. Шаблоны сопоставляются с исходными путями, поэтому область нужно задавать по исходному файлу, а не по целевому:
lingo push "app/src/main/res/values/strings.xml"Чтобы забрать переводы, созданные в другом месте (например, в CI), в рабочее дерево, запустите lingo pull.
Множественное число#
Android использует элементы <plurals> с строками количества CLDR (zero, one, two, few, many, other) для обработки форм множественного числа. Разным языкам нужны разные категории множественного числа: английскому — две (one и other), русскому — четыре, арабскому — шесть.
CLI сохраняет структуру <plurals> при переводе и создаёт корректные элементы quantity для каждой целевой локали. Например, исходная запись с двумя категориями:
<plurals name="messages_count">
<item quantity="one">%d new message</item>
<item quantity="other">%d new messages</item>
</plurals>даёт корректные категории для каждого целевого языка. Движок локализации знает, какие правила множественного числа CLDR применяются к каждой локали, и создаёт только те категории, которые действительно нужны этому языку.
Блокировка ключей#
Некоторые строковые значения должны оставаться одинаковыми на всех языках — например, названия брендов, API-эндпоинты или шаблоны форматирования. Используйте блокировку ключей, чтобы копировать такие значения без перевода:
{
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android",
"lockedKeys": ["app_name", "api_base_url"]
}
]
}Заблокированные ключи копируются из исходного файла во все целевые файлы, не попадая в пайплайн перевода.
Автоматизация в CI#
Самый удобный способ держать переводы актуальными — Lingo.dev GitHub App. Он работает на стороне сервера, читает зафиксированные .lingo/config.json и engineId и автоматически открывает обновления переводов — без раннера, без хранения секретов и без управления lockfile. Установите его и укажите на репозиторий — переводы будут обновляться при каждом пуше.
Если вы предпочитаете запускать CLI в своём пайплайне, добавьте рабочий процесс, который устанавливает CLI и выполняет lingo push:
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install -g @lingo.dev/cli
- run: lingo push --backfill-missing
env:
LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}Сохраните ключ API как LINGO_API_KEY в разделе Settings > Secrets and variables > Actions репозитория GitHub, затем зафиксируйте обновлённые целевые файлы (или откройте pull request) следующим шагом.
Проверьте перед деплоем#
Используйте lingo check как проверку перед деплоем — команда завершится с ненулевым статусом, если есть непереведённые строки, и они не попадут в продакшн:
lingo checkДобавьте это как отдельный шаг CI перед сборкой:
- name: Verify translations
run: lingo check
env:
LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}