CLI нативно поддерживает монорепозитории. Можно использовать один i18n.json в корне с рекурсивным glob-паттерном ** для автоматического поиска пакетов, одну корневую конфигурацию с явными путями для каждого пакета или отдельные файлы i18n.json в каждом пакете в сочетании с GitHub Action на основе matrix strategy.
Когда использовать каждый вариант#
| Сценарий | Вариант | Файлы конфигурации | GitHub Action |
|---|---|---|---|
| У всех пакетов одинаковая структура и одинаковые локали, и вы хотите, чтобы новые пакеты подключались автоматически | Одна рекурсивная конфигурация | Один i18n.json в корне с glob-паттерном ** | Один шаг, стандартный working-directory |
| У всех пакетов одинаковые исходная и целевые локали | Одна конфигурация | Один i18n.json в корне | Один шаг, стандартный working-directory |
| Пакетам нужны разные целевые локали | Конфигурации для каждого пакета | Один i18n.json на каждый пакет | Matrix strategy с working-directory |
| Пакетам нужны разные движки (глоссарий, тональность бренда) | Конфигурации для каждого пакета + отдельные движки | Один i18n.json на пакет, у каждого свой engineId | Matrix strategy с working-directory |
Вариант 1: Одна рекурсивная конфигурация#
Если у всех пакетов одинаковая структура (например, apps/<name>/locales/[locale].json), используйте рекурсивный glob-паттерн ** в одном корневом i18n.json. Новые пакеты будут подхватываться автоматически, если соответствуют этой структуре:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de", "ja"]
},
"buckets": {
"json": {
"include": ["apps/**/locales/[locale].json"]
}
}
}CLI по умолчанию игнорирует node_modules, .git, dist, build, .next и .turbo, поэтому рекурсивные шаблоны не заходят в вендорные директории и каталоги сборки. Если нужно пропустить что-то ещё, добавьте свои записи в exclude.
GitHub Action здесь такой же, как в варианте 2 ниже: один шаг, рабочая директория по умолчанию.
Этот вариант подходит, если у всех пакетов одинаковые исходная локаль, целевые локали, структура и движок локализации, и вы не хотите править i18n.json при каждом добавлении нового пакета.
Вариант 2: Одна конфигурация, общие локали#
Один i18n.json в корне репозитория. Пути bucket явно указывают на каждый пакет:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de", "ja"]
},
"buckets": {
"json": {
"include": [
"apps/web/locales/[locale].json",
"apps/dashboard/locales/[locale].json"
]
},
"markdown": {
"include": ["packages/docs/content/[locale]/*.md"]
}
}
}GitHub Action — стандартный одиночный шаг:
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: lingodotdev/lingo.dev@main
with:
api-key: ${{ secrets.LINGODOTDEV_API_KEY }}
pull-request: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}Этот вариант подходит, если у всех пакетов одинаковые исходная локаль, целевые локали и движок локализации, но структура различается настолько, что рекурсивный glob-паттерн получится слишком широким.
Вариант 3: Конфигурации для каждого пакета, разные локали#
У каждого пакета свой i18n.json с независимыми целевыми локалями:
apps/web/i18n.json:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de", "ja", "ko", "zh-Hans"]
},
"buckets": {
"json": {
"include": ["locales/[locale].json"]
}
}
}apps/marketing/i18n.json:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de"]
},
"buckets": {
"json": {
"include": ["locales/[locale].json"]
},
"markdown": {
"include": ["content/[locale]/*.md"]
}
}
}GitHub Action — matrix strategy с working-directory:
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
translate:
runs-on: ubuntu-latest
strategy:
matrix:
package: [apps/web, apps/marketing]
steps:
- uses: actions/checkout@v4
- uses: lingodotdev/lingo.dev@main
with:
api-key: ${{ secrets.LINGODOTDEV_API_KEY }}
working-directory: ${{ matrix.package }}
pull-request: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}Каждая запись в matrix запускает CLI в контексте i18n.json соответствующего пакета. Action переводит только те файлы, которые объявлены в конфигурации этого пакета.
Вариант 4: Конфигурации для каждого пакета, отдельные движки#
Структура та же, что и в варианте 3, но каждый пакет подключён к своему движку локализации. Благодаря этому у каждого пакета свои глоссарий, тональность бренда и конфигурация модели.
apps/product/i18n.json:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de", "ja"]
},
"buckets": {
"json": {
"include": ["locales/[locale].json"]
}
},
"engineId": "eng_ProductApp123"
}apps/docs/i18n.json:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr"]
},
"buckets": {
"markdown": {
"include": ["content/[locale]/*.md"]
}
},
"engineId": "eng_DocsEngine456"
}YAML для GitHub Action такой же, как в варианте 3: engineId в каждом i18n.json автоматически направляет переводы в нужный движок.
Как работает lockfile#
Для каждого расположения i18n.json создаётся свой файл i18n.lock в той же директории. Lockfile отслеживает, какой исходный контент уже был переведён, и позволяет выполнять инкрементальные обновления. В вариантах 1 и 2 один lockfile находится в корне. В вариантах 3 и 4 у каждого пакета свой lockfile.
FAQ#
Новые пакеты будут подключаться автоматически?
Только в варианте 1 (рекурсивный **). В вариантах 3 и 4 при добавлении пакета нужно добавить новую запись в список matrix.package процесса.
Можно ли задать разные локали для разных пакетов?
Да. Используйте вариант 3 или 4. В i18n.json каждого пакета независимо задаётся свой массив locale.targets.
Нужен один файл процесса или несколько?
Один файл процесса с matrix strategy может охватить все пакеты. Каждая запись в matrix запускается с другим working-directory, ограничивая CLI конфигурацией конкретного пакета.
Могут ли пакеты использовать общий глоссарий, но разные локали?
Да. Укажите для обоих пакетов один и тот же engineId, но настройте разные locale.targets в каждом i18n.json. Глоссарий движка будет применяться к тем парам локалей, которые запрашиваются.
