Volver al blog
A git diff view showing a locale file with three changed keys highlighted, and only those three keys being sent to the translation API below.

No necesitas volver a traducir todo: cómo funciona la traducción delta en CI

By Robert M

No necesitas volver a traducir todo: cómo funciona la traducción delta en CI

Una vez que tienes la traducción automatizada integrada en tu pipeline de CI, surge rápidamente una pregunta natural: ¿se vuelve a traducir todo el archivo de localización cada vez que alguien hace un push con un cambio?

Sin el modo delta, sí. Cada push que toca tu archivo de localización fuente envía todo el archivo a la API, cada clave, cada cadena, haya cambiado o no. Para un proyecto pequeño en sus inicios está bien. Para un proyecto maduro con cientos de claves de traducción en 10 o 20 idiomas, estás gastando tokens en cadenas que no han cambiado desde la última ejecución y recibiendo la misma salida a cambio.

La traducción delta soluciona esto. En lugar de enviar el archivo completo, la Action compara tu archivo fuente actual con una línea base almacenada, identifica solo las claves que se añadieron o modificaron, y envía solo esas a la API. La salida para las claves sin cambios se toma de los archivos traducidos existentes. El uso de tokens baja para coincidir con el trabajo real que se está haciendo.


Cómo funciona la línea base

Cuando el modo delta se ejecuta por primera vez, o cuando fuerzas una actualización completa, la Action traduce el archivo fuente completo y almacena una representación JSON plana como archivo de línea base en tu repositorio. En ejecuciones posteriores, la Action carga esa línea base, la compara con el archivo fuente actual y construye una carga útil que contiene solo las claves cambiadas.

Para archivos de localización JSON, la línea base se almacena como .polylingo-baseline.json en tu directorio de mensajes. Para archivos YAML de localización es .polylingo-yaml-baseline.json en tu directorio de locales. Para archivos Laravel PHP lang es .polylingo-laravel-php-baseline.json en tu directorio lang.

La línea base se comete junto con tus archivos traducidos para que viaje con el repositorio. Cualquier desarrollador que clone el repo obtiene la misma línea base desde la que trabaja la pipeline.


Qué cuenta como cambio

El diff opera sobre la representación de clave plana de tu archivo fuente. Las estructuras anidadas se aplanan a claves con notación de puntos antes de la comparación:

{
  "nav.home": "Inicio",
  "nav.about": "Sobre nosotros",
  "hero.title": "Bienvenido a nuestra plataforma",
  "hero.cta": "Comenzar"
}

Una clave se incluye en la carga delta si:

  • Existe en el archivo fuente actual pero no en la línea base (clave nueva)
  • Existe en ambos pero el valor ha cambiado (clave modificada)

Las claves que existen en la línea base pero no en el archivo fuente actual (claves eliminadas) se eliminan automáticamente de los archivos de salida traducidos. Las claves idénticas en ambos se omiten completamente y sus traducciones existentes permanecen.


Cómo se ve esto en la práctica

Supongamos que tienes un proyecto Next.js con 200 claves de traducción en messages/en.json, ya traducidas a 12 idiomas. Un desarrollador actualiza el texto de la sección hero y añade dos claves nuevas para un anuncio de función. Eso son 4 claves cambiadas de 200.

Sin modo delta, la pipeline envía las 200 claves multiplicadas por 12 idiomas en cada push. Con modo delta envía 4 claves. El uso de tokens para esa ejecución es aproximadamente el 2% de lo que costaría una traducción completa. La pipeline también es más rápida porque hay menos que enviar y menos que esperar.

En un mes de desarrollo regular, el ahorro se acumula significativamente. La mayoría de los push tocan unas pocas cadenas. La retraducción completa solo ocurre cuando añades un nuevo idioma o restableces explícitamente la línea base.


Las tres GitHub Actions de PolyLingo

El modo delta está disponible en las tres Actions de traducción de PolyLingo. Cada una está construida para un tipo específico de contenido y estructura de proyecto.

translateAction — JSON y Markdown

La Action original. Maneja archivos de localización JSON planos al estilo next-intl e i18next, con un pase opcional de documentación Markdown vía la API de trabajos asíncronos para archivos grandes.

- uses: UsePolyLingo/translate-action@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    source_file: messages/en.json
    locales: fr,de,es,ja,zh
    delta: true
    commit: true
    commit_message: "chore(i18n): sync translations"

Línea base delta: messages/.polylingo-baseline.json

github.com/UsePolyLingo/translateActionVer en Marketplace


translate-action-yaml — Archivos de localización YAML

Para proyectos que usan archivos de localización YAML anidados: Rails i18n, Vue i18n y cualquier otro framework que use formato YAML. La Action maneja automáticamente la convención Rails de una clave raíz de localización — en.yml tiene una clave raíz en:, y cada archivo de salida recibe la clave de localización destino correcta (fr:, de: etc).

