Die CLI unterstützt Monorepos nativ. Nutze entweder ein einzelnes i18n.json im Root mit einem rekursiven **-Glob, der Pakete automatisch erkennt, eine einzelne Root-Konfiguration mit expliziten Pfaden pro Paket oder separate i18n.json-Dateien in jedem Paket in Kombination mit einer GitHub Action auf Basis einer Matrix-Strategie.
Wann sich welches Muster eignet#
| Szenario | Muster | Konfigurationsdateien | GitHub Action |
|---|---|---|---|
| Alle Pakete haben dasselbe Layout und dieselben Sprachen, und neue Pakete sollen automatisch erkannt werden | Rekursive Einzelkonfiguration | Ein i18n.json im Root mit einem **-Glob | Ein Schritt, Standard-working-directory |
| Alle Pakete verwenden dieselbe Quell- und Zielsprache | Einzelkonfiguration | Ein i18n.json im Root | Ein Schritt, Standard-working-directory |
| Pakete benötigen unterschiedliche Zielsprachen | Paketweise Konfigurationen | Ein i18n.json pro Paket | Matrix-Strategie mit working-directory |
| Pakete benötigen unterschiedliche Engines (Glossar, Markenstimme) | Paketweise Konfigurationen + separate Engines | Ein i18n.json pro Paket, jeweils mit eigener engineId | Matrix-Strategie mit working-directory |
Muster 1: Rekursive Einzelkonfiguration#
Wenn jedes Paket demselben Layout folgt (z. B. apps/<name>/locales/[locale].json), verwende einen rekursiven **-Glob in einem einzigen i18n.json im Root. Neue Pakete werden automatisch erkannt, solange sie diesem Layout entsprechen:
{
"$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"]
}
}
}Die CLI ignoriert standardmäßig node_modules, .git, dist, build, .next und .turbo. Rekursive Muster steigen daher nicht in Vendor- oder Build-Verzeichnisse hinab. Füge eigene exclude-Einträge hinzu, wenn du weitere Pfade überspringen möchtest.
Die GitHub Action ist identisch mit Muster 2 weiter unten – ein Schritt, Standard-Working-Directory.
Nutze dieses Muster, wenn alle Pakete dieselbe Quellsprache, dieselben Zielsprachen, dasselbe Layout und dieselbe Lokalisierungs-Engine verwenden und du i18n.json nicht jedes Mal anpassen möchtest, wenn ein neues Paket hinzukommt.
Muster 2: Einzelkonfiguration, gemeinsame Sprachen#
Ein i18n.json im Root des Repositorys. Die Bucket-Pfade verweisen dabei explizit auf die einzelnen Pakete:
{
"$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 – ein einzelner Standardschritt:
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 }}Nutze dieses Muster, wenn alle Pakete dieselbe Quellsprache, dieselben Zielsprachen und dieselbe Lokalisierungs-Engine verwenden, sich die Layouts aber so stark unterscheiden, dass ein rekursiver Glob zu breit wäre.
Muster 3: Paketweise Konfigurationen, unterschiedliche Sprachen#
Jedes Paket hat sein eigenes i18n.json mit unabhängigen Zielsprachen:
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-Strategie mit 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 }}Jeder Matrix-Eintrag führt die CLI im Kontext des i18n.json dieses Pakets aus. Die Action übersetzt nur die Dateien, die für dieses Paket deklariert sind.
Muster 4: Paketweise Konfigurationen, separate Engines#
Gleiche Struktur wie Muster 3, aber jedes Paket ist mit einer anderen Lokalisierungs-Engine verbunden. So bekommt jedes Paket sein eigenes Glossar, seine eigene Markenstimme und eine eigene Modellkonfiguration.
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"
}Das GitHub-Action-YAML ist identisch mit Muster 3 – das engineId in jedem i18n.json leitet Übersetzungen automatisch an die richtige Engine weiter.
So funktioniert das Lockfile#
Jeder Speicherort von i18n.json erzeugt im selben Verzeichnis eine eigene i18n.lock-Datei. Das Lockfile erfasst, welche Quellinhalte bereits übersetzt wurden, und ermöglicht inkrementelle Updates. In Muster 1 und 2 gibt es ein Lockfile im Root. In Muster 3 und 4 hat jedes Paket sein eigenes Lockfile.
FAQ#
Werden neue Pakete automatisch erkannt?
Nur mit Muster 1 (rekursives **). Bei Muster 3 und 4 fügst du der matrix.package-Liste des Workflows einen neuen Eintrag hinzu, sobald du ein Paket ergänzt.
Kann ich pro Paket unterschiedliche Sprachen festlegen?
Ja. Nutze Muster 3 oder 4. Das i18n.json jedes Pakets deklariert sein eigenes locale.targets-Array unabhängig von den anderen.
Brauche ich eine Workflow-Datei oder mehrere?
Eine Workflow-Datei mit Matrix-Strategie reicht für alle Pakete. Jeder Matrix-Eintrag läuft gegen ein anderes working-directory und begrenzt die CLI auf die Konfiguration dieses Pakets.
Können Pakete ein Glossar teilen, aber unterschiedliche Sprachen haben?
Ja. Verweise beide Pakete auf dasselbe engineId, konfiguriere aber in jedem i18n.json unterschiedliche locale.targets. Das Glossar der Engine gilt für die jeweils angeforderten Sprachpaare.
