---
title: "Configuración y glosario"
description: "Puntos de entrada del SDK que cargan y validan la configuración de verbatra y editan el glosario, además del que detecta si un directorio contiene un proyecto."
type: "reference"
---
# Configuración y glosario

Puntos de entrada del SDK que cargan y validan la configuración de verbatra y editan el glosario, además del que detecta si un directorio contiene un proyecto.

## Carga la configuración [#configuración]

### loadConfig [#loadconfig]

Encuentra, carga y valida la configuración del proyecto, devolviendo una `VerbatraConfig`. `configOverride`
(validar un objeto en memoria) gana a `configPath` (cargar un archivo explícito), que gana a una
búsqueda desde `cwd` en el [orden de descubrimiento](https://verbatra.kreitz-webdev.de/es/docs/config-file.md#orden-de-descubrimiento). Un `glossary` dado como
ruta de archivo se lee y valida aquí, así que el código posterior siempre ve un glosario en memoria:
un mapa de versión 1 de término de origen a traducción, o una definición de versión 2.

```ts title="Firma"
function loadConfig(
  options?: LoadConfigOptions,
): Promise<VerbatraConfig>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `cwd` | `string` | no | Directory the search starts from, and the base a relative `configPath` resolves against. Defaults to the process working directory. A flow given the loaded config without a `cwd` resolves its paths against the project root resolveProjectRoot describes, except for a `configOverride` config, whose flows fall back to the process working directory. |
| `configOverride` | `unknown` | no | A config object to validate directly instead of reading any file. Takes precedence over `configPath` and over searching. Useful for embedding verbatra in a tool that already holds the configuration in memory. |
| `configPath` | `string` | no | An explicit config file to load, bypassing the search. A missing file is an error rather than a fallback to search. |
| `fs` | `SdkFs` | no | File-system port used to read the glossary file. Defaults to the real file system. |
| `fresh` | `boolean` | no | Re-evaluate a JavaScript or TypeScript config file instead of reusing what an earlier load in the same process evaluated. A `.ts` config is re-evaluated together with the modules it imports; a `.js` or `.cjs` config is re-evaluated alone, so a module it imports or requires keeps its first evaluation until the process restarts. Without it, a process that loads the config twice keeps the first result of a `verbatra.config.ts`, `.js`, or `.cjs` file even after the file changed. A long-running process that reloads the config after an edit sets it. JSON, YAML, and `package.json` configs are always read afresh. Defaults to `false`. |

**Devuelve:** `VerbatraConfig`

**Lanza:** [`CONFIG_NOT_FOUND`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_not_found), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_invalid)

**Ejemplo:** [Una configuración sin archivo](https://verbatra.kreitz-webdev.de/es/docs/programmatic-api.md#una-configuración-sin-archivo)

Consulta el [Archivo de configuración](https://verbatra.kreitz-webdev.de/es/docs/config-file.md) para ver el esquema.
`fs` es el puerto del sistema de archivos a través del cual se lee un archivo de glosario, como se
describe en [El punto de inyección de dependencias](https://verbatra.kreitz-webdev.de/es/docs/sdk.md#el-punto-de-inyección-de-dependencias).

### loadConfigWithMeta [#loadconfigwithmeta]

<AvailableFrom version="0.5.0" />

La misma carga, más la procedencia: devuelve `{ config, source, glossary }`, donde `source` dice si la
configuración vino de un acierto de búsqueda, de una ruta explícita o de una anulación en memoria (con
el `filepath` absoluto cuando lo hay), y `glossary` registra si el glosario estaba ausente, en línea o
resuelto desde un archivo. Úsalo cuando necesites mostrar de dónde salió la configuración.

```ts title="Firma"
function loadConfigWithMeta(
  options?: LoadConfigOptions,
): Promise<LoadedConfig>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `cwd` | `string` | no | Directory the search starts from, and the base a relative `configPath` resolves against. Defaults to the process working directory. A flow given the loaded config without a `cwd` resolves its paths against the project root resolveProjectRoot describes, except for a `configOverride` config, whose flows fall back to the process working directory. |
| `configOverride` | `unknown` | no | A config object to validate directly instead of reading any file. Takes precedence over `configPath` and over searching. Useful for embedding verbatra in a tool that already holds the configuration in memory. |
| `configPath` | `string` | no | An explicit config file to load, bypassing the search. A missing file is an error rather than a fallback to search. |
| `fs` | `SdkFs` | no | File-system port used to read the glossary file. Defaults to the real file system. |
| `fresh` | `boolean` | no | Re-evaluate a JavaScript or TypeScript config file instead of reusing what an earlier load in the same process evaluated. A `.ts` config is re-evaluated together with the modules it imports; a `.js` or `.cjs` config is re-evaluated alone, so a module it imports or requires keeps its first evaluation until the process restarts. Without it, a process that loads the config twice keeps the first result of a `verbatra.config.ts`, `.js`, or `.cjs` file even after the file changed. A long-running process that reloads the config after an edit sets it. JSON, YAML, and `package.json` configs are always read afresh. Defaults to `false`. |

**Devuelve:** `LoadedConfig`

**Lanza:** [`CONFIG_NOT_FOUND`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_not_found), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_invalid)

