Referencia / CLI
Página traducida automáticamente
verbatra types
Genera declaraciones de TypeScript para las claves de tu catálogo y los argumentos de sus mensajes, sin llamar a un proveedor ni leer una clave de API.
Convierte una clave mal escrita o un argumento de interpolación olvidado en un error de compilación. types lee tu catálogo de origen a través del adaptador de formato configurado y escribe un archivo de declaraciones: una unión de todas las claves y, por clave, los argumentos que toma su mensaje. No llama a ningún proveedor, no lee ninguna clave de API y nunca toca un archivo de locale de destino.
Sinopsis
verbatra types [flags]Ejemplos
# write verbatra-types.d.ts from the source catalog
verbatra types
# write it where the app already imports from
verbatra types --out src/generated/messages.d.ts
# CI gate: exit 1 if the committed declaration is stale
verbatra types --check
# machine-readable result for a script
verbatra types --jsonFlags
| Flag | Argumento | Por defecto | Efecto |
|---|---|---|---|
--out | <path> | verbatra-types.d.ts | dónde escribir la declaración, relativo al directorio de trabajo y dentro de la raíz del proyecto; los directorios que falten se crean |
--check | ninguno | desactivado | compara byte a byte la declaración confirmada con una generación nueva, sin escribir nada; sale con 1 si está obsoleta o falta |
También acepta los flags globales --cwd, --config y --json.
Comportamiento
Qué genera
A partir de un locales/en.json como este:
{
"app": { "title": "Verbatra" },
"greeting": "Hello {{name}}",
"cart": { "item_one": "{{count}} item", "item_other": "{{count}} items" }
}obtienes esto:
// Generated by verbatra from locales/en.json (i18next-json). Do not edit by hand.
// Re-run `verbatra types` after the source catalog changes.
/** An argument whose type the source catalog does not record. */
export type VerbatraArgument = string | number;
/** The arguments of a message that takes none: passing any argument is a type error. */
export type VerbatraNoArguments = Record<string, never>;
/**
* The arguments of a message verbatra could not analyse, so nothing is claimed about them.
* Every key carrying this type is listed by `verbatra types` when it generates this file.
*/
export type VerbatraUnknownArguments = Record<string, VerbatraArgument>;
/** Every key in the source catalog, mapped to the arguments its message takes. */
export interface VerbatraMessages {
"app.title": VerbatraNoArguments;
"greeting": { readonly "name": VerbatraArgument };
"cart.item": { readonly "count": VerbatraArgument };
"cart.item_one": { readonly "count": VerbatraArgument };
"cart.item_other": { readonly "count": VerbatraArgument };
}
/** Every key in the source catalog. */
export type VerbatraMessageKey = keyof VerbatraMessages;
/** The arguments the message at `Key` takes. */
export type VerbatraMessageArguments<Key extends VerbatraMessageKey> =
VerbatraMessages[Key];
/** The keys the source catalog marks as carrying plural forms. */
export type VerbatraPluralMessageKey = "cart.item_one" | "cart.item_other";Tipa tu propia función de traducción con ella y el compilador hace el resto:
import type { VerbatraMessageArguments, VerbatraMessageKey } from "./verbatra-types.js";
declare function t<Key extends VerbatraMessageKey>(
key: Key,
args: VerbatraMessageArguments<Key>,
): string;
t("greeting", { name: "Ada" }); // fine
t("greting", { name: "Ada" }); // error: not a key in the catalog
t("greeting", {}); // error: the name argument is required
t("app.title", { name: "Ada" }); // error: this message takes no argumentQué afirma y qué no
Las claves son exactamente las que produjo el adaptador de formato, en el orden del documento, así que el mismo catálogo produce siempre los mismos bytes. Los argumentos vienen de los tokens de placeholder que extrajo el adaptador; los mensajes de next-intl-json y arb se leen con el analizador ICU del adaptador, así que también se declara un argumento que solo usan algunas ramas. No se adivina nada, y nada se declara como any.
| Tu mensaje | Qué se declara |
|---|---|
| sin placeholders | VerbatraNoArguments, así que pasar cualquier cosa es un error de tipo |
placeholders con nombre ({{name}}, {name}, %(name)s) | una forma de objeto con esos nombres |
placeholders numerados o anónimos ({0}, %@, %1$d) | una tupla readonly, una posición por argumento |
un argumento que solo usan algunas ramas select o plural (next-intl-json, arb) | un miembro opcional, name?:, o una posición opcional al final de la tupla ([number, VerbatraArgument?]); uno que usan todas las ramas sigue siendo obligatorio |
un argumento ICU number, plural o selectordinal en next-intl-json o arb | number |
un argumento ICU date o time ({d, date, short}) en next-intl-json o arb | Date | number |
un argumento ICU select ({gender, select, ...}) en next-intl-json o arb | string |
un formateador number de i18next ({{count, number}}) en i18next-json, ngx-translate-json o yaml | number |
un formateador datetime de i18next ({{d, datetime}}) en esos mismos tres formatos | Date | number |
una interpolación sin escapar de i18next ({{- name}}) | el nombre detrás del prefijo, name |
un argumento MessageFormat number, plural o choice ({0,number}) en properties | number |
una conversión printf numérica (%d, %1$d) | number |
una conversión printf de cadena (%s, %(name)s) | string |
cualquier otro placeholder, incluido un argumento ICU simple ({name}) | VerbatraArgument, un alias de string | number |
sintaxis de mensaje inválida, que solo comprueban next-intl-json y arb | VerbatraUnknownArguments, y la clave se nombra en la salida |
| un mensaje que mezcla argumentos con nombre, numerados y anónimos | VerbatraUnknownArguments, y la clave se nombra en la salida |
un argumento numerado por debajo de la posición 0 o a partir de la posición 64 (%0$s, {64}) | VerbatraUnknownArguments, y la clave se nombra en la salida |
Un formato cuyos placeholders no llevan nombre (Apple .strings, Android strings.xml, conversiones posicionales de gettext) recibe una tupla, nunca nombres inventados. Un nombre que aparece con tipos distintos recibe su unión: {d, date, short} junto a un {d} simple pasa a ser Date | number | string. Las claves son siempre literales de cadena entrecomillados, así que una clave con un punto, una palabra reservada, un dígito inicial o una comilla se declara tal cual. Una clave que el adaptador excluyó de la traducción (una hoja que no es una cadena, un recurso de Android con translatable="false") nunca se declara y se nombra en la salida.
Una clave cuyo propio nombre contiene un punto
La clave declarada se escribe como verbatra la escribe en verbatra.lock.json, no en una sintaxis de búsqueda que entienda tu biblioteca de i18n. Un catálogo JSON con {"a.b": "..."} lleva la clave a\.b, deliberadamente distinta de la ruta anidada a.b:
export interface VerbatraMessages {
"a\\.b": VerbatraNoArguments;
}i18next no tiene escape para su separador de claves, así que t("a\\.b") no busca esa clave. Si tu catálogo lleva claves así, pon keySeparator en otro carácter (o en false para un catálogo plano) y asigna la clave declarada a la clave del runtime en tu propio wrapper tipado.
El único caso en que la declaración se equivoca en lugar de solo callar
Solo next-intl-json y arb validan la sintaxis de mensaje. En cualquier otro formato, un valor roto como "Hello {name" no produce ningún token de placeholder, así que el mensaje se declara sin argumentos y pasarle el argumento que de verdad necesita es un error de compilación. Nada lo informa, porque nada lo detectó. Arregla el catálogo, no la declaración.
Claves con plural
No se agrupa nada. i18next lleva el plural como sufijo de clave, así que cart.item_ y cart.item_ se declaran tal como están escritas y, junto a ellas, la clave base cart.item que busca t("cart.item", { count }), que exige count y todos los argumentos que toma alguna de las formas. Los tipos propios de i18next también aceptan ambas formas de escribirla. Un grupo ordinal como place_ declara place, y una clave base que el catálogo ya contiene conserva su propia declaración. VerbatraPluralMessageKey lista las claves que el adaptador marcó como portadoras de formas plurales, las que llevan sufijo, para que puedas acotarte a ellas.
Dónde va la declaración
Por defecto acaba en verbatra-types.d.ts en la raíz de tu proyecto. Haz commit de ella: un compañero o un job de CI comprueba los tipos contra ella sin ejecutar verbatra, y --check necesita un archivo confirmado con el que comparar. Nada la añade a .gitignore.
Una ruta de salida se rechaza con TYPES_ cuando:
- no nombra ningún archivo, también cuando termina en un separador de ruta como
generated/(un--outvacío falla antes, conINVALID_),OUT - es absoluta,
- se sale de la raíz del proyecto con
.., - no es un archivo TypeScript, es decir, su nombre no termina en
.ts,.mtso.cts, - nombra un archivo de locale configurado, de origen o de destino, para que la generación nunca sobrescriba un catálogo,
- es el archivo de bloqueo,
verbatra.lock.json, - es el archivo de procedencia,
verbatra.provenance.json, - es la caché de memoria de traducción,
verbatra.cache.json, - es un archivo donde verbatra busca su configuración:
package.json,.verbatrarc,.verbatrarc.json,.verbatrarc.yaml,.verbatrarc.yml,.verbatrarc.js,.verbatrarc.cjs,.verbatrarc.ts,verbatra.config.js,verbatra.config.cjsoverbatra.config.ts, - es el archivo de configuración que la ejecución cargó de verdad, incluido uno que indicaste con
--config, - es el archivo de glosario al que apunta
glossaryen tu configuración, - es un archivo existente que no empieza con la línea de cabecera
// Generated by verbatra fromque verbatra escribe al principio de cada declaración (se ignoran una marca de orden de bytes y líneas en blanco al inicio), o es demasiado grande para comprobarlo.
Los nombres de archivo se comparan sin distinguir mayúsculas de minúsculas, y las comprobaciones se repiten una vez resueltos los enlaces simbólicos, así que un directorio enlazado no puede llevar la declaración fuera de la raíz del proyecto ni sobre un archivo protegido. La última comprobación solo se hace cuando una ejecución fuera a escribir, y deja tu archivo intacto; --check nunca rechaza un archivo existente. Una ruta que supera todas las comprobaciones aún puede fallar al escribir (un directorio de solo lectura, un disco lleno): la ejecución se detiene con TYPES_ y nombra el archivo y el código del sistema de archivos, como EACCES.
Mantenerlo honesto en CI
Ejecuta types --check junto a verbatra check en el mismo job: check detecta locales que se quedan atrás respecto a la fuente, types --check tus tipos. La comparación es byte a byte y la declaración se escribe siempre con finales de línea line feed, así que fija los finales en .gitattributes, o un checkout que los reescriba deja el archivo desactualizado para siempre:
verbatra-types.d.ts text eol=lfSalida JSON
Esquema: types-envelope.json valida el envoltorio completo; Esquemas enumera los demás.
Con --json, el envoltorio lleva un resultado:
interface GenerateTypesResult {
path: string; // absolute path of the declaration file
sourcePath: string; // the source catalog, relative to the project root
keys: number; // how many keys are declared
withArguments: number; // keys taking at least one determined argument
unresolved: { key: string; reason: "invalid-message-syntax" | "mixed-argument-styles" | "argument-index-out-of-range" }[];
excluded: string[]; // keys the adapter excluded, never declared
plural: string[]; // keys carrying plural forms
written: boolean; // false under --check and when the file already matched
stale: boolean; // the file on disk differed when the run started
missing: boolean; // no file existed when the run started
check: boolean; // whether this was a --check run
}Información en el terminal
El resumen va a stdout; una línea de spinner y, tras escribir, una sugerencia para hacer commit del archivo van a stderr (--check no sugiere nada, y --quiet omite ambas). Una ejecución que genera, una repetición sin cambios y un --check obsoleto:
verbatra: generating the declarations... done (0.2s)
verbatra types
214 keys declared, 63 of them taking arguments, from locales/en.json
arguments not determined (1):
legal.notice invalid-message-syntax
excluded by the adapter (1): meta.version
wrote verbatra-types.d.ts
next: commit verbatra-types.d.ts (verbatra types --check compares against it in CI)
verbatra types
214 keys declared, 63 of them taking arguments, from locales/en.json
unchanged verbatra-types.d.ts
verbatra types
215 keys declared, 63 of them taking arguments, from locales/en.json
verbatra-types.d.ts is out of date, re-run verbatra typesConsulta Salida en el terminal para el color, el spinner y las variables que los controlan.
Códigos de salida
| Código | Significado |
|---|---|
0 | la declaración se generó, haya cambiado el archivo o no; o --check la encontró vigente |
1 | --check encontró obsoleta o ausente la declaración confirmada (is missing, run verbatra types to create it) |
2 | no se pudo ejecutar: un error de uso, un problema de configuración o de la fuente, una ruta de salida rechazada (TYPES_) o una declaración que no se pudo escribir (TYPES_) |
Consulta Códigos de salida para el contrato que sigue cada comando.
Relacionado
verbatra extractañade al catálogo las claves que usa tu código;typeslas declara después.verbatra checkes la puerta de CI para el desfase de locales, junto a esta para el desfase de tipos.- Formatos lista la sintaxis de placeholders de cada formato.
- Códigos de salida y salida JSON cubre el envoltorio y el contrato de códigos de salida.