Saltar al contenido principal

Cómo funciona la sincronización

El comando sync es la operación principal de rosetta. Esto es lo que sucede cuando usted ejecuta npx i18n-rosetta sync.

Descripción general del pipeline

Paso a paso

1. Resolución de la configuración

Rosetta carga i18n-rosetta.config.json (o detecta automáticamente la configuración). Resuelve lo siguiente:

  • El locale de origen y los locales de destino
  • El gráfico de pares (qué combinaciones de origen→destino procesar)
  • La configuración de método, modelo y calidad por par

Antes de escanear los archivos, rosetta imprime un encabezado de inicio:

i18n-rosetta v3.3.2

[INFO] Detected format: json (auto)
[INFO] Detected framework: Hugo
  • Banner de versión: Muestra la versión instalada para la depuración y los reportes de problemas.
  • Detección de formato: Reporta el formato del archivo y si fue detectado automáticamente (auto) o configurado explícitamente (config). Soporta json, toml y yaml.
  • Detección de framework: Cuando se establece contentDir, identifica el framework (Hugo) para confirmar que la sincronización de contenido está activa.

2. Escaneo de origen

El archivo del locale de origen se carga y se aplana en un mapa de clave→valor:

// Input (nested)
{ "hero": { "title": "Welcome", "subtitle": "Build" } }

// Flattened
{ "hero.title": "Welcome", "hero.subtitle": "Build" }

3. Detección de cambios

Rosetta lee .i18n-rosetta.lock, el cual almacena los hashes SHA-256 de los valores de origen traducidos previamente. Para cada clave, verifica lo siguiente:

CondiciónAcción
Clave faltante en el destinoTraducir
El hash de origen cambió desde la última sincronizaciónVolver a traducir (obsoleto)
El valor de destino comienza con [EN]Volver a traducir (marcador de respaldo heredado)
Hash de origen sin cambios, la clave existeOmitir

Esta es la razón por la que rosetta solo traduce lo que cambió; no vuelve a traducir todo su archivo en cada sincronización.

4. Procesamiento por lotes

Las claves se agrupan en lotes (predeterminado: 80 claves/lote para LLM, 128 para Google Translate). El procesamiento por lotes reduce las idas y vueltas de la API mientras mantiene los prompts manejables.

Durante la traducción, rosetta muestra una barra de progreso en línea que se actualiza después de que se completa cada lote:

[INFO] fr.json — 2,847 missing
████████████████░░░░░░░░░░░░░░░░ 1,440/2,847 keys

La barra se renderiza usando el retorno de carro \r para actualizaciones en el mismo lugar, sin desplazamiento. Se suprime en los modos --quiet y --json.

4b. Memoria de traducción

Antes del procesamiento por lotes, rosetta verifica la caché de la Memoria de traducción (.rosetta/tm.json). Las claves cuyo texto de origen + locale + método coinciden con una traducción anterior se sirven instantáneamente desde la caché; no se necesita ninguna llamada a la API.

[TM] 142 key(s) served from cache
Translating 3 key(s) to French (llm)... [OK]

La Memoria de traducción (TM) es el principal mecanismo de ahorro de costos. Volver a ejecutar la sincronización después del cambio de una sola clave solo traduce esa clave, no todo el archivo. Consulte Memoria de traducción para obtener más detalles.

Para omitir la caché en una sola ejecución: i18n-rosetta sync --no-tm

5. Traducción

Cada lote se envía al método de traducción configurado:

  • llm: Prompt estructurado a OpenRouter con instrucciones de guía de registro y género
  • llm-coached: Igual que el anterior, pero con reglas gramaticales, diccionario y notas de estilo inyectadas
  • google-translate: Solicitud por lotes a Google Cloud Translation API v2
  • api: HTTP POST a un endpoint remoto