Ambas aceptan `fresh: true` para volver a evaluar un archivo de configuración en JavaScript o
TypeScript en lugar de reutilizar lo que evaluó una carga anterior en el mismo proceso; un proceso de
larga duración que recarga la configuración tras una edición lo activa. Las configuraciones JSON, YAML
y de `package.json` siempre se leen de nuevo. <AvailableFrom version="0.12.0" />

### configCandidatePaths [#configcandidatepaths]

<AvailableFrom version="0.12.0" />

Lista cada archivo del que `loadConfigWithMeta` podría leer una configuración con los mismos
`{ cwd?, configPath? }`: solo el archivo explícito cuando se indica `configPath`, y si no, cada lugar
de búsqueda en cada directorio de la cadena de búsqueda, el más cercano primero, exista o no.
Vigílalas, por ejemplo por fecha de modificación, para notar que una configuración se crea, se
edita o se elimina sin cargarla en cada petición. El archivo de glosario no se incluye;
`loadConfigWithMeta` lo nombra en `glossary`.

```ts title="Firma"
function configCandidatePaths(
  options?: ConfigCandidateOptions,
): readonly string[];
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `cwd` | `string` | no | Directory the config search starts from. Defaults to the process working directory. |
| `configPath` | `string` | no | An explicit config file, resolved against `cwd`. When set, it is the only candidate. |

**Devuelve:** `readonly string[]`

### resolveProjectRoot [#resolveprojectroot]

<AvailableFrom version="0.12.0" />

Devuelve la raíz del proyecto contra la que los flujos resuelven rutas relativas: el directorio del
archivo de configuración encontrado, así que un proceso iniciado en un subdirectorio trabaja con los
archivos de locale, el archivo de bloqueo y `.verbatra-local/` del proyecto, o `cwd` para una
configuración de `configPath`. Un flujo que recibe la configuración que devolvió `loadConfig` o
`loadConfigWithMeta` ya usa esa raíz como `cwd` por defecto. Pasa
`resolveProjectRoot(loaded.source, cwd)` como `cwd` cuando copias o reconstruyes la configuración, y
a `loadLockFile`, `loadProvenance` y `runStatus`, que no reciben configuración.

```ts title="Firma"
function resolveProjectRoot(
  source: ConfigSource,
  cwd: string,
): string;
```

**Devuelve:** `string`

## Glosario [#glosario]

### readGlossaryFile [#readglossaryfile]

<AvailableFrom version="0.9.0" />

Lee un glosario respaldado por archivo directamente del disco y lo devuelve como un `Glossary`
normalizado: `{ version, terms, doNotTranslate }`, donde `version` es `1` para un mapa plano de
términos y `2` para un [glosario por locale](https://verbatra.kreitz-webdev.de/es/docs/config-file.md#glossary), y cada término lleva
`source`, un `target` opcional, `targets`, `forbidden`, `caseSensitive` y, de forma opcional, `note`
y `partOfSpeech`. Su entrada `glossary` es la `GlossaryProvenance` de `loadConfigWithMeta`, de modo
que el archivo que lee siempre es el que nombra la configuración; no hay ningún argumento de ruta.
Úsalo en una herramienta de larga duración que muestre el glosario como está ahora, no como al
cargarlo.

```ts title="Firma"
function readGlossaryFile(
  input: GlossaryFileInput,
  deps?: GlossaryFileDeps,
): Promise<Glossary>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `glossary` | `GlossaryProvenance` | yes | Where the loaded config's glossary came from, as reported by loadConfigWithMeta. Only a `file` provenance is accepted; it also carries the path, which is why neither function takes one. |

