---
title: "Archivo de configuración"
description: "Cada clave de configuración con su tipo, su valor por defecto y la versión que la añadió, más dónde puede vivir el archivo y cómo falla una configuración mala."
type: "reference"
---
# Archivo de configuración

Cada clave de configuración con su tipo, su valor por defecto y la versión que la añadió, más dónde puede vivir el archivo y cómo falla una configuración mala.

verbatra lee un único objeto de configuración sin secretos y lo valida antes de cualquier trabajo. Ninguna clave de API se lee jamás de él ([Proveedores](https://verbatra.kreitz-webdev.de/es/docs/providers.md#las-claves-vienen-del-entorno)), así que la configuración se puede confirmar sin riesgo.

## Una configuración mínima [#una-configuración-mínima]

```ts title="verbatra.config.ts"
import { defineConfig } from "@verbatra/cli";

export default defineConfig({
  // Locales and files: required
  sourceLocale: "en",
  targetLocales: ["de", "fr"],
  format: "i18next-json",
  files: {
    // {locale} is the only token
    pattern: "locales/{locale}.json",
  },

  // Provider: required; the API key comes from the environment, never from here
  provider: {
    id: "gemini",
    options: {
      // example model id; use your provider's current one
      model: "gemini-2.5-flash",
      maxOutputTokens: 4096,
    },
  },

  // Optional groups, each off or at its default until you add it:
  // tone: "informal",
  // glossary: "glossary.json",
  // network: { policy: "local-only" },
  // sensitiveData: { mode: "warn" },
  // maxTokens: 200000,
  // budgetBehavior: "stop",
});
```

Mira [locales y archivos](#locales-y-archivos), [provider](#provider), [glossary](#glossary), [network](#network), [contenido sensible](https://verbatra.kreitz-webdev.de/es/docs/data-handling.md#protección-de-contenido-sensible), [presupuesto](#maxtokens-y-budgetbehavior), [rates](#rates) y [extract](#extract).

`defineConfig` solo da tipos a su argumento: `options.model` autocompleta con los IDs de modelo del proveedor, aunque en tiempo de ejecución vale cualquier cadena no vacía.

## Cada clave [#cada-clave]

Las claves desconocidas se rechazan en todos los niveles salvo `$schema` y los mapas cuyas claves nombras tú, como `maxLength`, `rates.table`, `localeMap` y un `glossary` en línea, así que una clave de API no puede vivir en la configuración.

| Clave | Tipo | Por defecto | Desde | Efecto |
| --- | --- | --- | --- | --- |
| `$schema` | string | ninguno | 0.9.0 | Apunta un editor al [JSON Schema](#validación-en-el-editor); se ignora en tiempo de ejecución. |
| `sourceLocale` | código de locale | obligatoria | 0.1.0 | El locale en el que están escritas tus cadenas de origen. |
| `targetLocales` | array de códigos de locale | obligatoria | 0.1.0 | Al menos uno; nunca `sourceLocale`, nunca dos iguales sin distinguir mayúsculas. |
| `format` | id de formato | obligatoria | 0.1.0 | El [formato](https://verbatra.kreitz-webdev.de/es/docs/formats.md) de tus archivos de locale, o un id `custom:` para un [adaptador externo](https://verbatra.kreitz-webdev.de/es/docs/custom-format-adapters.md). |
| `files.pattern` | string | obligatoria | 0.1.0 | La ruta de cada archivo de locale, con un token `{locale}`. |
| `files.localeStyle` | `"literal"`, `"posix"`, `"android"` | `"literal"` | 0.7.0 | Cómo se escribe `{locale}` en la ruta. |
| `provider.id` | id de proveedor | obligatoria | 0.1.0 | El proveedor de traducción, o `none` para no usar traducción automática. |
| `provider.options` | objeto | obligatoria, salvo con `none` | 0.1.0 | Las [opciones propias](https://verbatra.kreitz-webdev.de/es/docs/providers.md) del proveedor. |
| `glossary` | objeto o ruta de archivo | ninguno | 0.1.0 | Traducciones fijas, traducciones prohibidas y términos que no se traducen. |
| `tone` | `"formal"`, `"informal"`, `"neutral"` | ninguno | 0.1.0 | El registro en el que traducir, aplicado [por proveedor](https://verbatra.kreitz-webdev.de/es/docs/providers.md#tono-y-glosario-entre-proveedores). |
| `prune` | boolean | `false` | 0.3.0 | Elimina las claves huérfanas de los archivos de destino y del bloqueo; `translate --prune` tiene prioridad. |
| `generatePlurals` | boolean | `false` | 0.3.0 | Sintetiza las formas plurales CLDR que necesita un idioma de destino. |
| `fuzzyCache.enabled` | boolean | obligatoria en el bloque | 0.11.0 | Reutiliza la traducción de un origen poco cambiado. |
| `fuzzyCache.threshold` | número, de `0.5` a `1` | `0.9` | 0.11.0 | Cuánto deben parecerse origen antiguo y nuevo. |
| `humanEdits` | `"protect"`, `"suggest"`, `"overwrite"` | `"protect"` | 0.12.0 | Qué hace una ejecución con una clave obsoleta que escribió una persona. |
| `pinnedKeys` | array de strings | ninguno | 0.12.0 | Patrones de claves (`*` como comodín) que ninguna escritura automática toca. |
| `network.policy` | `"any"`, `"local-only"`, `"allowlist"` | `"any"` | 0.12.0 | A qué hosts puede [conectarse](https://verbatra.kreitz-webdev.de/es/docs/network-policy.md) un proveedor. |
| `network.allowedHosts` | array de strings | ninguno; obligatoria con `"allowlist"` | 0.12.0 | Hosts permitidos adicionales: nombres, comodines `*.suffix`, IPs o rangos CIDR. |
| `sensitiveData.mode` | `"off"`, `"warn"`, `"block"`, `"redact"` | obligatorio en el bloque; `"off"` sin el bloque | 0.12.0 | Qué hace una ejecución con el [contenido sensible](https://verbatra.kreitz-webdev.de/es/docs/data-handling.md#protección-de-contenido-sensible) antes de enviarlo. |
| `sensitiveData.detectors` | array de IDs de detector | `secret`, `email`, `iban`, `credit-card` | 0.12.0 | Detectores activos; `phone`, `ip`, `private-host` son opcionales. |
| `sensitiveData.patterns` | array de strings | ninguno | 0.12.0 | Expresiones regulares para tus propios términos, como nombres en clave. |
| `sensitiveData.allow` | array de strings | ninguno | 0.12.0 | Coincidencias que nunca se informan; `*` es un comodín y no distingue mayúsculas. |
| `maxBatchSize` | entero positivo | `50` | 0.3.0 | El máximo de entradas por petición al proveedor. |
| `maxLength` | mapa de clave a entero positivo | ninguno | 0.11.0 | Presupuestos de longitud por clave, en clústeres de grafemas. |
| `maxTokens` | entero positivo | ninguno | 0.5.0 | Un presupuesto de tokens para toda la ejecución. |
| `budgetBehavior` | `"warn"`, `"stop"` | `"warn"` | 0.5.0 | Si alcanzar `maxTokens` avisa o detiene el envío. |
| `rates.asOf` | fecha `YYYY-MM-DD` | obligatoria en el bloque | 0.11.0 | La fecha en que leíste las tarifas. |
| `rates.currency` | tres letras mayúsculas | obligatoria en el bloque | 0.11.0 | La moneda de todas las tarifas, como `USD`. |
| `rates.table` | mapa de clave de tarifa a tarifa | obligatoria en el bloque | 0.11.0 | Tarifas por [clave de tarifa](#rates). |
| `extract.framework` | `"i18next"` | obligatoria en el bloque | 0.11.0 | Qué llamadas busca el análisis del código fuente. |
| `extract.roots` | array de strings | obligatoria en el bloque | 0.11.0 | Los directorios que se analizan, al menos uno. |
| `extract.exclude` | array de strings | ninguno | 0.11.0 | Nombres de directorio extra que se omiten. |
| `extract.literals.ignore` | array de strings | ninguno | 0.11.0 | Textos exactos que `doctor --literals` retiene. |
| `extract.unused.ignore` | array de strings | ninguno | 0.11.0 | Claves o patrones `*` que `diff --unused` nunca señala. |

### Locales y archivos [#locales-y-archivos]

- **`files.pattern`** debe contener `{locale}`, su único token, y se resuelve contra la raíz del proyecto: `locales/{locale}.json` pasa a `locales/de.json`. Es una ruta literal, nunca un glob, así que una configuración direcciona un archivo por locale ([Diseños con namespaces](https://verbatra.kreitz-webdev.de/es/docs/formats.md#diseños-con-namespaces)); `apple-xcstrings` resuelve todos los locales al mismo catálogo ([Xcode String Catalogs](https://verbatra.kreitz-webdev.de/es/docs/formats.md#xcode-string-catalogs-xcstrings)).
- **`files.localeStyle`** decide en qué se expande el token:
  - `literal` escribe la etiqueta tal como está configurada, como necesitan la mayoría de diseños.
  - `posix` reemplaza `-` por `_` para gettext y el diseño Java `messages_{locale}.properties` (`pt-BR` pasa a `pt_BR`); una variante como `de-1996` no tiene escritura posix. `gettext-po` escribe los scripts a la manera de gettext (siguiente sección).
  - `android` se expande a un directorio de recursos, escrito como `res/{locale}/strings.xml`: `values` para el origen, y luego `values-de`, `values-pt-rBR`, `values-b+zh+Hans`.

  Un estilo rechaza un locale que no puede escribir.

### Nombres de locale de gettext [#nombres-de-locale-de-gettext]

<AvailableFrom version="0.12.0" />

Con `format: "gettext-po"` y `localeStyle: "posix"`, los archivos llevan nombres de gettext (`language_REGION@modifier`) mientras la configuración conserva códigos BCP 47:

| Código en la configuración | Nombre de archivo |
| --- | --- |
| `pt-BR` | `pt_BR` |
| `es-419` | `es_419` |
| `sr-Latn` | `sr@latin` |
| `sr-Latn-RS` | `sr_RS@latin` |
| `uz-Cyrl` | `uz@cyrillic` |
| `ks-Deva-IN` | `ks_IN@devanagari` |
| `zh-Hant-TW` | `zh_TW` |
| `sr-Cyrl-RS` | `sr_RS` |

Un script que el idioma y la región ya implican se omite, así que `zh-TW` y `zh-Hant-TW` juntos fallan con `LOCALE_PATH_COLLISION`; un script sin modificador de gettext, como `zh-Hant` solo, falla con `LOCALE_LAYOUT_INVALID`. [`verbatra init`](https://verbatra.kreitz-webdev.de/es/docs/cli/init.md) lee estos nombres de vuelta. Los demás formatos mantienen la escritura de ICU (`sr_Latn`).

### Códigos de locale [#códigos-de-locale]

<AvailableFrom version="0.12.0" />

Cada código de locale debe ser una etiqueta que `Intl.getCanonicalLocales` acepte, con una subetiqueta de idioma de dos o tres letras, o la carga falla con `CONFIG_INVALID`: `pt_BR` (escribe `pt-BR` con `localeStyle: "posix"`) y `german` se rechazan. Un código válido no canónico, como `zh-hant-tw` o el obsoleto `iw`, funciona tal como está escrito.

### provider [#provider]

`provider.id` selecciona uno de los [proveedores](https://verbatra.kreitz-webdev.de/es/docs/providers.md) o `none`, cuyo `options` puede omitirse y, si se indica, debe ser `{}` ([Trabajar sin traducción automática](https://verbatra.kreitz-webdev.de/es/docs/human-only-workflow.md)). Los demás proveedores aceptan `options.localeMap` y `options.requestTimeoutMs` ([Proveedores](https://verbatra.kreitz-webdev.de/es/docs/providers.md#códigos-de-locale-enviados-al-proveedor)); desde 0.12.0 una clave mal colocada bajo `provider`, como `localeMap`, falla con `CONFIG_INVALID`.

### glossary [#glossary]

Términos que se traducen de una forma fija, en línea o como ruta a un archivo JSON con la misma forma (nunca fusionadas). La versión 1 asigna a cada término de origen una traducción para todos los locales:

```ts title="verbatra.config.ts"
export default defineConfig({
  // ...
  glossary: {
    "Sign in": "Anmelden",
  },
  // or: glossary: "glossary.json",
});
```

Una ruta relativa se resuelve contra el directorio del archivo de configuración; el archivo debe estar en UTF-8 y no superar 1 MiB, y se lee una vez al cargar. Un archivo ausente, JSON inválido o una forma inválida fallan con `CONFIG_INVALID`, nombrando la ruta y, en la versión 2, el campo. Pon un término `__proto__` en un archivo; un literal de JavaScript lo convierte en el prototipo.

#### Glosario por locale (versión 2) [#glosario-por-locale-versión-2]

<AvailableFrom version="0.12.0" />

La versión 2 añade traducciones por locale, traducciones prohibidas y términos que se quedan tal como están escritos:

```json title="glossary.json"
{
  "version": 2,
  "terms": [
    {
      "source": "Dashboard",
      "targets": { "de": "Übersicht", "fr": "Tableau de bord" },
      "forbidden": { "de": ["Instrumententafel"] },
      "note": "The start page after sign-in",
      "partOfSpeech": "noun"
    },
    { "source": "Sign in", "target": "Anmelden", "caseSensitive": true }
  ],
  "doNotTranslate": ["verbatra", { "term": "Acme", "caseSensitive": false }]
}
```

| Campo | Significado |
| --- | --- |
| `version` | Siempre `2`; cualquier otro número falla. |
| `terms[].source` | El término de origen; cada término aparece una vez. |
| `terms[].target` | La traducción para cada locale que no tenga entrada propia en `targets`. |
| `terms[].targets` | Traducciones por locale. Un locale usa su propia entrada, luego la de su idioma base (`de` cubre `de-AT`) y luego `target`, comparando códigos canónicos sin distinguir mayúsculas. |
| `terms[].forbidden` | Traducciones que un locale nunca debe usar; un locale regional también se rige por la lista de su idioma base. |
| `terms[].caseSensitive` | Comparar el término, las traducciones y las traducciones prohibidas distinguiendo mayúsculas. Por defecto `false`. |
| `terms[].note`, `terms[].partOfSpeech` | Contexto en texto libre, que un proveedor LLM recibe como datos. |
| `doNotTranslate` | Términos que se copian sin traducir. Un string simple conserva sus mayúsculas; `{ "term", "caseSensitive": false }` puede cambiarlas. |

Cada término necesita un `target`, una entrada en `targets` o una lista `forbidden`; no puede prohibir su propia traducción, nombrar un locale dos veces ni aparecer en `doNotTranslate`. Ningún texto puede estar en blanco; un término admite como máximo 200 caracteres, una traducción o una forma prohibida 2000, una `note` 500 y una `partOfSpeech` 50. La huella de [caché](https://verbatra.kreitz-webdev.de/es/docs/the-cache.md) de un locale solo cubre sus propios términos. Un archivo de la versión 1 conserva su huella; [`updateGlossaryTerm`](https://verbatra.kreitz-webdev.de/es/docs/sdk/config.md#updateglossaryterm) lo reescribe como versión 2 solo para una edición que la versión 1 no puede expresar.

<AvailableFrom version="0.4.0" pkg="@verbatra/studio" /> [Studio](https://verbatra.kreitz-webdev.de/es/docs/review-in-studio.md) solo edita la forma de archivo, término a término. Qué proveedores aplican el glosario está en [Proveedores](https://verbatra.kreitz-webdev.de/es/docs/providers.md#tono-y-glosario-entre-proveedores); cada salida se [comprueba después](https://verbatra.kreitz-webdev.de/es/docs/translation-safety.md).

### generatePlurals [#generateplurals]

Cuando es true, verbatra sintetiza las formas plurales CLDR que un destino necesita y el origen no tiene, como `few` y `many` en polaco, y las claves ordinales (`<key>_ordinal_<category>`) según las reglas ordinales CLDR. Solo lo admite `i18next-json` con un proveedor LLM; todo lo demás, y un locale sin reglas CLDR, recibe el [aviso de plurales](https://verbatra.kreitz-webdev.de/es/docs/language-support.md#plurales) (los ordinales suponen `other`). No hay opción de CLI; `translate()` del SDK acepta un override por ejecución.

### fuzzyCache [#fuzzycache]

`fuzzyCache: { enabled: true }` permite que un origen cambiado reutilice la traducción de su forma anterior cuando ambas se parecen al menos `threshold`, siempre marcada como `FUZZY_CACHE_REUSE` ([Reutilización difusa](https://verbatra.kreitz-webdev.de/es/docs/the-cache.md#reutilización-difusa)); `--no-cache` lo omite.

### humanEdits y pinnedKeys [#humanedits-y-pinnedkeys]

`humanEdits` cubre una clave obsoleta cuyo valor escribió una persona ([procedencia](https://verbatra.kreitz-webdev.de/es/docs/the-lock-file.md#procedencia-quién-escribió-cada-valor) `human`, `import` o `external`); una clave que coincide con `pinnedKeys` (como `["legal.*", "brand.name"]`) nunca se escribe de forma automática, diga lo que diga `humanEdits`. `*` coincide con cualquier secuencia de caracteres, puntos incluidos, y la comparación distingue mayúsculas. Qué hace cada modo está en [Conserva las traducciones humanas](https://verbatra.kreitz-webdev.de/es/docs/protecting-human-translations.md).

### network [#network]

Consulta [Restringe el acceso a la red](https://verbatra.kreitz-webdev.de/es/docs/network-policy.md).

```ts title="verbatra.config.ts"
network: { policy: "local-only", allowedHosts: ["gpu.lan"] }
```

### maxBatchSize [#maxbatchsize]

Las entradas faltantes y modificadas se envían en [sublotes](https://verbatra.kreitz-webdev.de/es/docs/providers.md#lotes) secuenciales que no superan este tamaño. Ninguna opción de CLI lo sobrescribe.

### maxLength [#maxlength]

Límites de longitud por clave, para cadenas sujetas a una restricción de maquetación:

```ts title="verbatra.config.ts"
maxLength: {
  "nav.dashboard": 18,
  "cta.submit": 12,
}
```

- **Aquí o en `verbatra.limits.json`.** <AvailableFrom version="0.13.0" /> Las claves se comparan literalmente, nunca como globs; una clave que no fija ninguno de los dos nunca se mide. `setKeyLengthLimit` solo admite claves del origen, así que Studio no puede fijar un límite a una forma plural generada; una entrada escrita a mano para su propia clave sí se aplica. El archivo versionado junto al archivo de bloqueo admite `{ "version": 1, "maxLength": { ... } }`, la configuración gana por clave y [`setKeyLengthLimit`](https://verbatra.kreitz-webdev.de/es/docs/sdk/config.md#setkeylengthlimit) lo escribe.
- **Clústeres de grafemas.** La longitud cuenta caracteres percibidos, espacios incluidos: un emoji, una letra acentuada o un carácter CJK cuentan como uno. El límite es inclusivo.
- **Cuándo.** Cada valor que `translate` produce para la clave, reutilizaciones de caché incluidas; una clave al día solo se mide cuando cambia su origen, o con [`export --include-unchanged`](https://verbatra.kreitz-webdev.de/es/docs/cli/export.md).
- **Informativo.** Un exceso se sigue escribiendo y bloqueando, y se marca para revisión como [`MAX_LENGTH_EXCEEDED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#max_length_exceeded).

### maxTokens y budgetBehavior [#maxtokens-y-budgetbehavior]

`maxTokens` es un presupuesto para toda la ejecución: tokens de entrada más de salida en cada llamada al proveedor (traducción y generación de plurales) y en cada locale de destino. [`translate --max-tokens`](https://verbatra.kreitz-webdev.de/es/docs/cli/translate.md#tope-de-tokens) puede endurecerlo para una ejecución, nunca relajarlo, y siempre como un `"stop"` estricto.

`budgetBehavior` decide qué pasa entonces:

- `"warn"`, el valor por defecto, cuenta el gasto y señala el exceso, pero continúa.
- `"stop"` <AvailableFrom version="0.11.0" /> lo convierte en un techo para todos los proveedores. Antes de cada petición, la ejecución proyecta su coste como [la estimación previa](https://verbatra.kreitz-webdev.de/es/docs/estimating-cost.md) y rechaza una que superaría `maxTokens`. Las claves de esa petición y cada clave aún no intentada (el resto del locale y cada locale posterior, cuyo diff e informe de huérfanas siguen ejecutándose) se retienen, conservan su hash anterior en el bloqueo y se reintentan en la siguiente ejecución.

Con `"stop"`:

- Después de cada petición el total se reconcilia con el uso que informó el proveedor, así que una ejecución puede terminar algo por encima de `maxTokens` ([el `budget` del resumen de ejecución](https://verbatra.kreitz-webdev.de/es/docs/sdk/run-summary.md#la-anatomía-de-runsummary)). Los proveedores de traducción automática no informan de tokens y se presupuestan a partir de la proyección.
- Una petición fallida o truncada se carga por completo.
- La proyección suma una asignación fija para el prompt del LLM, también para los proveedores de traducción automática, y abarca un lote entero, así que un `maxTokens` por debajo de la proyección de un lote lo rechaza en cada ejecución; el aviso indica que bajes `maxBatchSize` o subas `maxTokens`.
- Un locale con claves retenidas es `partial`, o `failed` si no llegó ninguna clave, y ambos salen con `1`. Con `"warn"` el código de salida nunca cambia.

El presupuesto acota una ejecución de `translate`, nunca la retraducción de una sola entrada; `watch` arranca uno nuevo por ejecución. Un presupuesto excluye [`--concurrency`](https://verbatra.kreitz-webdev.de/es/docs/cli/translate.md#locales-en-paralelo) por encima de `1` en una ejecución real; un dry run queda exento. `budgetBehavior` sin `maxTokens` no tiene efecto.

<Callout type="warn" title="Dos maxTokens distintos">
El `maxTokens` de nivel superior es este presupuesto de toda la ejecución; el `provider.options.maxTokens` de Anthropic, sin relación con él, limita una respuesta ([Proveedores](https://verbatra.kreitz-webdev.de/es/docs/providers.md#anthropic)).
</Callout>

### rates [#rates]

Solo lo lee [`translate --estimate`](https://verbatra.kreitz-webdev.de/es/docs/estimating-cost.md), que convierte las tarifas en dinero; una ejecución real lo ignora.

```ts title="verbatra.config.ts"
rates: {
  asOf: "2026-01-15",
  currency: "USD",
  table: {
    // placeholders: copy the current rates from each provider's pricing page
    "gemini/gemini-2.5-flash": { inputPerMillionTokens: 1, outputPerMillionTokens: 2 },
    deepl: { perMillionCharacters: 1 },
  },
}
```

Una clave de `table` es `provider/model`, o el id a secas para un proveedor sin modelo (`deepl`, `google-translate`). Una entrada se factura por tokens (`inputPerMillionTokens`, `outputPerMillionTokens`) o por caracteres (`perMillionCharacters`), nunca ambas cosas, y se rechaza una tarifa negativa, una tarifa por encima de 1.000.000.000 por millón o la unidad equivocada. `openai-compatible` y `libretranslate` no emiten factura, así que su cantidad se informa sin tarifa.

### extract [#extract]

Solo lo leen [`extract`](https://verbatra.kreitz-webdev.de/es/docs/cli/extract.md), [`doctor --literals`](https://verbatra.kreitz-webdev.de/es/docs/cli/doctor.md#literales-sin-traducir) y [`diff --unused`](https://verbatra.kreitz-webdev.de/es/docs/cli/diff.md#claves-de-origen-sin-uso).

```ts title="verbatra.config.ts"
extract: {
  framework: "i18next",
  roots: ["src", "app"],
  exclude: ["generated"],
  literals: { ignore: ["Acme Inc."] },
  unused: { ignore: ["emails.*"] },
}
```

- **`framework`** debe nombrar uno con extractor ([formas de llamada](https://verbatra.kreitz-webdev.de/es/docs/cli/extract.md#qué-encuentra)); cualquier otro se rechaza.
- **`roots`** se resuelven contra la raíz del proyecto; **`exclude`** añade nombres de directorio (no rutas), que coinciden en cualquier punto bajo una raíz, al [conjunto que siempre se omite](https://verbatra.kreitz-webdev.de/es/docs/cli/extract.md#límites-del-análisis).
- **`literals.ignore`** coincide con el texto completo de un literal, con espacios reducidos y referencias decodificadas ([Literales sin traducir](https://verbatra.kreitz-webdev.de/es/docs/cli/doctor.md#literales-sin-traducir)).
- **`unused.ignore`** se compara con la clave decodificada ([`diff --unused`](https://verbatra.kreitz-webdev.de/es/docs/cli/diff.md#claves-de-origen-sin-uso)).

## Orden de descubrimiento [#orden-de-descubrimiento]

verbatra busca hacia arriba desde el directorio de trabajo y toma la primera coincidencia, deteniéndose en el directorio más cercano que contenga `.git`, si no en tu directorio personal (o en el de trabajo cuando el personal no está por encima), así que nunca recoge una configuración por encima de tu repositorio:

1. `package.json` (una propiedad `"verbatra"`)
2. `.verbatrarc`
3. `.verbatrarc.json`
4. `.verbatrarc.yaml`
5. `.verbatrarc.yml`
6. `.verbatrarc.js`
7. `.verbatrarc.cjs`
8. `.verbatrarc.ts`
9. `verbatra.config.js`
10. `verbatra.config.cjs`
11. `verbatra.config.ts`

`--config <path>` carga un solo archivo en su lugar, relativo al directorio de trabajo; la prioridad en el SDK está en [`loadConfig`](https://verbatra.kreitz-webdev.de/es/docs/sdk/config.md#loadconfig).

## Validación en el editor [#validación-en-el-editor]

<AvailableFrom version="0.9.0" />

`@verbatra/sdk` publica un JSON Schema generado a partir de su esquema zod, servido también en una URL estable para cualquier instalación, `npx`, un monorepo con hoisting o un agente remoto:

```text
https://verbatra.kreitz-webdev.de/schema/v1/config.json
```

Sin conexión, o para fijar la versión instalada, usa la copia del paquete, `./node_modules/@verbatra/sdk/dist/config-schema.json` ([todos los esquemas](https://verbatra.kreitz-webdev.de/es/docs/cli/output.md#esquemas)).

`.verbatrarc.json` y `.verbatrarc` llevan una clave `$schema` para VS Code:

```json title=".verbatrarc.json"
{
  "$schema": "https://verbatra.kreitz-webdev.de/schema/v1/config.json",
  "sourceLocale": "en",
  "targetLocales": ["de", "fr"],
  "format": "i18next-json",
  "files": { "pattern": "locales/{locale}.json" },
  "provider": { "id": "gemini", "options": { "model": "gemini-2.5-flash", "maxOutputTokens": 4096 } }
}
```

El `.verbatrarc` sin extensión necesita además una asociación de archivos del espacio de trabajo:

```json title=".vscode/settings.json"
{
  "json.schemas": [
    {
      "fileMatch": [".verbatrarc", ".verbatrarc.json"],
      "url": "https://verbatra.kreitz-webdev.de/schema/v1/config.json"
    }
  ]
}
```

Una configuración YAML lleva un comentario del YAML Language Server:

```yaml title=".verbatrarc.yaml"
# yaml-language-server: $schema=https://verbatra.kreitz-webdev.de/schema/v1/config.json
sourceLocale: en
targetLocales: [de, fr]
format: i18next-json
files:
  pattern: "locales/{locale}.json"
provider:
  id: gemini
  options:
    model: gemini-2.5-flash
    maxOutputTokens: 4096
```

`package.json` no admite esquema; las formas ejecutables las tipa `defineConfig`.

### Lo que el documento no puede comprobar [#lo-que-el-documento-no-puede-comprobar]

Solo la carga de la configuración comprueba estas reglas: las reglas de `targetLocales` y de los [códigos de locale](#códigos-de-locale), las claves de [`localeMap`](https://verbatra.kreitz-webdev.de/es/docs/providers.md#códigos-de-locale-enviados-al-proveedor) y las reglas de `baseUrl` y [`apiKeyEnvVar`](https://verbatra.kreitz-webdev.de/es/docs/providers.md#openai-compatible) de `openai-compatible`, direcciones y rangos válidos en [`network.allowedHosts`](https://verbatra.kreitz-webdev.de/es/docs/network-policy.md), `sensitiveData.patterns` dentro de las [reglas de seguridad de patrones](https://verbatra.kreitz-webdev.de/es/docs/data-handling.md#protección-de-contenido-sensible) y las reglas de términos de un glosario en línea de la [versión 2](#glosario-por-locale-versión-2).

## El directorio de trabajo y .env [#el-directorio-de-trabajo-y-env]

El directorio de trabajo (donde ejecutas verbatra, o `--cwd`) inicia la búsqueda de configuración y contiene los [archivos de entorno](https://verbatra.kreitz-webdev.de/es/docs/cli.md#archivos-de-entorno). Las rutas de locale, `verbatra.lock.json`, la caché, el archivo de procedencia y `.verbatra-local/` se resuelven contra la raíz del proyecto, el directorio de la configuración encontrada, así que una ejecución desde un subdirectorio usa los mismos archivos. Con `--config`, el directorio de trabajo es la raíz, y una configuración en otro lugar recibe un aviso en stderr, porque la ruta de su glosario se resuelve contra su propio directorio. Una ruta que pasas tú, como `--out` o `check --file`, se resuelve contra el directorio de trabajo.

## Cuando la carga falla [#cuando-la-carga-falla]

- [`CONFIG_NOT_FOUND`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_not_found): no hay configuración en ningún sitio buscado, o la ruta de `--config` no existe.
- [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_invalid): se encontró una configuración pero no se puede usar. El mensaje lista cada problema con la ruta de su clave; una clave desconocida añade la pista de que las claves de API vienen del entorno. Un fallo de parseo nombra el archivo (con línea y columna en YAML) pero nunca cita su contenido, y cada mensaje pasa por la redacción de claves.

La CLI sale con `2` en ambos casos.