El mensaje del sistema (registro, guía de género, reglas) es idéntico en todos los lotes para un locale determinado, lo que permite el almacenamiento en caché de prompts (prompt caching): proveedores como Anthropic y Google almacenan en caché los mensajes del sistema repetidos, reduciendo los costos de tokens.

6. Puerta de calidad

Cada traducción se valida antes de escribirse en el disco. Se ejecutan cinco comprobaciones:

ComprobaciónQué detectaEjemplo
Vacío/en blancoEl modelo no devolvió nada""
Eco de origenEl modelo devolvió la entrada en inglés"Welcome" para japonés
Bucle de alucinaciónTrigramas repetidos"Qo' Qo' Qo' Qo'"
Inflación de longitudLa salida es 4 veces o más larga que el origenOrigen de 10 caracteres → salida de 50 caracteres
Cumplimiento de escrituraSistema de escritura incorrecto para el localeTexto latino para un locale en árabe

Las fallas se registran con un prefijo [GATE]. No hay respaldos silenciosos.

Consulte Puerta de calidad para obtener más detalles.

6b. Verificación de terminología

Para los pares entrenados (coached) con un diccionario, rosetta verifica si el LLM realmente utilizó la terminología requerida después de la traducción. Las infracciones se registran como advertencias [TERM]:

[TERM] en→fr: 2 term violation(s)
• "dashboard" → expected "tableau de bord" but got "panneau"

Estas son advertencias, no errores bloqueantes; la traducción se escribe de todos modos.

7. Cascada de reintentos

En caso de falla de análisis JSON o errores a nivel de lote, rosetta vuelve a intentar con lotes progresivamente más pequeños:

Full batch (80 keys) → Failed
└→ Half batch (40 keys) → 1 failure
└→ Individual keys (1 each) → Isolates the problem key

El presupuesto de reintentos está limitado por maxRetries (predeterminado: 3) para evitar un gasto descontrolado de tokens.

8. Escritura y bloqueo

Las traducciones aprobadas se escriben en el archivo del locale de destino, preservando la estructura de anidamiento original. El archivo de bloqueo (lock file) se actualiza con los nuevos hashes SHA-256.

9. Verificación

Después de procesar todos los pares, rosetta vuelve a leer los archivos de locale escritos en el disco y ejecuta un paso de verificación (a menos que se establezca --no-verify). Esto detecta la brecha entre el éxito reportado por la sincronización y las claves que en realidad son incorrectas:

  • Paridad de claves: todas las claves de origen están presentes en cada destino
  • Marcadores de respaldo [EN]: marcadores heredados de ejecuciones anteriores
  • Traducciones vacías: valores en blanco que se filtraron
  • Cumplimiento de escritura: locales no latinos con traducciones que solo contienen ASCII
  • Preservación de marcadores de posición: los marcadores de posición ICU coinciden con el origen
  • Problemas de codificación: marcadores BOM, caracteres invisibles

Esto también está disponible como un comando i18n-rosetta verify independiente para las puertas de CI.

Traducción de contenido (Fase 2)

Para los proyectos de Docusaurus y Hugo, sync ejecuta una segunda fase después de la traducción de claves JSON. Esta fase traduce archivos Markdown y MDX (documentación, publicaciones de blog, tutoriales) utilizando los mismos métodos y la puerta de calidad.

Cómo funciona

  1. Rosetta descubre todos los archivos de contenido de origen (.md, .mdx) recorriendo el directorio content/docs
  2. Para cada par de archivo × locale, verifica un archivo de bloqueo de contenido separado (.i18n-rosetta-content.lock) en busca de cambios en el hash SHA-256
  3. Los archivos modificados o faltantes se recopilan en un grupo plano de elementos de trabajo (work-item pool)
  4. El grupo se procesa con concurrencia paralela (predeterminado: 12 llamadas simultáneas a la API)
Phase 2: content (79 translations to process, 341 skipped, concurrency: 48)

