Ejecuta Lingo.dev dentro de GitLab CI para que cada merge request que añada o cambie cadenas de origen vuelva con las traducciones ya completadas. El pipeline ejecuta lingo push, el motor traduce solo las claves nuevas o modificadas y el resultado se confirma directamente en la rama de la MR: las traducciones aparecen en el diff de la MR y se revisan antes de que alguien haga el merge. Nada llega a tu rama principal sin que se vea.
Ejemplo funcional
Tienes una configuración completa y lista para ejecutar en gitlab.com/lingo.dev/gitlab-cicd-example.
Requisitos previos#
Una organización y un motor de Lingo.dev, además de una clave de API de servicio (Dashboard → API Keys → create, type service).
Un proyecto configurado para Lingo.dev. Genéralo una vez con:
bashnpx @lingo.dev/cli@latest init # scaffolds .lingo/config.json npx @lingo.dev/cli@latest link # connects the project to your org + engine.lingo/config.jsondeclara los idiomas de origen y destino, además de los globs de origen:json{ "sourceLocale": "en", "targetLocales": ["es", "fr", "de", "zh"], "files": [{ "pattern": "locales/en.json" }], "orgId": "org_...", "engineId": "eng_..." }Un estado base ya confirmado. La primera vez, tradúcelo todo y haz commit para que CI tenga un lockfile con el que comparar diferencias:
bashnpx @lingo.dev/cli@latest push --backfill-missing --wait git add locales .lingo && git commit -m "chore(i18n): baseline translations"
Tokens de acceso#
Añade dos variables de CI/CD enmascaradas en Settings → CI/CD → Variables:
LINGO_API_KEY— tu clave de servicio de Lingo.dev (lingo_sk_...). La CLI la detecta automáticamente para autenticarse.GITLAB_PUSH_TOKEN— un Project Access Token con el scopewrite_repository(rol Developer). Esto permite que CI haga commit de las traducciones directamente en la rama de la MR.
Crea el Project Access Token en Settings → Access tokens. CI_JOB_TOKEN no puede hacer push de commits, así que hace falta un token específico para este paso. Los project access tokens requieren un plan de pago de GitLab.
Pipeline#
Haz commit de este .gitlab-ci.yml. Se ejecuta en merge requests dirigidas a la rama principal y hace push de las traducciones a la rama de origen de la MR:
stages:
- localize
localize:
stage: localize
image: node:22-alpine
rules:
# Only on merge requests that target the default branch.
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
before_script:
- apk add --no-cache git
script:
# Pin the CLI version — never @latest; bump deliberately after testing.
# --wait blocks until the engine finishes and writes files: since 1.6.0
# `push` is async by default (it submits the run and exits), so CI must
# wait to have something to commit.
- npx -y @lingo.dev/cli@1.6.0 push --wait
- |
if [ -z "$(git status --porcelain)" ]; then
echo "Translations already up to date — nothing to commit."
exit 0
fi
git config user.name "lingo-bot"
git config user.email "bot@lingo.dev"
git add locales .lingo/lock.json
# [skip ci] keeps the bot's own commit from re-triggering this pipeline.
git commit -m "chore(i18n): sync translations [skip ci]"
git push "https://oauth2:${GITLAB_PUSH_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}"Pruébalo#
git checkout -b feat/new-strings
# add or change a key in locales/en.json
git commit -am "feat: add strings" && git push -u origin feat/new-strings
# open an MR feat/new-strings -> main (UI, or: glab mr create --fill --target-branch main)El pipeline de la MR ejecuta lingo push --wait, hace commit de locales/{...}.json junto con el .lingo/lock.json actualizado en la rama de la MR, y las traducciones aparecen en el diff. Después, la persona revisora ajusta cualquier valor y hace el merge.
Cómo sobreviven las ediciones manuales#
lingo push conserva las ediciones manuales por clave:
- Edita una cadena de destino (sin cambiar su origen en inglés) → esa cadena se conserva; todas las demás claves se siguen traduciendo.
- Cambia el origen en inglés de una clave editada → se genera una traducción nueva para esa clave (porque ha cambiado el significado).
- Se añade una nueva clave de origen → se traduce y se añade, incluso en archivos que contienen ediciones manuales.
Así, la corrección hecha por la persona revisora en la MR se mantiene en cada ejecución posterior del pipeline, mientras que las claves nuevas y modificadas siguen entrando automáticamente.
Modos de push#
lingo push— incremental; el valor predeterminado en CI. Traduce solo las claves nuevas o modificadas y conserva todo lo demás. Añade--waiten CI para que espere hasta que se escriban los resultados (1.6.0+ es asíncrono por defecto).lingo push --backfill-missing— primer push / arranque de un idioma nuevo; rellena los archivos de destino que todavía no existen. No es para cambios continuos.lingo push --force --yes— vuelve a traducirlo todo desde cero (sobrescribe las ediciones manuales). Poco habitual.
Personalización#
- Commit automático en la rama principal en lugar de en las MR: ejecútalo en
$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCHy haz push de vuelta a$CI_DEFAULT_BRANCH. Es más sencillo, pero la salida de la IA llega a la rama principal sin revisión. - Fijar cadenas concretas: usa
preservedKeys/lockedKeysen.lingo/config.jsonpara mantener determinadas claves fijas incluso cuando cambie su origen. - GitLab autoalojado: funciona sin cambios. En gitlab.com, las cuentas nuevas deben pasar la verificación de identidad antes de que los runners compartidos ejecuten trabajos de CI.
