La CLI es compatible con monorepos de forma nativa. Usa un solo i18n.json en la raíz con un glob recursivo ** para detectar paquetes automáticamente, una sola configuración en la raíz con rutas explícitas por paquete o archivos i18n.json separados en cada paquete, combinados con una GitHub Action con estrategia de matriz.
Cuándo usar cada patrón#
| Escenario | Patrón | Archivos de configuración | GitHub Action |
|---|---|---|---|
| Todos los paquetes comparten la misma estructura y los mismos idiomas, y quieres que los paquetes nuevos se detecten automáticamente | Configuración única recursiva | Un i18n.json en la raíz con un glob ** | Un paso, working-directory predeterminado |
| Todos los paquetes comparten los idiomas de origen y de destino | Configuración única | Un i18n.json en la raíz | Un paso, working-directory predeterminado |
| Los paquetes necesitan distintos idiomas de destino | Configuraciones por paquete | Un i18n.json por paquete | Estrategia de matriz con working-directory |
| Los paquetes necesitan motores distintos (glosario, voz de marca) | Configuraciones por paquete + motores separados | Un i18n.json por paquete, cada uno con su propio engineId | Estrategia de matriz con working-directory |
Patrón 1: Configuración única recursiva#
Cuando todos los paquetes siguen la misma estructura (por ejemplo, apps/<name>/locales/[locale].json), usa un glob recursivo ** en un solo i18n.json en la raíz. Los paquetes nuevos se detectan automáticamente siempre que coincidan con esa estructura:
{
"$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"]
}
}
}La CLI ignora node_modules, .git, dist, build, .next y .turbo de forma predeterminada, así que los patrones recursivos no descenderán a árboles vendorizados o de compilación. Agrega tus propias entradas exclude para cualquier otro elemento que quieras omitir.
La GitHub Action es idéntica a la del Patrón 2 de abajo: un paso, con el directorio de trabajo predeterminado.
Úsalo cuando todos los paquetes compartan el mismo idioma de origen, los mismos idiomas de destino, la misma estructura y el mismo motor de localización, y no quieras editar i18n.json cada vez que agregas un paquete.
Patrón 2: Configuración única, idiomas compartidos#
Un i18n.json en la raíz del repositorio. Las rutas del bucket apuntan de forma explícita a cada paquete:
{
"$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: paso único estándar:
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 }}Úsalo cuando todos los paquetes compartan el mismo idioma de origen, los mismos idiomas de destino y el mismo motor de localización, pero las estructuras difieran lo suficiente como para que un glob recursivo sea demasiado amplio.
Patrón 3: Configuraciones por paquete, distintos idiomas#
Cada paquete tiene su propio i18n.json con idiomas de destino independientes:
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: estrategia de matriz con 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 }}Cada entrada de la matriz ejecuta la CLI dentro del alcance del i18n.json de ese paquete. La acción traduce solo los archivos que ese paquete declara.
Patrón 4: Configuraciones por paquete, motores separados#
La misma estructura que el Patrón 3, pero cada paquete se conecta a un motor de localización distinto. Así, cada paquete tiene su propio glosario, voz de marca y configuración del modelo.
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"
}El YAML de GitHub Action es idéntico al del Patrón 3: el engineId en cada i18n.json enruta las traducciones al motor correcto automáticamente.
Cómo funciona el lockfile#
Cada ubicación de i18n.json genera su propio archivo i18n.lock en el mismo directorio. El lockfile registra qué contenido de origen ya se tradujo, lo que permite actualizaciones incrementales. En los Patrones 1 y 2, hay un solo lockfile en la raíz. En los Patrones 3 y 4, cada paquete tiene su propio lockfile.
Preguntas frecuentes#
¿Los paquetes nuevos se detectan automáticamente?
Solo con el Patrón 1 (con ** recursivo). Con los Patrones 3 y 4, agregas una nueva entrada a la lista matrix.package del flujo de trabajo cuando agregas un paquete.
¿Puedo tener distintos idiomas por paquete?
Sí. Usa el Patrón 3 o 4. El i18n.json de cada paquete declara su propio arreglo locale.targets de forma independiente.
¿Necesito un archivo de flujo de trabajo o varios?
Un solo archivo de flujo de trabajo con una estrategia de matriz maneja todos los paquetes. Cada entrada de la matriz se ejecuta con un working-directory distinto, lo que limita la CLI a la configuración de ese paquete.
¿Los paquetes pueden compartir un glosario pero tener distintos idiomas?
Sí. Haz que ambos paquetes apunten al mismo engineId, pero configura distintos locale.targets en cada i18n.json. El glosario del motor se aplica a cualquier par de idiomas solicitado.