[1/79] (1%) docs/concepts/security.md → ja [RE-TRANSLATE] (~3328s left)
[2/79] (3%) docs/concepts/security.md → th [RE-TRANSLATE] (~1821s left)
...
[79/79] (100%) blog/v3-2-quality.md → de [OK]

[OK] Created 79 content file(s), 341 unchanged

Paralelismo

Tanto la Fase 1 (claves JSON) como la Fase 2 (contenido) ahora se ejecutan en paralelo:

  • Fase 1: Todas las traducciones de locales se inician de forma concurrente (predeterminado: 50 locales simultáneos). Dentro de cada locale, los lotes de la API también se ejecutan en paralelo (4 lotes concurrentes). Una sincronización de 12 locales con 120 claves se completa en ~1 minuto en lugar de ~15 minutos.
  • Fase 2: Todas las combinaciones de archivo × locale se traducen como un grupo plano (predeterminado: 12 llamadas simultáneas a la API). Diferentes archivos y diferentes locales se traducen simultáneamente.

Controle el paralelismo con --json-concurrency, --content-concurrency o --concurrency (establece ambos):

# Faster JSON sync (more parallel locale translations)
npx i18n-rosetta sync --json-concurrency 30

# Faster content sync (more parallel API calls)
npx i18n-rosetta sync --content-concurrency 20

# Slower (gentler on rate limits)
npx i18n-rosetta sync --concurrency 4

Protección de contenido

Durante la traducción, rosetta protege el contenido no traducible:

  • Bloques de código (cercados y con sangría) se reemplazan con marcadores de posición
  • Campos de frontmatter que no están en la lista translatableFields se preservan tal cual
  • Enlaces, rutas de imágenes y etiquetas HTML están protegidos
  • Shortcodes y variables de interpolación (por ejemplo, {count}, {{.Params.title}}) están resguardados

Después de la traducción, todos los marcadores de posición se restauran y validan. Si falta alguno o está dañado, la traducción se rechaza y se vuelve a intentar.

Éxito parcial

Un lote fallido no bloquea al resto. Si 9 de cada 10 lotes tienen éxito, esos 9 se escriben. El lote fallido se registra y usted puede volver a ejecutar sync para reintentar.

Ejecución de prueba (Dry Run)

Obtenga una vista previa de lo que cambiaría sin escribir ningún archivo:

npx i18n-rosetta sync --dry-run

Forzar nueva traducción

Fuerce la traducción de claves específicas incluso si no han cambiado:

npx i18n-rosetta sync --force-keys "hero.title,nav.about"

Estimación de costos

Antes de traducir, rosetta genera un reporte de costos previo a la sincronización que muestra los costos estimados por par. Esto se ejecuta automáticamente durante cada sync; usted lo ve antes de que se realice cualquier llamada a la API.

╔══════════════════════════════════════════════════════════╗
║ Cost Estimate ║
╠════════════╦═══════╦════════════╦════════════════════════╣
║ Pair ║ Keys ║ Est. Cost ║ Method ║
╠════════════╬═══════╬════════════╬════════════════════════╣
║ en → fr ║ 142 ║ $0.07 ║ google-translate ║
║ en → ja ║ 38 ║ — ║ llm (model-dependent) ║
║ en → crk ║ 38 ║ — ║ llm-coached ║
╚════════════╩═══════╩════════════╩════════════════════════╝

Qué se estima

Cada método de traducción proporciona su propia estimación de costos:

MétodoBase de costoPrecisión
google-translateTarifa publicada de Google ($20/millón de caracteres)Exacta
llmVaría según el modelo de OpenRouterDepende del modelo — consulte los precios de OpenRouter
llm-coachedIgual que llm más los tokens de contexto de entrenamiento (coaching)Depende del modelo
apiDeterminado por el servidorDesconocida — no se puede estimar sin consultar el endpoint

Cuando un método no puede determinar el costo (métodos LLM, API remotas), rosetta reporta en lugar de adivinar. Use --dry para ver las estimaciones de costos sin realizar la traducción.


Consulte también