Formatos
Los doce 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 doce: cuatro variantes de JSON, más XLIFF, YAML, ARB, properties de Java/Spring, .strings de Apple, Xcode String Catalogs (.xcstrings), strings.xml de Android y .po/.pot de gettext.
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(. - Texto de llave simple en los formatos de doble llave. En
i18next-json,ngx-translate-jsonyyaml, un token con forma{name}es texto literal y no interpolación, así que no se extrae como marcador de posición y una traducción puede eliminarlo o reformularlo. Consulta la salvaguarda contra fabricaciones para la única dirección en la que sí se comprueba. - 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.
La salvaguarda contra fabricaciones de llave simple
Disponible a partir de 0.9.0
Bajo i18next-json, ngx-translate-json y yaml, un token con forma {name} que aparece en una traducción y nunca apareció en el origen se rechaza como fabricación. Eso cubre tanto un marcador de posición inventado de cero como uno alterado hasta un nombre que el origen nunca tuvo. La salvaguarda actúa solo en esa dirección: verbatra no tiene ningún ajuste para los interpolation.prefix e interpolation.suffix propios de i18next, así que si has cambiado a delimitadores de llave simple, una traducción que pierda en silencio uno de tus marcadores de posición no se detecta.
Diseños con namespaces
Repartir las cadenas entre varios archivos de namespace por locale es habitual en los proyectos i18next, con common.json, auth.json y demás uno al lado del otro dentro de un directorio de locale. Una configuración de verbatra direcciona exactamente un archivo por locale: files.pattern es una ruta literal con {locale} sustituido, nunca se expande como un glob, y no hay token de namespace. Un patrón como public/locales/{locale}/*.json se busca como un archivo llamado literalmente *.json y falla con SOURCE_UNREADABLE.
Un diseño de un solo namespace funciona tal cual se configura:
files: {
pattern: "public/locales/{locale}/common.json",
},Una configuración por namespace
Para un proyecto con varios namespaces, escribe una configuración por namespace y ejecuta verbatra una vez por configuración. Cualquier nombre de archivo sirve, ya que --config carga una ruta explícita por su extensión:
verbatra translate --config verbatra.common.config.ts
verbatra translate --config verbatra.auth.config.tsCada ejecución se ocupa de su propio namespace: las claves que faltan en un archivo de destino se traducen como siempre.
Solo el namespace que se ejecutó en último lugar conserva la detección de cambios
Todas las configuraciones del mismo directorio de trabajo comparten un único verbatra.lock.json, y cada ejecución de translate reemplaza la línea base registrada de ese locale con las claves que acaba de procesar. Tras la segunda ejecución, el primer namespace se queda sin línea base, así que editar una de sus cadenas de origen se informa como sincronizado en check y diff y no se vuelve a traducir. Cambiar el orden de las ejecuciones no ayuda; la que va última borra a la otra. Para volver a traducir una cadena editada con este montaje, borra esa clave del archivo de destino (o borra el archivo de destino entero) para que cuente como faltante en lugar de modificada.
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 reserva. 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, incluida la protección contra tokens de llave simple fabricados descrita más arriba, 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 finales de línea siguen al destino. Un archivo que contenga cualquier CRLF se reescribe entero con CRLF, un archivo solo con CR con CR, y todo lo demás, incluido un archivo que todavía no existe, con LF. Un archivo mixto converge por tanto en un único estilo en lugar de mantenerse línea a línea, y un
\ro un\ndentro de un valor se sigue escapando en vez de emitirse como un salto de línea. Esto mantiene un cambio de traducción de dos claves como un diff de dos líneas en los repositorios CRLF en los que suelen vivir estos archivos. - 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.
Apple .strings
Disponible a partir de 0.10.0
El formato apple-strings cubre los archivos .strings de Apple para iOS y macOS: una secuencia plana de sentencias "clave" = "valor";, detectada por la extensión .strings. Las reglas de plural viven en el archivo .stringsdict que lo acompaña (mismo directorio, mismo nombre base, extensión .stringsdict), que verbatra lee y escribe automáticamente junto con el archivo .strings, bajo el mismo id de formato apple-strings.
- La codificación es solo UTF-8.
genstringsde Xcode puede generar UTF-16 con una marca de orden de bytes. verbatra detecta una marca de orden de bytes UTF-16, little o big endian, y la rechaza conINVALID_STRUCTUREen lugar de interpretarla como claves corruptas e intercaladas con NUL. Vuelve a guardar el archivo como UTF-8 (Xcode lo hace de forma nativa) antes de ejecutar verbatra sobre él. - Comentarios y escapes. Un comentario de bloque
/* ... */situado justo antes de una entrada se lee como su descripción: llega al proveedor como contexto de desambiguación y aparece en la columnaContextde una hoja de cálculo exportada. Es de solo lectura y nunca se escribe de vuelta. Un comentario de línea//se conserva al escribir, pero no lleva descripción. Los escapes\",\\,\n,\ty el escape unicode\Ude cuatro dígitos hexadecimales se decodifican al leer; al escribir se escapan las comillas, la barra invertida, el salto de línea y el tabulador, y cualquier otro carácter, incluido el texto no ASCII, se escribe como UTF-8 sin escapar. - Destino inexistente. A diferencia de XLIFF, un destino
.stringsque todavía no existe se sintetiza a partir de las entradas en lugar de hacer fallar la escritura, igual que el formato properties. - Se conservan el orden, los comentarios y las líneas en blanco. Una escritura vuelve a leer el destino y lo reconstruye a partir de esa estructura: cada clave existente se reescribe en su sitio con su nuevo valor, una clave que el destino aún no tiene se añade en el orden del origen, y una clave eliminada de las entradas se elimina del destino junto con su propio comentario precedente.
- Los marcadores de posición son de estilo printf.
%@,%d,%1$@y el literal escapado%%se extraen y se protegen durante la traducción; las banderas, el ancho, la precisión y los modificadores de longitud (%05.2f,%ld) se tratan como decoración y no forman parte de la identidad del token. Un reordenamiento posicional como%1$@ %2$@convirtiéndose en%2$@ %1$@se acepta, ya que ese es precisamente el propósito de los especificadores posicionales. Un%suelto seguido de texto corriente, como en"50% off", no extrae nada. - Los plurales viven en el
.stringsdictque lo acompaña.Localizable.stringsforma pareja conLocalizable.stringsdicten el mismo directorio; verbatra lo descubre automáticamente y fusiona sus categorías de plural en el mismo recurso de locale, así que traducir sigue apuntando a un únicofiles.patternpor locale. Cada categoría CLDR presente en una entrada (zero,one,two,few,many,other) se convierte en su propia entrada traducible, con el mismo sufijo<clave>_<categoría>que ya usai18next-json, por ejemplophoto_count_oneyphoto_count_other. Un locale que solo aporta algunas categorías, el caso habitual ya que la mayoría de idiomas solo necesitaoneyother, hace el ciclo completo con exactamente esas: no se inventa ninguna para un destino y no se descarta ninguna de la fuente. Los marcadores de posición printf dentro de la cadena de formato de una categoría, como%den"%d photos", se extraen y se protegen igual que en los valores.strings. Un.stringsdictmal formado (XML inválido, una sustitución%#@variable@que falta, o una categoría de plural no soportada) lanza un error estructurado que nombra el archivo y la clave. Un destino.stringsdictque todavía no existe se crea igual que un destino.strings, directorio.lprojincluido, y su estructura no traducible (la clave de formato, el nombre de la variable de sustitución y el tipo de valor) se conserva al volver a escribirlo. - Un archivo por locale,
.lprojincluido.files.patterncon{locale}.lproj/Localizable.stringsdirecciona directamente el diseño de paquete por locale de Apple:{locale}es una sustitución literal de token, así que no necesita un estilo de locale propio, y una escritura crea un directorio{locale}.lprojque falte igual que crea cualquier otro directorio de destino que falte.
Xcode String Catalogs (.xcstrings)
Disponible a partir de 0.10.0
El formato apple-xcstrings cubre los archivos String Catalog de Xcode, .xcstrings, introducidos en Xcode 15 para reemplazar el par .strings/.stringsdict en proyectos nuevos: un único documento JSON que contiene los strings, los plurales y el estado de traducción de todos los locales juntos, detectado por la extensión .xcstrings. Esto es estructuralmente distinto de cualquier otro formato que soporta verbatra, que usan un archivo por locale: un catálogo apple-xcstrings es un archivo para todos los locales a la vez.
- Un catálogo compartido, no un archivo por locale.
files.patternsigue necesitando el token{locale}, pero para este formato se resuelve a la misma ruta sin importar qué locale se sustituya; por ejemplo,{locale}Localizable.xcstringsdirecciona un único archivoLocalizable.xcstrings. El locale de origen y cada locale de destino configurado comparten así un archivo físico. - Las escrituras en un catálogo compartido se serializan. Como la escritura de cada locale toca el mismo archivo, verbatra serializa entre sí toda operación que pueda escribirlo:
translate, una edición en Studio, la retraducción de una sola clave y la importación de la hoja de cálculo. En la práctica, esto significa que un proyectoapple-xcstringsejecuta esas operaciones de una en una aunque--concurrencyesté por encima de 1; cualquier otro formato sigue ejecutando sus llamadas al proveedor en paralelo según lo configurado. - La clave es el string de origen. Una clave del catálogo sin una entrada
localizationsexplícita para elsourceLanguagedeclarado en el propio documento recurre al texto de la clave, siguiendo la propia convención de Xcode. Una clave sin entrada para cualquier otro locale simplemente se trata como aún no traducida para ese locale, igual que una clave ausente en el archivo de destino de cualquier otro formato. - Los plurales viven en
variations.plural. Cada categoría CLDR (zero,one,two,few,many,other) presente bajovariations.pluralde un locale se convierte en su propia entrada traducible, con el mismo sufijo<clave>_<categoría>que usani18next-jsony el soporte de.stringsdictdel formato.stringsde Apple, por ejemplo%lld photos_oney%lld photos_other. Un locale que solo aporta algunas categorías hace el ciclo completo con exactamente esas: ninguna se inventa y ninguna se descarta. - Los marcadores de posición son de estilo printf.
%@,%d,%1$@,%lldy el literal escapado%%se extraen y se protegen durante la traducción igual que en los valores.stringsde Apple; un modificador de longitud como elllde%lldes decoración y no forma parte de la identidad del token, así que%lldy%dson el mismo marcador de posición. shouldTranslate: falsese respeta. Una clave marcada así nunca se envía a un proveedor y nunca se reescribe modificada.- Las escrituras parchean el documento, no lo reconstruyen. Una escritura vuelve a leer el catálogo actual y solo actualiza las localizations que toca, así que
extractionState, cualquier otro locale, las entradas no traducibles, las categorías de plural, laversionde nivel superior del catálogo y susourceLanguagepermanecen intactos. Un valor que verbatra acaba de traducir recibestringUnit.state: "translated"; la localization existente de un valor sin cambios, estado incluido, se deja idéntica byte a byte en lugar de reescribirse. - El catálogo de destino ya debe existir. A diferencia de
.stringso.properties, verbatra no crea un nuevo catálogo.xcstrings: créalo primero en Xcode y luego apuntafiles.patternhacia él. - La entrada mal formada es específica. Un
AdapterErrorestructurado nombra el archivo y, cuando el problema está dentro de una entrada, también la clave y el locale, por ejemplo una entrada sin campostringUnitnivariations.plural, o una categoría de plural fuera del conjunto CLDR.
Android strings.xml
Disponible a partir de 0.10.0
El formato android-xml cubre los archivos de recursos de Android, res/values/strings.xml para el locale de origen y res/values-<calificador>/strings.xml para cada destino, detectado por la extensión .xml. Configura files.localeStyle en android (mira el archivo de configuración) para que {locale} en files.pattern se resuelva al directorio de calificador de recursos correcto en lugar de a una etiqueta BCP-47 literal.
<string>y<plurals>. Un<string name="key">value</string>es una entrada. Un<plurals name="key">se convierte en una entrada por cada<item quantity="...">(zero,one,two,few,many,other), con la clavekey[quantity], por ejemplocount[one]ycount[other]. Un locale que solo aporta algunas categorías redondea con exactamente esas: ninguna se inventa y ninguna se descarta. Cadanamede recurso se valida contra la gramática de identificadores de Android (una letra o guion bajo, luego letras, dígitos o guiones bajos) antes de convertirse en clave, así que un nombre no puede falsificar una colisión con forma de[quantity]en el espacio real de claves de plural.translatable="false"se respeta. Un<string>o<plurals>con este atributo nunca se envía a un proveedor y queda intacto en el disco.formatted="false"se traduce con normalidad. El atributo solo le dice a las herramientas de compilación propias de Android que no valide argumentos printf; no cambia lo que hace verbatra. Los marcadores de posición al estilo%s/%dse siguen extrayendo y protegiendo durante la traducción igual que siempre.<string-array>y el marcado en línea se dejan pasar tal cual en esta versión. Un<string-array>y un<string>cuyo contenido no es texto plano (un elemento en línea como<b>,<xliff:g>o una secciónCDATA) se conservan exactamente como están y nunca entran en el conjunto traducible de verbatra. La traducción a nivel de elemento para estos es una posible ampliación futura, no algo soportado hoy.- El escapado se decodifica al leer y se vuelve a codificar al escribir.
\',\",\n,\ty un\@o\?inicial se decodifican a sus caracteres literales al leer, y esos mismos caracteres (más un@o?inicial sin escapar) se vuelven a escapar al escribir; las entidades propias de XML&,<y>las gestiona de forma independiente la capa XML subyacente, así que un valor traducido con cualquiera de estos caracteres se escribe de vuelta de forma segura sin que tengas que escaparlo tú mismo. - Los marcadores de posición son al estilo printf.
%s,%d,%1$sy el literal escapado%%se extraen y protegen durante la traducción. Un%suelto seguido de texto ordinario, como en"50% off", no extrae nada: el extractor no trata un espacio como un flag de conversión válido, a diferencia del propioString.formatde Java, así que un signo de porcentaje en prosa normal nunca se confunde con un marcador de posición. - Las escrituras actualizan los destinos en el sitio; un destino ausente se sintetiza. Un
res/values-<calificador>/strings.xmlexistente se parchea: una clave traducida se actualiza, una clave eliminada del origen se borra, y el directorio padre se crea si aún no existe. Un destino que todavía no existe se crea desde cero, directoriores/values-<calificador>/incluido. - Limitación: una clave degradada a solo lectura tras traducirse se elimina, no se preserva. Si una clave ya estaba traducida en un archivo de destino y luego, en el archivo de origen, gana
translatable="false"o marcado en línea, la siguiente ejecución no puede distinguir eso de que la clave se haya eliminado directamente, y quita la traducción obsoleta del archivo de destino. Esto es un caso acotado (solo afecta a una clave cuya clasificación de origen cambia después de haber sido traducida) y recuperable mediante el control de versiones o una nueva ejecución de traducción; no afecta a una clave que mantiene su clasificación original, incluidas las claves nuevas, cambiadas y eliminadas normales. - Limitación:
--pruneno tiene conciencia de la cantidad plural. La detección de claves huérfanas y--prunede verbatra compara claves contra el propio conjunto de claves del origen, sin caso especial para los gruposkey[quantity]. Una locale de destino que necesita más cantidades plurales que las que declara el origen (por ejemplo, un idioma con más distinciones gramaticales de número) tiene cantidades que solo existen en el destino, que una ejecución con--pruneno puede distinguir de una clave realmente eliminada, y puede borrarlas. Desactivado por defecto; una ejecución normal deverbatra translatesin--pruneno se ve afectada. - Las entradas mal formadas son específicas. Un XML mal formado genera un
AdapterErrorestructurado que nombra el problema; un documento cuyo elemento raíz no es<resources>, un nombre de recurso que no cumple la gramática de identificadores, un elemento<plurals>con una cantidad fuera del conjunto CLDR, o dos elementos que resuelven a la misma clave se reportan todos por su nombre en lugar de como un fallo de análisis genérico. Una declaración DTD o ENTITY se rechaza de plano.
gettext .po/.pot
Disponible a partir de 0.10.0
El formato gettext-po cubre los catálogos .po y .pot de GNU gettext, detectados por cualquiera de las dos extensiones: una secuencia plana de entradas msgid/msgstr, con clave por su msgid, nunca dividida en un árbol.
- Desambiguación con
msgctxt. Unmsgctxtantes de una entrada se combina con sumsgiden una sola clave, de modo que dos entradas que comparten unmsgidbajo contextos distintos nunca colisionan. La clave compuesta usa un punto de código de uso privado reservado (U+E000) como separador interno, un carácter que ningún archivo.poreal contiene legítimamente; una cadena de origen que sí lo contenga se rechaza con un error estructurado en lugar de corromper la clave en silencio. - Los plurales son
msgid_plural/msgstr[n], con clave por índice, no por categoría CLDR. Cadamsgstr[n]se convierte en su propia entrada, con la clavekey[n](nel índice decimal tal cual), por ejemploone item[0]yone item[1]. Esto es deliberadamente distinto del sufijo<key>_<category>que usan los formatos JSON y el.stringsdictde Apple: traducir un índice de gettext a una categoría CLDR requeriría evaluar la expresión CPlural-Formspropia del archivo, algo que verbatra no hace. La cabeceraPlural-Formsse conserva literalmente como texto intacto; verbatra solo lee de ahí el enteronplurals=N, para comprobar que cada índicemsgstr[n]esté dentro de rango. Un archivo con entradas plurales y sin cabeceraPlural-Formsse rechaza, igual que exigemsgfmt --check. - Las entradas
fuzzyse leen, no se omiten. Elmsgstrexistente de una entrada#, fuzzyse lee como el valor actual de esa entrada, igual que cualquier otra entrada traducida; verbatra no tratafuzzycomo si estuviera pendiente. La marca se conserva literalmente en cada escritura y nunca se añade ni se elimina automáticamente. - Los comentarios y la cabecera se conservan intactos. Los comentarios de desarrollador
#.se convierten en la descripción de la entrada: llegan al proveedor como contexto de desambiguación y aparecen en la columnaContextode una hoja de cálculo exportada. Las referencias#:y otras marcas#,se conservan al escribir pero no se interpretan de ningún otro modo. Un bloque obsoleto#~se conserva como texto inerte y nunca se convierte en una entrada traducible. La entrada de cabecera (el bloquemsgid ""que llevaContent-Type,Plural-Formsy metadatos similares) nunca se toca al escribir. - Las plantillas
.potse leen sin problemas. Una plantilla de origen.pot, cuyas entradas llevan unmsgstrvacío, se lee sin error; el valor de cada entrada es simplemente la cadena vacía hasta que se traduce. - Destino inexistente. Igual que los formatos properties y Apple
.strings, un destino.poque todavía no existe se sintetiza a partir de las entradas en lugar de fallar la escritura, incluyendo una cabecera mínima. Un archivo sintetizado con entradas plurales recibe una cabeceraPlural-Formsdimensionada al índice más alto presente; para una o dos formas es la expresión universal estándar, para tres o más es un valor de respaldo seguro dentro de rango en lugar de una regla lingüística adivinada, posiblemente incorrecta; siembra primero el destino desde una plantilla real del idioma de destino si necesitas la gramática exacta. - Los marcadores de posición son de estilo printf, incluida la forma con nombre de Python.
%s,%d,%1$s, el%(name)sal estilo Python y el literal escapado%%se extraen y se protegen durante la traducción. - Las entradas mal formadas son específicas. Un
AdapterErrorestructurado nombra elmsgiden cuestión y la línea física, por ejemplo una cadena entre comillas sin terminar, una secuencia de escape desconocida, un índicemsgstr[n]no contiguo o una entrada plural sin cabeceraPlural-Forms, en lugar de un fallo de análisis genérico. - Limitación:
--pruneno tiene conciencia del índice plural. La detección de claves huérfanas y--prunede verbatra compara claves contra el propio conjunto de claves del origen, sin caso especial para los gruposkey[n]. Una locale de destino que necesita más formas plurales que las que declara el origen (por ejemplo, un idioma con más distinciones gramaticales de número) tiene índices que solo existen en el destino, que una ejecución con--pruneno puede distinguir de una clave realmente eliminada, y puede borrarlos. Desactivado por defecto; una ejecución normal deverbatra translatesin--pruneno se ve afectada.
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, properties para archivos .properties de Java o Spring, apple-strings para archivos .strings de Apple, apple-xcstrings para archivos .xcstrings de Xcode String Catalog, android-xml para strings.xml de Android, y gettext-po para catálogos .po/.pot de gettext.
Proveedores
Los seis proveedores de traducción, sus opciones y claves de API, y el comportamiento que todos comparten.
Estimar el coste
Dimensiona una ejecución de traducción antes de gastar: cuenta las claves con una ejecución en seco, conviértelas en peticiones y tokens, y ponles precio con las tarifas de tu proveedor.