La CLI traduce dieciocho formatos de archivo. El formato se deduce a partir de la extensión del archivo; para sobrescribirlo, configura format en una entrada files[], algo imprescindible en los tres formatos que siempre lo requieren (yaml-openapi, yaml-root-key, android).
| Formato | Extensiones | Valor de format | Notas |
|---|---|---|---|
| JSON | .json | json | Clave/valor. Compatible con controles de clave. |
| JSONC | .jsonc | jsonc | JSON con comentarios. Los comentarios se conservan y además funcionan como notas para traductores. |
| YAML | .yaml, .yml | yaml | YAML genérico. Se traduce cada valor de texto; las claves y la estructura se conservan. |
| YAML de OpenAPI | .yaml, .yml | yaml-openapi | Especificaciones OpenAPI. Define format explícitamente: un .yaml normal se detecta automáticamente como yaml. |
| Clave raíz YAML del idioma | .yaml, .yml | yaml-root-key | El idioma es la clave raíz de YAML (Rails config/locales). La clave raíz se reescribe al idioma de destino. Configura format explícitamente. |
| Markdown | .md | md | Se traduce la prosa; el frontmatter es opcional. |
| MDX | .mdx | mdx | Markdown + JSX. Las props de los componentes son opcionales. |
| Markdoc | .mdoc | markdoc | Markdown + etiquetas. Frontmatter + atributos de etiquetas. |
| TypeScript | .ts, .mts, .cts | typescript | Módulos de idioma (export default { … }). Se traducen los literales de texto; el código se conserva. |
| Gettext PO | .po | po | Se traduce msgstr; msgid, los comentarios y las cabeceras se conservan. |
| Flutter ARB | .arb | flutter | Se traducen los valores de texto; se conservan los metadatos @ y {placeholders}. |
| Android | .xml | android | strings.xml. Define format explícitamente: .xml no se detecta automáticamente. |
| Cadenas de Xcode | .strings | xcode-strings | Se traducen los valores; las claves se conservan. |
| Catálogo de cadenas de Xcode | .xcstrings | xcode-xcstrings | Un solo archivo contiene todos los idiomas: los destinos se vuelven a escribir en ese mismo archivo (véase más abajo). |
| stringsdict de Xcode | .stringsdict | xcode-stringsdict | Se traducen las cadenas plurales; las claves de control de formato se conservan. |
| XLIFF | .xlf, .xliff | xliff | Se conserva <source> y se escribe <target> por unidad. Versiones 1.2 y 2.0. |
| SubRip | .srt | srt | Se traduce el texto de los subtítulos; los índices y los códigos de tiempo no se tocan. |
| PHP | .php | php | Archivos de idioma de Laravel. Se traducen los valores de texto; las claves, los números y la estructura se conservan. |
Verlo de principio a fin
El proyecto de demostración es un pequeño Sandbox que reúne los formatos de documentos y datos — JSON, JSONC, Markdown, MDX, Markdoc y OpenAPI YAML — cada uno con la configuración exacta que necesita. Clónalo con npx degit lingodotdev/lingo.dev/demo/new-cli my-lingo-demo y haz un push. Los formatos de app y framework no están incluidos; para esos casos, Example projects ofrece un repositorio completo por framework, y los fragmentos de abajo, organizados por formato, cubren la configuración.
npx degit lingodotdev/lingo.dev/demo/new-cli my-lingo-demo
cd my-lingo-demoJSON y JSONC#
Traducción sencilla de clave/valor. Se traduce cada valor de texto, salvo que un control de clave indique lo contrario.
{ "pattern": "content/en/app.json", "lockedKeys": ["meta.version"] }JSONC, además, conserva los comentarios, que el motor interpreta como contexto. Consulta notas para traductores.
{ "pattern": "content/en/settings.jsonc", "preservedKeys": ["featureFlags"] }Markdown, MDX y Markdoc#
La prosa del cuerpo se traduce por defecto. El frontmatter y los componentes incrustados no se traducen a menos que lo actives expresamente.
Frontmatter#
Indica con translateFrontmatterFields qué campos del frontmatter quieres traducir:
{
"pattern": "content/en/guide.md",
"translateFrontmatterFields": ["title", "description"]
}Props de componentes MDX#
En MDX, puedes traducir props concretas de componentes concretos con translateComponentProps:
{
"pattern": "content/en/landing.mdx",
"translateFrontmatterFields": ["title"],
"translateComponentProps": [{ "component": ["Hero", "Callout"], "props": ["title", "body"] }]
}Esto traduce las props title y body de <Hero> y <Callout>, y deja intactas todas las demás.
Markdoc#
Markdoc funciona como Markdown, conservando el frontmatter y los atributos de las etiquetas:
{
"pattern": "content/en/changelog.mdoc",
"translateFrontmatterFields": ["title"]
}YAML#
El YAML genérico se detecta automáticamente a partir de .yaml/.yml: se traduce cada valor de texto y se conservan las claves y la estructura:
{ "pattern": "content/en/strings.yaml" }Las especificaciones OpenAPI son un caso especial: comparten la extensión .yaml, pero necesitan un format explícito para que el motor traduzca solo los campos visibles para las personas (resúmenes, descripciones) y deje intactas las claves del esquema, las rutas y los ID de operación:
{ "pattern": "content/en/api.yaml", "format": "yaml-openapi" }Los archivos de idioma con formato Rails son el otro caso especial: el idioma es la clave raíz de YAML (en:) y el archivo de destino debe tener como raíz el idioma de destino (es:). En estos casos, configura también format explícitamente:
{ "pattern": "config/locales/en.yml", "format": "yaml-root-key" }Formatos de apps y frameworks#
PO, Flutter ARB, Xcode .strings, Xcode .stringsdict, módulos de idioma de TypeScript, XLIFF, SubRip y PHP siguen la misma regla: se traduce el texto traducible y se conserva todo lo estructural (claves, ID, metadatos, marcadores de posición, códigos de tiempo, código, formato). Cada uno se detecta automáticamente por su extensión; solo tienes que apuntar un patrón al archivo fuente:
{ "pattern": "lib/l10n/app_en.arb" }
{ "pattern": "locales/en.po" }
{ "pattern": "Localizable.strings" }
{ "pattern": "l10n/en.xlf" }Hay uno que necesita un format explícito porque su extensión es demasiado ambigua para detectarla automáticamente:
{ "pattern": "res/values/strings.xml", "format": "android" }Catálogos de cadenas de Xcode#
Un archivo .xcstrings (String Catalog) contiene todos los idiomas en un solo archivo. No hay una ruta de salida por idioma: el CLI lee el idioma de origen y vuelve a escribir cada destino en ese mismo archivo:
{ "pattern": "Localizable.xcstrings" }Las cadenas marcadas con "shouldTranslate": false en el catálogo se omiten: la CLI las deja sin traducir y sin tocar.
Rutas de salida#
El patrón da nombre a tu archivo de origen; a partir de él se derivan todas las rutas de destino. Se aplican cuatro reglas, en este orden:
- Un segmento completo de la ruta o un nombre de archivo que sea el idioma — el caso más habitual.
content/en/app.json→content/de/app.json,locales/en.json→locales/de.json. - Un idioma al final de un segmento o de un nombre de archivo, en las estructuras que lo expresan así: Android, Xcode
.strings/.stringsdict, Flutter yyaml-root-key.res/values-en/→res/values-de/,app_en.arb→app_de.arb,devise.en.yml→devise.de.yml. - El nombre reservado de una plataforma para el idioma predeterminado, sin que aparezca ningún idioma en la ruta. El
res/values/a secas de Android pasa a serres/values-de/, y elBase.lprojde Xcode pasa a serde.lproj. - El String Catalog, donde la ruta de destino es la ruta de origen, porque un único archivo contiene todos los idiomas.
Android es la única plataforma cuyas rutas de destino no siguen BCP 47: la CLI escribe el calificador de recursos que Android realmente utiliza, así que pt-BR va a parar a values-pt-rBR/ y zh-Hans a values-b+zh+Hans/.
Si ninguna de las reglas encaja —el idioma de origen no aparece en ninguna parte de la ruta—, la CLI recurre a crear un directorio <locale>/ junto al archivo, y lingo push te avisa de que ha hecho esa suposición. Tómalo como una señal de que el patrón no es correcto. Consulta Configuration.
¿Vienes del CLI heredado?#
La mayoría de los formatos del CLI heredado ya están disponibles en el CLI actual (PO, XLIFF, cadenas de Android/Xcode, Flutter ARB y más; consulta la tabla de arriba). Algunos formatos menos habituales (por ejemplo, CSV, HTML, MJML, .properties) aún no están disponibles; hasta que llegue el tuyo, la documentación del CLI heredado te lo cubre.