Dado que la API PolyLingo trabaja nativamente con JSON, la Action aplana YAML anidado a JSON con notación de puntos antes de enviarlo, traduce, luego reconstruye la estructura anidada y escribe salida YAML válida. Una advertencia de v1: las claves que contienen puntos naturalmente no son soportadas, ya que entran en conflicto con el aplanado de notación de puntos.

- uses: UsePolyLingo/translate-action-yaml@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    locales_dir: config/locales
    source_file: config/locales/en.yml
    locales: fr,de,es,ja
    delta: true
    commit: true

Línea base delta: config/locales/.polylingo-yaml-baseline.json

github.com/UsePolyLingo/translate-action-yamlVer en Marketplace


translate-action-laravel — Archivos lang de Laravel

Para proyectos Laravel que usan archivos de traducción JSON (lang/en.json, soportando estructuras anidadas y planas al estilo Laravel 9+) o archivos PHP array lang (lang/en/*.php). La Action detecta automáticamente qué formato usa tu proyecto mediante php_format: auto — primero busca lang/en.json y si no lo encuentra, usa archivos PHP array.

Para archivos PHP, ejecuta la CLI de PHP para leer los archivos fuente y serializa la salida traducida de vuelta a sintaxis válida de array PHP en JavaScript, sin dependencias adicionales. Los runners ubuntu-latest alojados en GitHub incluyen PHP 8.x por defecto, por lo que no se necesita paso adicional de configuración. Se requiere PHP 7.4 o superior.

Una advertencia de v1: las claves que contienen puntos no son soportadas en modo PHP debido a la estrategia de aplanado de notación de puntos.

- uses: UsePolyLingo/translate-action-laravel@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    lang_dir: lang
    source_locale: en
    locales: fr,de,es,pt,nl
    php_format: auto
    delta: true
    open_pr: true

Línea base delta: lang/.polylingo-laravel-json-baseline.json o lang/.polylingo-laravel-php-baseline.json dependiendo del formato.

github.com/UsePolyLingo/translate-action-laravelVer en Marketplace


Modo PR vs modo commit

Las tres Actions soportan dos modos de salida.

Modo commit (commit: true) escribe los archivos traducidos y los comitea directamente en la rama actual. Configuración simple, bueno para equipos que tratan la traducción como un proceso automatizado que no necesita revisión.

Modo PR (open_pr: true) crea una nueva rama (polylingo/yaml-<sha>, polylingo/laravel-<sha> etc), escribe los archivos traducidos allí y abre un pull request contra tu rama base. Mejor para equipos que quieren un paso de revisión humana antes de que el contenido traducido se fusione, o para proyectos donde la calidad de la traducción afecta directamente la experiencia del usuario.

Cuando ambos están configurados, gana el modo PR.

El modo PR requiere pull-requests: write en los permisos de tu workflow:

permissions:
  contents: write
  pull-requests: write

Forzar una actualización completa

El modo delta compara con la línea base almacenada. Si quieres retraducir todo sin importar lo que muestre la línea base, configura delta: false. Esto también actualiza la línea base para que coincida con el archivo fuente actual, así que las ejecuciones delta posteriores comienzan desde el nuevo estado.

Una actualización completa es útil cuando añades un nuevo idioma objetivo, cuando quieres incorporar mejoras en la calidad de la traducción en una nueva versión del modelo, o cuando la línea base se ha desviado de la realidad por cualquier motivo.

- uses: UsePolyLingo/translate-action-yaml@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    locales_dir: config/locales
    locales: fr,de,es,ja,zh,ko,ar
    delta: false  # actualización completa, actualiza línea base
    commit: true

Salidas para pasos posteriores

Las tres Actions exponen las mismas salidas para que puedas usarlas en pasos posteriores del workflow:

- uses: UsePolyLingo/translate-action@v1
  id: translate
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    source_file: messages/en.json
    locales: fr,de,es
    delta: true
    commit: true

- name: Registrar estadísticas de traducción
  run: |
    echo "Idiomas traducidos: ${{ steps.translate.outputs.locales_translated }}"
    echo "Archivos cambiados: ${{ steps.translate.outputs.files_changed }}"
    echo "Tokens usados: ${{ steps.translate.outputs.tokens_used }}"

Cada ejecución también escribe una tabla resumen en el resumen del paso de GitHub Actions para que puedas ver el uso de tokens y los resultados de la traducción sin buscar en los logs.


Comenzando

Las tres Actions están disponibles en el GitHub Marketplace. Necesitarás una clave API de PolyLingo, disponible gratis en usepolylingo.com. El nivel gratuito incluye 50,000 tokens por mes. Con el modo delta activado, la mayoría de los proyectos se mantendrán cómodamente dentro de ese límite en los pushes de desarrollo rutinarios.

Agrega tu clave API como un secreto del repositorio (POLYLINGO_API_KEY) y coloca la Action relevante en tu workflow. La primera ejecución hace una traducción completa y establece la línea base. Cada ejecución posterior solo traduce lo que cambió.