Formatos
Los ocho formatos soportados, cómo lee y escribe sus archivos cada uno, y la garantía de orden de claves del documento.
Página traducida automáticamente
verbatra trabaja sobre tus archivos de locale a través de un adaptador de formato. Cada adaptador lee un archivo y lo convierte en una forma neutral al formato sobre la que corren el diff, el hashing y las comprobaciones de integridad, y luego lo escribe de vuelta con la forma original del archivo. Eliges el formato con el campo format de tu configuración. Se soportan ocho: cuatro variantes de JSON, más XLIFF, YAML, ARB y properties de Java/Spring.
Los cuatro formatos JSON
format | Para | Marcadores de posición | Plurales | ICU |
|---|---|---|---|---|
i18next-json | i18next | {{name}} y referencias de anidamiento $t(...) | sufijo de plural CLDR en la clave | no |
vue-i18n-json | vue-i18n | {name}, {0} | pipe en el valor | no |
next-intl-json | next-intl | nombres de argumentos y etiquetas ICU | plural o selectordinal ICU | sí |
ngx-translate-json | ngx-translate | {{name}} | ninguno | no |
Los cuatro leen objetos JSON anidados de hojas string. Sus diferencias son la sintaxis de mensajes:
- i18next usa interpolación
{{double-brace}}y decide el plural por el sufijo CLDR de la clave (_zero,_one,_two,_few,_many,_other). Además extrae y protege como marcadores de posición las referencias de anidamiento$t()(que empalman el contenido de otra clave dentro del valor), por ejemplo$t(common.foo)y$t(common.foo, { options }), así que una traducción que pierda o altere una falla la comprobación de integridad. Dos limitaciones: no se soportan paréntesis anidados dentro de las opciones de$t(), y solo se reconoce el prefijo predeterminado$t(. - vue-i18n usa tokens de llave simple
{name}y{0}y decide el plural por un pipe en el valor. - Los valores de next-intl son ICU MessageFormat: los marcadores de posición son los nombres de argumentos y de etiquetas de texto enriquecido ICU, el plural sigue un argumento ICU plural o selectordinal, y el cuerpo ICU se mantiene textual a través de la canalización. Un valor que no parsea como ICU se informa como inválido y se omite, nunca se lanza.
- ngx-translate comparte la interpolación
{{double-brace}}de i18next pero no tiene anidamiento$t()ni plural o ICU integrados. Sus archivos pueden ser planos (claves con puntos) o anidados, y verbatra preserva al escribir el estilo que use el archivo; un archivo de destino nuevo se escribe anidado. De forma única, un archivo que mezcla claves planas con puntos y objetos anidados falla la lectura conMIXED_STRUCTURE, porque un archivo así es ambiguo y no adivinable.
XLIFF
El formato xliff cubre archivos .xlf y .xliff, XLIFF 1.2 (file/body/trans-unit) y 2.0 (file/unit/segment). A diferencia de los formatos de árbol, un documento XLIFF es una lista plana de trans-units.
- Claves. Cada entrada se identifica por el
idde su trans-unit, conresnamecomo respaldo. Una unidad sin ninguno de los dos recurre a una clave posicional, que se desplaza cuando se añaden o quitan unidades anteriores, así que dale a cada unidad unidestable. Dos unidades que resuelven a la misma clave (normalmente unidduplicado) hacen fallar la lectura conINVALID_STRUCTUREen lugar de quedarse con una en silencio. - Valores. El valor viene de
<target>cuando está presente, y de<source>en caso contrario. - Las escrituras actualizan los targets en su sitio. verbatra escribe cada valor en su
<target>y deja intactos<source>, los atributos y los elementos<note>, así que el documento hace el viaje de ida y vuelta. Como un mapa plano de clave/valor no puede reconstruir un documento XLIFF, el archivo de destino debe existir ya: verbatra actualiza los targets en un archivo de destino pre-sembrado (el flujo XLIFF estándar) y no crea uno ausente; un destino ausente falla conINVALID_STRUCTURE. - Marcado en línea. Los elementos de marcador de posición en línea (
x,g,bx,ex,ph,it,mrk) y la interpolación de llave simple{name}se extraen como marcadores de posición y se protegen a través de la traducción. Al escribir, solo esos elementos de la lista permitida (con sus propios atributos mínimos y no ejecutables) sobreviven como marcado vivo en<target>; cualquier otra cosa en un valor traducido, incluido un elemento inesperado o una discordancia de namespace, se escribe como texto plano. - Las notas como contexto. El
<note>de una trans-unit (en 2.0, el<notes><note>de la unidad, compartido por todos los segmentos de la unidad) se lee como contexto de desarrollador: llega al proveedor como contexto de desambiguación y aparece en la columnaContextde un libro exportado. Es de solo lectura y nunca se escribe de vuelta.
YAML
El formato yaml cubre archivos .yml y .yaml: un árbol anidado en sintaxis YAML, la misma forma que un archivo JSON anidado, manejado por la misma canalización de árbol. Asume interpolación {{double-brace}} compatible con i18next y detecta solo por extensión.
- Los comentarios YAML no sobreviven una escritura, igual que JSON no tiene concepto de comentario.
- Las claves escalares no string conservan su forma de cadena (
1:se lee como"1",true:como"true"). - Una clave compuesta (un mapa o secuencia usados como clave de mapeo) no tiene una forma de cadena fiel, así que la lectura falla con
INVALID_STRUCTUREen lugar de colapsarla a texto en silencio. - La sintaxis malformada se informa como
INVALID_YAML, y la expansión de anclas y alias está acotada, así que un documento hostil no puede hacer estallar el parseo.
ARB
El formato arb cubre los archivos .arb de Flutter: JSON con un objeto plano de claves de mensaje junto a metadatos con prefijo @ (metadatos por mensaje @key y globales con prefijo @@ como @@locale).
- Los metadatos se preservan, nunca se traducen. Las claves con prefijo
@se apartan antes de la traducción y se fusionan de vuelta al escribir, en su posición del documento. Un archivo de destino que existe pero está corrupto hace fallar la escritura en lugar de borrar sus metadatos en silencio. - Los mensajes son ICU. Los marcadores de posición, el manejo de plurales y la validación ICU funcionan exactamente igual que para
next-intl-json. - Las descripciones se vuelven contexto. Cada
@key.descriptionse lee como contexto de desarrollador para ese mensaje: llega al proveedor como contexto de desambiguación (nunca como texto a traducir) y aparece en la columnaContextde un libro exportado. Es de solo lectura y nunca se escribe de vuelta.
Properties
El formato properties cubre los archivos .properties de Java y Spring, detectados por la extensión .properties: una lista plana de líneas clave/valor. Las claves se mantienen literales como claves planas, nunca se dividen en un árbol.
- Separadores y comentarios. Una clave se separa de su valor con
=,:o espacios en blanco, ignorando los espacios alrededor del separador, igual quejava.util.Properties. Una línea cuyo primer carácter no en blanco es#o!es un comentario. - Continuaciones y escapes. Una línea que termina en una barra invertida continúa en la siguiente. Los escapes estándar (
\t,\n,\r,\f,\\, un separador o carácter de comentario escapado) y\uXXXXse decodifican al leer. La entrada se lee como UTF-8; al escribir, cada carácter no ASCII se emite como un escape\uXXXXseguro en ASCII, para que el archivo siga cargándose con un lector antiguo ISO-8859-1. - Se conservan el orden, los comentarios y las líneas en blanco. Una escritura vuelve a leer el destino y conserva su orden de claves, sus comentarios y sus líneas en blanco: cada línea de clave existente se reescribe en su sitio con su nuevo valor, y una clave que el archivo aún no tiene se añade en el orden del origen. Una clave duplicada mantiene su primera posición y toma el último valor, igual que
Properties.load. - Los marcadores de posición son MessageFormat. Los valores se leen como
java.text.MessageFormat, así que{0}, la forma con tipo{0,number}, la forma con estilo{0,number,integer}y los argumentos con nombre como{count}se extraen y se protegen durante la traducción. Los argumentos de submensaje (plural,select,selectordinal,choice) se reconocen, así que traducir el texto de la rama sigue siendo una coincidencia, pero eliminar o renombrar un argumento no. - Limitación: las comillas simples no se interpretan. El entrecomillado con comilla simple de MessageFormat no se respeta, así que un literal entrecomillado como
'{0}'se sigue leyendo como un marcador de posición. Es deliberado, para que un apóstrofo corriente en el texto traducido nunca se trague un marcador de posición que le siga.
Orden de claves del documento
Las escrituras preservan el orden de claves de tu documento. La familia JSON, YAML y ARB hacen el viaje de ida y vuelta de las claves exactamente en el orden del documento:
- Una clave con pinta de entero como
"2","10"o"404"conserva su posición en lugar de ser izada al frente y reordenada, así que un archivo con claves de ids numéricos, códigos de estado HTTP o años se queda en su propio orden. - Una clave que una ejecución de
translateañade a un archivo de destino se añade después de las claves existentes del destino, siguiendo el orden del documento de origen, en lugar de insertarse alfabéticamente. - Los bloques de metadatos ARB también hacen el viaje de ida y vuelta en su posición del documento.
XLIFF no se ve afectado: actualiza los elementos <target> existentes en su sitio, así que el orden del documento nunca se reconstruyó en primer lugar.
Claves con puntos y colisiones
Para i18next-json, vue-i18n-json y next-intl-json, una hoja literal con puntos (una clave como "foo.bar" usada como una única hoja) hace el viaje de ida y vuelta sin pérdida: verbatra la lee y la escribe de vuelta con su forma en disco preservada, sin re-anidarla en foo y luego bar. Las rutas anidadas reales siguen anidadas.
El único caso que falla por diseño es una colisión genuina, donde un archivo expresa la misma ruta efectiva a la vez como hoja literal con puntos y como ruta anidada real (por ejemplo "foo.bar" junto a "foo": { "bar": ... }). Esa lectura falla con INVALID_STRUCTURE en lugar de adivinar o corromper datos.
ngx-translate-json trata una clave con puntos como una ruta anidada y no como una hoja literal, así que no hay ambigüedad de literal contra puntos que preservar, pero recibe la misma seguridad ante colisiones: una clave con puntos cuya ruta colisiona con una ruta anidada real, incluido el caso en que una es ancestro de la otra, falla con INVALID_STRUCTURE en lugar de sobrescribir un valor en silencio.
Cómo se leen y escriben los archivos
verbatra limita el tamaño de entrada y la profundidad de anidamiento al leer, y resiste que un archivo cambie por debajo. Escribe de forma atómica: escribe en un archivo temporal y luego lo renombra a su sitio, así que una escritura interrumpida nunca deja un archivo de locale a medias. Cuando verbatra no puede manejar un archivo, levanta un error estructurado y sin secretos con un código estable en lugar de uno crudo: INVALID_JSON, INVALID_YAML o INVALID_XML para sintaxis malformada, INVALID_STRUCTURE para un archivo parseable con la forma equivocada, MAX_DEPTH_EXCEEDED e INPUT_TOO_LARGE para los límites, y MIXED_STRUCTURE para el caso de estilos mezclados de ngx-translate.
Un archivo de locale de árbol (la familia JSON, YAML y ARB) puede llevar una hoja que no es string, por ejemplo un valor count: 5 o enabled: true junto a las claves traducibles. verbatra los acepta: una hoja puede ser string, número, booleano o null, y solo una hoja de otro tipo, como un array, falla con INVALID_STRUCTURE. Una hoja no string queda excluida del conjunto traducible: nunca se traduce, se hashea, se incluye en el diff ni se comprueba por marcadores de posición o ICU. Excluir no es preservar: si verbatra luego escribe ese mismo archivo de locale, la escritura se reconstruye a partir de las cadenas que gestiona, así que una hoja no string presente al leer no se traslada a la salida. Si un valor así necesita sobrevivir a una reescritura, mantenlo fuera de los archivos en los que verbatra escribe. Los valores de trans-unit de XLIFF y los valores de .properties son siempre strings, así que esto no aplica ahí.
Por qué importa el formato
El formato le dice a verbatra dos cosas que necesita para una ejecución segura. Primero, la sintaxis de los marcadores de posición, para que la comprobación de integridad de marcadores de posición sepa qué comparar antes y después de la traducción. Segundo, para los formatos ICU, qué valores validar, para que una clave de origen con ICU inválido se omita en lugar de enviarse en un estado roto. El formato equivocado compara los tokens equivocados, así que hazlo coincidir con tu librería de i18n: i18next-json para i18next, vue-i18n-json para vue-i18n, next-intl-json para next-intl, ngx-translate-json para ngx-translate, xliff para archivos XLIFF, yaml para i18n basado en YAML, arb para Flutter y properties para archivos .properties de Java o Spring.