**Devuelve:** `Glossary`

**Lanza:** [`GLOSSARY_NOT_FILE_BACKED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#glossary_not_file_backed), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_invalid)

Lanza `GLOSSARY_NOT_FILE_BACKED` cuando el glosario está en línea o ausente, y `CONFIG_INVALID`
cuando el archivo incumple las [reglas del archivo de glosario](https://verbatra.kreitz-webdev.de/es/docs/config-file.md#glossary) o declara
otra versión.

<AvailableFrom version="0.12.0" />

Hasta la 0.11 devolvía el propio mapa plano de términos.

### updateGlossaryTerm [#updateglossaryterm]

<AvailableFrom version="0.9.0" />

Añade, cambia o elimina exactamente un término de un glosario respaldado por archivo y devuelve el
glosario normalizado tal como queda. `translation`
es el texto nuevo o `null` para eliminar el término. El resto del archivo conserva su
orden de claves y su sangría, la escritura es atómica y todo el ciclo de leer, modificar y escribir
se mantiene bajo un bloqueo de glosario para todo el proyecto, así que dos ediciones simultáneas se
serializan en vez de entrelazarse.

```ts title="Firma"
function updateGlossaryTerm(
  input: UpdateGlossaryTermInput,
  deps?: GlossaryFileDeps,
): Promise<Glossary>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `cwd` | `string` | no | Directory the write lock is taken under. Defaults to the process working directory. |
| `term` | `string` | yes | The source term to add, change, or remove. Must not be blank. |
| `translation` | `string \| null` | no | The translation to store for the term. Without `locale` it is the translation every target locale uses; with `locale` it is that locale's own translation. `null` removes that translation only, and the term goes with it once it has no translation and no forbidden rendering left. Must not be blank. |
| `locale` | `string` | no | The target locale `translation` and `forbidden` apply to. Omit it for every locale. |
| `forbidden` | `readonly string[] \| null` | no | Renderings `locale` must never use for the term, replacing any listed before. `null` or an empty list removes them. Requires `locale`. |
| `note` | `string \| null` | no | Free-text context for the term, or `null` to remove it. |
| `partOfSpeech` | `string \| null` | no | The term's part of speech, free text, or `null` to remove it. |
| `caseSensitive` | `boolean` | no | Whether the term is matched with case. |
| `doNotTranslate` | `boolean` | no | `true` adds the term to the terms kept untranslated in every locale, `false` removes it from them. Cannot be combined with any field but `caseSensitive`. |
| `lockAcquireTimeoutMs` | `number` | no | How long, in milliseconds, to wait for the project's glossary write lock before failing with `LOCK_CONTENDED`. Defaults to ten minutes. |
| `glossary` | `GlossaryProvenance` | yes | Where the loaded config's glossary came from, as reported by loadConfigWithMeta. Only a `file` provenance is accepted; it also carries the path, which is why neither function takes one. |

**Devuelve:** `Glossary`

**Lanza:** [`GLOSSARY_NOT_FILE_BACKED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#glossary_not_file_backed), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_invalid), [`LOCK_TIMEOUT_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#lock_timeout_invalid), [`LOCK_CONTENDED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#lock_contended), [`RUN_CANCELLED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#run_cancelled), [`GLOSSARY_UNWRITABLE`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#glossary_unwritable)

<AvailableFrom version="0.12.0" />

También recibe `locale` (entonces `translation` es la traducción propia de ese locale y `null` solo
elimina esa), `forbidden` (las traducciones que `locale` nunca debe usar; `null` o `[]` las
elimina), `note`, `partOfSpeech` (cada uno `null` para eliminarlo), `caseSensitive` y
`doNotTranslate` (`true` añade el término a los que no se traducen, `false` lo quita; no se puede
combinar con los campos del término). Un archivo de la versión 1 sigue siendo versión 1 mientras la
edición solo fije o elimine una traducción para todos los locales; cualquier otra edición lo
reescribe como versión 2, y cada término existente conserva su traducción como `target`. `translation: null` sin `locale` ahora elimina solo la traducción compartida; el término en sí
se elimina cuando ya no le queda ninguna traducción ni traducción prohibida, lo que en un término de
la versión 1 ocurre de inmediato.

Un glosario en línea se rechaza con `GLOSSARY_NOT_FILE_BACKED` en lugar de convertirse: vive dentro
de un módulo de configuración ejecutable. Un campo vacío, una edición que no fija ningún campo o que mezcla
`doNotTranslate` con los campos del término, traducciones prohibidas sin locale, un locale no válido,
una edición que dejaría un glosario no válido y una edición cuyo resultado superaría el límite de
1 MiB del glosario se rechazan con `CONFIG_INVALID`; una escritura fallida, incluido un bloqueo de escritura del glosario que no se puede crear en un proyecto de solo lectura o liberar tras una edición guardada, es `GLOSSARY_UNWRITABLE`, con el error del sistema de archivos como `cause`.
Una edición que deja el glosario tal como ya está tiene éxito y no escribe nada.

<AvailableFrom version="0.12.0" />

También acepta `lockAcquireTimeoutMs`, que limita la espera del bloqueo del glosario antes de que la llamada falle con `LOCK_CONTENDED` (diez minutos por defecto); un límite no válido falla con `LOCK_TIMEOUT_INVALID` antes de leer nada.

### glossaryForLocale [#glossaryforlocale]

<AvailableFrom version="0.12.0" />

Resuelve la parte de un glosario que se aplica a un locale de destino:
`glossaryForLocale(config.glossary, "de")` devuelve `{ terms, doNotTranslate }`, cada término con el
`target` del locale (su propia entrada, luego la de su idioma base, luego la compartida), sus
traducciones `forbidden`, `caseSensitive`, y su `note` y `partOfSpeech`, o `undefined` cuando nada
del glosario se aplica allí. Es exactamente lo que una petición de traducción a ese locale lleva como
[`TranslateRequest.glossary`](https://verbatra.kreitz-webdev.de/es/docs/sdk/extend.md#proveedores-propios), y lo que ven las comprobaciones de revisión y la huella de caché de
ese locale.

```ts title="Firma"
function glossaryForLocale(
  glossary: GlossaryInput | Glossary | undefined,
  locale: string,
): LocaleGlossary | undefined;
```

**Devuelve:** `LocaleGlossary | undefined`

### glossaryHits [#glossaryhits]

<AvailableFrom version="0.12.0" />

`glossaryHits({ glossary, locale, sourceLocale, source })` devuelve las entradas del glosario que se
aplican a un texto de origen en un locale de destino, como `{ terms, doNotTranslate }` con la forma
que devuelve `glossaryForLocale`: cada término cuyo origen aparece en `source` como término
completo, con la traducción y las traducciones prohibidas a las que está sujeto ese locale, y cada
término que se mantiene sin traducir y aparece en él. Un término coincide con o sin mayúsculas según
indique, normalizando para `sourceLocale`. Usa la misma coincidencia que aplica una ejecución de
traducción al marcar un término de glosario omitido, y no lee nada.

```ts title="Firma"
function glossaryHits(
  input: GlossaryHitsInput,
): LocaleGlossary;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `glossary` | `Glossary \| GlossaryInput \| undefined` | yes | The config's glossary, in either supported shape or already normalized, or `undefined`. |
| `locale` | `string` | yes | The target locale whose translations and forbidden renderings apply. |
| `sourceLocale` | `string` | yes | The locale the text is written in, used to fold case for a term matched without case. |
| `source` | `string` | yes | The source text to look for terms in. |

**Devuelve:** `LocaleGlossary`

### glossaryDraftCheck [#glossarydraftcheck]

<AvailableFrom version="0.12.0" />

`glossaryDraftCheck({ glossary, locale, sourceLocale, source, draft })` comprueba un borrador de
traducción contra las entradas del glosario que `glossaryHits` encuentra en el texto de origen,
antes de que lo escribas. Cada término vuelve con `targetUsed` (si el borrador lleva la traducción
obligatoria; ausente en un término que solo prohíbe traducciones) y `forbiddenUsed` (las
traducciones prohibidas que usa el borrador y no el origen), y cada término que se mantiene sin
traducir con `kept`. Son las reglas con las que una ejecución de traducción marca
`GLOSSARY_TERM_MISSED` y `GLOSSARY_FORBIDDEN_TERM`. No lee nada.

```ts title="Firma"
function glossaryDraftCheck(
  input: GlossaryDraftCheckInput,
): GlossaryDraftCheck;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `glossary` | `Glossary \| GlossaryInput \| undefined` | yes | The config's glossary, in either supported shape or already normalized, or `undefined`. |
| `locale` | `string` | yes | The target locale the draft is written in. |
| `sourceLocale` | `string` | yes | The locale the source text is written in. |
| `source` | `string` | yes | The key's source text. |
| `draft` | `string` | yes | The draft translation to check. |

**Devuelve:** `GlossaryDraftCheck`

### normalizeGlossary [#normalizeglossary]

<AvailableFrom version="0.12.0" />

Convierte un glosario en cualquiera de sus formas, un mapa plano de la versión 1 o una definición de
la versión 2, al `Glossary` normalizado que devuelve `readGlossaryFile`, con todos los valores por
defecto rellenados. Úsalo para mostrar un glosario en línea igual que uno respaldado por archivo. No
vuelve a validar; `loadConfig` ya lo hizo.

```ts title="Firma"
function normalizeGlossary(
  glossary: GlossaryInput | Glossary,
): Glossary;
```

**Devuelve:** `Glossary`

### sharedGlossaryTranslations [#sharedglossarytranslations]

<AvailableFrom version="0.12.0" />

Proyecta un `Glossary` normalizado sobre un mapa plano de cada término que tiene un `target`
compartido a esa traducción, en el orden del glosario. Las traducciones por locale, las traducciones
prohibidas y los términos de `doNotTranslate` quedan fuera, así que úsalo solo donde un consumidor
no pueda mostrar más que un mapa plano de términos. Un término llamado `__proto__` sigue siendo una
clave propia.

```ts title="Firma"
function sharedGlossaryTranslations(
  glossary: Glossary,
): Readonly<Record<string, string>>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `version` | `1 \| 2` | yes | The format the glossary was written in: `1` for a flat term map, `2` for a GlossaryDefinition. |
| `terms` | `readonly GlossaryTerm[]` | yes | Every term, in the order it was written. |
| `doNotTranslate` | `readonly DoNotTranslateTerm[]` | yes | Every term to keep untranslated, in the order it was written. |

**Devuelve:** `Readonly<Record<string, string>>`

### redactGlossary [#redactglossary]

<AvailableFrom version="0.12.0" />

Pasa cada término de origen, traducción, traducción prohibida, nota, categoría gramatical y término
de `doNotTranslate` de un `Glossary`
normalizado por `redact` y devuelve `{ glossary, redactedTerms }`, donde `redactedTerms` nombra cada
término al que se le sustituyó un valor, un término de origen redactado como `[REDACTED]`, para que
la lista nunca repita un secreto. El servidor MCP y Studio lo usan antes de que un glosario salga del proceso; úsalo igual
en tu propia herramienta.

```ts title="Firma"
function redactGlossary(glossary: Glossary): RedactedGlossary;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `version` | `1 \| 2` | yes | The format the glossary was written in: `1` for a flat term map, `2` for a GlossaryDefinition. |
| `terms` | `readonly GlossaryTerm[]` | yes | Every term, in the order it was written. |
| `doNotTranslate` | `readonly DoNotTranslateTerm[]` | yes | Every term to keep untranslated, in the order it was written. |

**Devuelve:** `RedactedGlossary`

### readCurrentGlossary [#readcurrentglossary]

<AvailableFrom version="0.12.0" />

Lee el glosario que nombra una configuración cargada tal como está ahora:
`readCurrentGlossary({ loaded })`, donde `loaded` es lo que devuelve `loadConfigWithMeta`.
Un glosario respaldado por archivo se lee directamente del disco, uno en línea sale de la
configuración, y en ambos casos el resultado es el `Glossary` normalizado, o `undefined` cuando la
configuración no declara ninguno. Para ver a qué está sujeto un locale de destino, pasa el resultado
a `glossaryForLocale`.

```ts title="Firma"
function readCurrentGlossary(
  input: ReadCurrentGlossaryInput,
  deps?: GlossaryFileDeps,
): Promise<Glossary | undefined>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `loaded` | `GlossaryConfig` | yes | The loaded config, as loadConfigWithMeta returns it. |

**Devuelve:** `Glossary | undefined`

**Lanza:** [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_invalid)

### editConfiguredGlossaryTerm [#editconfiguredglossaryterm]

<AvailableFrom version="0.12.0" />

`updateGlossaryTerm` para una herramienta que tiene una configuración cargada: recibe
`loaded` en lugar de `glossary` con los mismos campos de edición, trata un campo dejado en `undefined`
como ausente y comprueba primero `locale` contra los locales de destino configurados; si no es uno de
ellos, falla con `UNKNOWN_LOCALE` y no escribe nada. El servidor MCP y Studio escriben el glosario
a través de ella.

```ts title="Firma"
function editConfiguredGlossaryTerm(
  input: EditConfiguredGlossaryTermInput,
  deps?: GlossaryFileDeps,
): Promise<Glossary>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `loaded` | `GlossaryConfig` | yes | The loaded config, as loadConfigWithMeta returns it. |
| `term` | `string` | yes | The source term to add, change, or remove. Must not be blank. |
| `cwd` | `string` | no | Directory the write lock is taken under. Defaults to the process working directory. |
| `translation` | `string \| null` | no | The translation to store for the term. Without `locale` it is the translation every target locale uses; with `locale` it is that locale's own translation. `null` removes that translation only, and the term goes with it once it has no translation and no forbidden rendering left. Must not be blank. |
| `locale` | `string` | no | The target locale `translation` and `forbidden` apply to. Omit it for every locale. |
| `forbidden` | `readonly string[] \| null` | no | Renderings `locale` must never use for the term, replacing any listed before. `null` or an empty list removes them. Requires `locale`. |
| `note` | `string \| null` | no | Free-text context for the term, or `null` to remove it. |
| `partOfSpeech` | `string \| null` | no | The term's part of speech, free text, or `null` to remove it. |
| `caseSensitive` | `boolean` | no | Whether the term is matched with case. |
| `doNotTranslate` | `boolean` | no | `true` adds the term to the terms kept untranslated in every locale, `false` removes it from them. Cannot be combined with any field but `caseSensitive`. |
| `lockAcquireTimeoutMs` | `number` | no | How long, in milliseconds, to wait for the project's glossary write lock before failing with `LOCK_CONTENDED`. Defaults to ten minutes. |

**Devuelve:** `Glossary`

**Lanza:** [`UNKNOWN_LOCALE`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#unknown_locale), [`GLOSSARY_NOT_FILE_BACKED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#glossary_not_file_backed), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#config_invalid), [`LOCK_TIMEOUT_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#lock_timeout_invalid), [`LOCK_CONTENDED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#lock_contended), [`RUN_CANCELLED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#run_cancelled), [`GLOSSARY_UNWRITABLE`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#glossary_unwritable)

## Escritura, detección y modo solo humano [#escritura-detección-y-modo-solo-humano]

### defineConfig [#defineconfig]

Un ayudante de identidad para un `verbatra.config.ts` tipado: devuelve su argumento sin cambios,
para la inferencia de tipos y el autocompletado del editor, incluidos los IDs de modelo conocidos del
proveedor seleccionado (solo al escribir; en tiempo de ejecución pasa cualquier cadena no vacía).
Cada proveedor salvo `opencode`, `openai-compatible`, `libretranslate` y `none` tiene además una sobrecarga que
recibe `AuthoringConfigFor<"<id>">`, como `AuthoringConfigFor<"anthropic">`, que restringe el bloque
`provider` a las opciones de ese proveedor; esos cuatro usan la alternativa con `AuthoringConfig` de
abajo.

```ts title="Firma"
function defineConfig(config: AuthoringConfigFor<"anthropic">): VerbatraConfigInput;
function defineConfig(config: AuthoringConfigFor<"openai">): VerbatraConfigInput;
function defineConfig(config: AuthoringConfigFor<"gemini">): VerbatraConfigInput;
function defineConfig(config: AuthoringConfigFor<"deepl">): VerbatraConfigInput;
function defineConfig(config: AuthoringConfigFor<"google-translate">): VerbatraConfigInput;
function defineConfig(config: AuthoringConfig): VerbatraConfigInput;
```

**Devuelve:** `VerbatraConfigInput`

**Ejemplo:** [Añade un archivo fuente y una configuración](https://verbatra.kreitz-webdev.de/es/docs/sdk-quickstart.md#añade-un-archivo-fuente-y-una-configuración)

### verbatraConfigSchema [#verbatraconfigschema]

El esquema zod con el que valida `loadConfig`, exportado para que tu propia herramienta pueda validar un
objeto de configuración igual que lo hace el SDK. Las claves desconocidas de nivel superior se rechazan,
así que un secreto extraviado no puede esconderse en la configuración, salvo `$schema`: una cadena
opcional, ignorada en tiempo de ejecución, con la que una configuración JSON o YAML apunta un editor
al `@verbatra/sdk/config-schema.json` del paquete.

```ts title="Firma"
const verbatraConfigSchema: z.ZodObject<{ ... }, z.core.$strict>;
```

Su bloque `rates` es una `RateCard`, la lista de precios que convierte una [estimación](https://verbatra.kreitz-webdev.de/es/docs/estimating-cost.md) en dinero:

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `asOf` | `string` | yes | The date the rates were read, written as `YYYY-MM-DD`; printed beside every priced estimate. |
| `currency` | `string` | yes | The three-letter uppercase currency code the rates are written in, such as `USD` or `EUR`. |
| `table` | `Record<string, union>` | yes | The rate entries by rate key: a token rate or a character rate, never both. |

### scaffoldingMetadata [#scaffoldingmetadata]

<AvailableFrom version="0.4.0" />

Metadatos de solo lectura de los que el comando `init` de la CLI deriva sus preguntas: `providerEnv` (de
id de proveedor a la variable de entorno de la que se lee su clave), `scaffoldModels` (un modelo de
scaffold por defecto por proveedor LLM), `providerTokenLimitKeys` (la clave de opción bajo la que cada
proveedor LLM recibe su límite de tokens de salida) y `supportedFormats` (el conjunto cerrado de ids de
formato). Lee la clave del límite de tokens de `providerTokenLimitKeys` en lugar de suponer una, porque
las claves difieren ([proveedores](https://verbatra.kreitz-webdev.de/es/docs/providers.md)); DeepL y Google Cloud Translation no tienen
entrada porque no reciben límite de tokens. El tipo `ScaffoldableProviderId` es
`Exclude<ProviderId, "openai-compatible" | "libretranslate" | "none">`: todos los proveedores que solo
necesitan su id. `openai-compatible` y `libretranslate` necesitan cada uno una `baseUrl` que solo tú
conoces y no tienen variable de entorno obligatoria, y `none` no llama a ningún proveedor.

```ts title="Firma"
const scaffoldingMetadata: {
  readonly providerEnv: { ... };
  readonly scaffoldModels: { ... };
  readonly providerTokenLimitKeys: { ... };
  readonly supportedFormats: readonly [...];
  readonly humanOnlyProviderId: "none";
  readonly openAiCompatibleKeyEnv: "OPENAI_COMPATIBLE_API_KEY";
  readonly libreTranslateKeyEnv: "LIBRETRANSLATE_API_KEY";
  readonly configSearchPlaces: readonly string[];
};
```

`scaffoldingMetadata.humanOnlyProviderId` es `"none"`, el id que desactiva la traducción automática. No tiene entrada en `providerEnv`, porque no lee ninguna clave.

<AvailableFrom version="0.12.0" />

`scaffoldingMetadata.libreTranslateKeyEnv` es `"LIBRETRANSLATE_API_KEY"`, la variable de la que un proveedor `libretranslate` lee su clave. Es opcional: un servidor iniciado sin `--api-keys` no necesita ninguna, así que un generador debería dejarla sin definir.

`scaffoldingMetadata.openAiCompatibleKeyEnv` es `"OPENAI_COMPATIBLE_API_KEY"`, la variable que lee un proveedor `openai-compatible` cuando sus opciones no nombran ningún `apiKeyEnvVar`. `scaffoldingMetadata.configSearchPlaces` lista cada nombre de archivo que `loadConfig` busca como configuración, en el orden en que los comprueba; un generador que escribe `verbatra.config.ts` debería negarse cuando ya existe otro de ellos, porque gana el primero que se encuentra.

### detectProject [#detectproject]

<AvailableFrom version="0.12.0" />

Detecta el formato de los archivos de locale de un proyecto y su estructura a partir de sus archivos, igual que hace `verbatra init` antes de escribir una configuración. No escribe nada y no llama a ningún proveedor. Recorre el directorio (saltándose los directorios ocultos, `node_modules` y la salida de compilación, dentro de una profundidad y un número de entradas acotados) en busca de archivos que reclame un adaptador registrado, encuentra en cada uno el segmento de la ruta que escribe un locale, y se queda con el patrón de archivo que cubre más locales. El formato es aquel cuyo adaptador reclama con `canHandle` cada archivo encontrado según su contenido; para JSON, donde todos los adaptadores JSON lo hacen, decide una única biblioteca de i18n coincidente en `package.json`.

```ts title="Firma"
function detectProject(
  input?: DetectProjectInput,
  deps?: DetectProjectDeps,
): Promise<ProjectDetection>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `cwd` | `string` | no | The directory to scan. Defaults to the process working directory. |
| `format` | `FormatId` | no | A format already chosen. Only files this format's adapter claims are considered. |
| `pattern` | `string` | no | A file pattern already chosen, containing the `{locale}` token. Only files matching it are considered, and no other layout is searched for. |
| `sourceLocale` | `string` | no | A source locale already chosen. It is reported as the layout's source locale unchanged. |

**Devuelve:** `ProjectDetection`

```ts title="Ejemplo"
import { detectProject } from "@verbatra/sdk";

const detection = await detectProject({ cwd: "/path/to/project" });
if (detection.ambiguities.length > 0) {
  // several formats or file patterns fit: choose one of detection.ambiguities[0].candidates
}
const format = detection.format?.id;          // for example "yaml"
const pattern = detection.layout?.pattern;    // for example "config/locales/{locale}.yml"
```

El resultado lleva `format` (con `from`: `input`, `files` o `dependencies`), `layout` (`pattern`, `localeStyle`, `locales`, `sourceLocale`, `files`, `unqualifiedSourceFile`), `ambiguities` (cada una con un `subject` de `format` o `layout` y sus `candidates`), una `confidence` de `high`, `medium`, `low` o `none`, y `reasons`, una frase por decisión. Los empates se informan como ambigüedades, nunca se adivinan. Las entradas opcionales `format`, `pattern` y `sourceLocale` acotan la búsqueda, y `deps.fs` y `deps.adapterRegistry` sustituyen el sistema de archivos y los adaptadores, así que también se detectan los archivos de un adaptador de terceros. Un archivo ausente, ilegible o malformado nunca lanza; solo deja el informe más escueto. `layout.unqualifiedSourceFile` nombra un archivo junto al layout con cadenas sin nombre de locale, como `messages.properties` o una plantilla `.pot` de gettext; entonces el locale de origen queda abierto, ya que el origen se lee del archivo que el patrón nombra para él.

### isMachineTranslationEnabled [#ismachinetranslationenabled]

<AvailableFrom version="0.12.0" />

Devuelve `false` exactamente cuando la configuración fija `provider: { id: "none" }`, el modo [solo humano](https://verbatra.kreitz-webdev.de/es/docs/human-only-workflow.md) en el que nunca se construye un proveedor ni se lee una clave de API. Una interfaz que ofrece acciones que gastan en el proveedor lo lee para omitirlas por completo; así es como Studio y el servidor MCP retienen el gasto incluso con `--allow-spend`.

```ts title="Firma"
function isMachineTranslationEnabled(
  config: Pick<VerbatraConfig, "provider">,
): boolean;
```

**Devuelve:** `boolean`

### assertMachineTranslationEnabled [#assertmachinetranslationenabled]

<AvailableFrom version="0.12.0" />

Recibe la configuración y una frase corta que nombra la acción, y lanza un `SdkError` `MACHINE_TRANSLATION_DISABLED` con `provider: { id: "none" }`. Llámalo antes de envolver `translate` en una acción explícita de "traducir todo lo pendiente", para que la acción falle igual que `retranslateEntry` en lugar de rellenar en silencio solo desde la memoria de traducción.

```ts title="Firma"
function assertMachineTranslationEnabled(
  config: Pick<VerbatraConfig, "provider">,
  action: string,
): void;
```

**Devuelve:** `void`

**Lanza:** [`MACHINE_TRANSLATION_DISABLED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#machine_translation_disabled)

### assertTargetLocale [#asserttargetlocale]

<AvailableFrom version="0.12.0" />

Recibe la configuración y un locale, y lanza un `SdkError` `UNKNOWN_LOCALE` cuando el locale no está entre los `targetLocales` configurados, con el mismo mensaje que usa cada función del SDK que acepta un filtro `locales`. Llámalo en una superficie que recibe un único locale propio, como hace `glossary.get` del servidor MCP, para que un locale incorrecto falle igual que en el SDK.

```ts title="Firma"
function assertTargetLocale(
  config: Pick<VerbatraConfig, "targetLocales">,
  locale: string,
): void;
```

**Devuelve:** `void`

**Lanza:** [`UNKNOWN_LOCALE`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#unknown_locale)
