---
title: "Konfiguration und Glossar"
description: "SDK-Einstiegspunkte, die die verbatra-Konfiguration laden und validieren und das Glossar bearbeiten, dazu einer, der erkennt, ob ein Ordner ein Projekt enthält."
type: "reference"
---
# Konfiguration und Glossar

SDK-Einstiegspunkte, die die verbatra-Konfiguration laden und validieren und das Glossar bearbeiten, dazu einer, der erkennt, ob ein Ordner ein Projekt enthält.

## Die Konfiguration laden [#konfiguration]

### loadConfig [#loadconfig]

Findet, lädt und validiert die Projektkonfiguration und gibt eine `VerbatraConfig` zurück.
`configOverride` (ein Objekt im Speicher validieren) geht vor
`configPath` (eine explizite Datei laden), das vor einer Suche ab `cwd` in der
[Suchreihenfolge](https://verbatra.kreitz-webdev.de/de/docs/config-file.md#suchreihenfolge) geht. Ein als Dateipfad angegebenes `glossary` wird hier
gelesen und validiert, sodass nachgelagerter Code immer ein Glossar im Speicher sieht: eine
Version-1-Zuordnung vom Quellbegriff zur Übersetzung oder eine Version-2-Definition.

```ts title="Signatur"
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`. |

**Rückgabe:** `VerbatraConfig`

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

**Beispiel:** [Eine Konfiguration ohne Datei](https://verbatra.kreitz-webdev.de/de/docs/programmatic-api.md#eine-konfiguration-ohne-datei)

Das Schema steht in [Konfigurationsdatei](https://verbatra.kreitz-webdev.de/de/docs/config-file.md). `fs`
ist der Dateisystem-Port, über den eine Glossardatei gelesen wird, wie unter
[Die Abhängigkeits-Nahtstelle](https://verbatra.kreitz-webdev.de/de/docs/sdk.md#die-abhängigkeits-nahtstelle) beschrieben.

### loadConfigWithMeta [#loadconfigwithmeta]

<AvailableFrom version="0.5.0" />

Dasselbe Laden, plus Herkunft: gibt `{ config, source, glossary }` zurück, wobei `source` sagt, ob
die Konfiguration aus einem Suchtreffer, einem expliziten Pfad oder einer Übersteuerung im
Speicher kam (mit dem absoluten `filepath`, wenn es einen gibt), und `glossary` festhält, ob das
Glossar fehlte, inline war oder aus einer Datei aufgelöst wurde. Nutze es, wenn du anzeigen musst,
woher die Konfiguration kam.

```ts title="Signatur"
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`. |

**Rückgabe:** `LoadedConfig`

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

Beide nehmen `fresh: true`, um eine JavaScript- oder TypeScript-Konfigurationsdatei neu auszuwerten,
statt wiederzuverwenden, was ein früheres Laden im selben Prozess ausgewertet hat; ein lang laufender
Prozess, der die Konfiguration nach einer Änderung neu lädt, setzt es. JSON-, YAML- und
`package.json`-Konfigurationen werden immer frisch gelesen. <AvailableFrom version="0.12.0" />

### configCandidatePaths [#configcandidatepaths]

<AvailableFrom version="0.12.0" />

Listet jede Datei, aus der `loadConfigWithMeta` mit denselben `{ cwd?, configPath? }` eine
Konfiguration lesen könnte: nur die explizite Datei, wenn `configPath` gesetzt ist, sonst jeden
Suchort in jedem Verzeichnis der Suchkette, das nächste zuerst, ob es die Datei gibt oder nicht.
Beobachte sie, etwa über die Änderungszeit, um eine angelegte, bearbeitete oder entfernte
Konfiguration zu bemerken, ohne sie bei jeder Anfrage zu laden. Die
Glossardatei ist nicht dabei; `loadConfigWithMeta` nennt sie in `glossary`.

```ts title="Signatur"
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. |

**Rückgabe:** `readonly string[]`

### resolveProjectRoot [#resolveprojectroot]

<AvailableFrom version="0.12.0" />

Gibt die Projektwurzel zurück, gegen die die Flows relative Pfade auflösen: das Verzeichnis der
gefundenen Konfigurationsdatei, sodass ein Prozess aus einem Unterverzeichnis mit den
Locale-Dateien, der Lock-Datei und `.verbatra-local/` des Projekts arbeitet, oder `cwd` bei einer
Konfiguration aus `configPath`. Ein Flow, der die Konfiguration aus `loadConfig` oder
`loadConfigWithMeta` bekommt, nimmt diese Wurzel schon als Standard für `cwd`. Übergib `resolveProjectRoot(loaded.source, cwd)`
als `cwd`, wenn du die Konfiguration kopierst oder neu baust, und an `loadLockFile`,
`loadProvenance` und `runStatus`, die keine Konfiguration nehmen.

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

**Rückgabe:** `string`

## Glossar [#glossar]

### readGlossaryFile [#readglossaryfile]

<AvailableFrom version="0.9.0" />

Liest ein dateibasiertes Glossar frisch von der Festplatte und gibt es als normalisiertes `Glossary`
zurück: `{ version, terms, doNotTranslate }`, wobei `version` für eine flache Begriffszuordnung `1`
und für ein [Glossar pro Locale](https://verbatra.kreitz-webdev.de/de/docs/config-file.md#glossary) `2` ist und jeder Begriff `source`, ein
optionales `target`, `targets`, `forbidden`, `caseSensitive` sowie optional `note` und
`partOfSpeech` trägt. Die Eingabe `glossary` ist die `GlossaryProvenance` aus `loadConfigWithMeta`,
sodass die gelesene Datei immer die ist, die die Konfiguration nennt; ein Pfadargument gibt es
nicht. Nutze es in einem lang laufenden Werkzeug, das das Glossar zeigt, wie es jetzt ist, nicht wie
beim Laden.

```ts title="Signatur"
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. |

**Rückgabe:** `Glossary`

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

Wirft `GLOSSARY_NOT_FILE_BACKED`, wenn das Glossar inline oder gar nicht vorhanden ist, und
`CONFIG_INVALID`, wenn die Datei gegen die [Regeln für Glossardateien](https://verbatra.kreitz-webdev.de/de/docs/config-file.md#glossary)
verstößt oder eine andere Version angibt.

<AvailableFrom version="0.12.0" />

Bis 0.11 gab es die flache Begriffszuordnung selbst zurück.

### updateGlossaryTerm [#updateglossaryterm]

<AvailableFrom version="0.9.0" />

Fügt genau einen Begriff zu einem dateibasierten Glossar hinzu, ändert ihn oder entfernt ihn, und
gibt das normalisierte Glossar in seinem neuen Stand zurück. `translation`
ist der neue Text oder `null`, um den
Begriff zu entfernen. Der Rest der Datei behält seine Key-Reihenfolge und seine Einrückung, der
Schreibvorgang ist atomar, und das gesamte Lesen, Ändern und Schreiben läuft unter einer
projektweiten Glossarsperre, sodass zwei gleichzeitige Änderungen serialisiert statt verschränkt
werden.

```ts title="Signatur"
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. |

**Rückgabe:** `Glossary`

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

<AvailableFrom version="0.12.0" />

Es nimmt außerdem `locale` (dann ist `translation` die eigene Übersetzung dieser Locale und `null`
entfernt nur sie), `forbidden` (die Wiedergaben, die `locale` nie verwenden darf; `null` oder `[]`
entfernt sie), `note`, `partOfSpeech` (jeweils `null` zum Entfernen), `caseSensitive` und
`doNotTranslate` (`true` nimmt den Begriff in die unübersetzten Begriffe auf, `false` entfernt ihn;
es lässt sich nicht mit den Begriffsfeldern kombinieren). Eine Datei der Version 1 bleibt Version 1,
solange eine Änderung nur eine Übersetzung für alle Locales setzt oder entfernt; jede andere
Änderung schreibt sie als Version 2 neu, wobei jeder bestehende Begriff seine Übersetzung als
`target` behält. `translation: null` ohne `locale` entfernt jetzt nur die gemeinsame Übersetzung; der Begriff selbst wird entfernt, sobald ihm keine Übersetzung und keine verbotene Wiedergabe mehr bleibt, bei einem Begriff der Version 1 also sofort.

Ein Inline-Glossar wird mit `GLOSSARY_NOT_FILE_BACKED` abgelehnt statt umgewandelt: Es liegt in
einem ausführbaren Konfigurationsmodul. Ein leeres Feld, eine Änderung, die kein Feld setzt oder
`doNotTranslate` mit Begriffsfeldern mischt, verbotene Wiedergaben ohne Locale, eine ungültige
Locale, eine Änderung, die ein ungültiges Glossar hinterließe, und eine Änderung, deren Ergebnis
die Glossargrenze von 1 MiB überschreiten würde, werden mit `CONFIG_INVALID` abgelehnt; ein
fehlgeschlagener Schreibvorgang, auch eine Glossar-Schreibsperre, die sich in einem schreibgeschützten Projekt nicht anlegen oder nach einer gespeicherten Änderung nicht freigeben lässt, ist `GLOSSARY_UNWRITABLE`, mit dem Dateisystem-Fehler als `cause`. Eine Änderung, die das Glossar so lässt,
wie es schon ist, gelingt und schreibt nichts.

<AvailableFrom version="0.12.0" />

Es nimmt außerdem `lockAcquireTimeoutMs`, das die Wartezeit auf die Glossarsperre begrenzt, bevor der Aufruf mit `LOCK_CONTENDED` scheitert (standardmäßig zehn Minuten); eine ungültige Grenze scheitert mit `LOCK_TIMEOUT_INVALID`, bevor etwas gelesen wird.

### glossaryForLocale [#glossaryforlocale]

<AvailableFrom version="0.12.0" />

Löst den Teil eines Glossars auf, der für eine Ziel-Locale gilt:
`glossaryForLocale(config.glossary, "de")` gibt `{ terms, doNotTranslate }` zurück, jeden Begriff
mit dem `target` der Locale (ihr eigener Eintrag, dann der ihrer Basissprache, dann der gemeinsame),
seinen `forbidden`-Wiedergaben, `caseSensitive` sowie `note` und `partOfSpeech`, oder `undefined`,
wenn nichts im Glossar dort gilt. Genau das trägt eine Übersetzungsanfrage in diese Locale als
[`TranslateRequest.glossary`](https://verbatra.kreitz-webdev.de/de/docs/sdk/extend.md#eigene-provider), und genau das sehen die Review-Prüfungen und der Cache-Fingerprint
dieser Locale.

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

**Rückgabe:** `LocaleGlossary | undefined`

### glossaryHits [#glossaryhits]

<AvailableFrom version="0.12.0" />

`glossaryHits({ glossary, locale, sourceLocale, source })` gibt die Glossareinträge zurück, die für
einen Quelltext in einer Ziel-Locale gelten, als `{ terms, doNotTranslate }` in der Form, die
`glossaryForLocale` liefert: jeden Begriff, dessen Quelle als ganzer Begriff in `source` vorkommt,
mit der Übersetzung und den verbotenen Wiedergaben, an die diese Locale gebunden ist, und jeden
unübersetzt zu lassenden Begriff, der darin vorkommt. Ein Begriff passt mit oder ohne
Groß-/Kleinschreibung, wie er es angibt, wobei für `sourceLocale` gefaltet wird. Er nutzt dieselbe
Zuordnung, mit der ein Übersetzungslauf einen verpassten Glossarbegriff markiert, und liest nichts.

```ts title="Signatur"
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. |

**Rückgabe:** `LocaleGlossary`

### glossaryDraftCheck [#glossarydraftcheck]

<AvailableFrom version="0.12.0" />

`glossaryDraftCheck({ glossary, locale, sourceLocale, source, draft })` prüft einen Entwurf einer
Übersetzung gegen die Glossareinträge, die `glossaryHits` im Quelltext findet, bevor du ihn
schreibst. Jeder Begriff kommt mit `targetUsed` zurück (ob der Entwurf die vorgeschriebene
Übersetzung enthält; fehlt bei einem Begriff, der nur Wiedergaben verbietet) und mit
`forbiddenUsed` (die verbotenen Wiedergaben, die der Entwurf nutzt und die Quelle nicht), und jeder
unübersetzt zu lassende Begriff mit `kept`. Das sind die Regeln, mit denen ein Übersetzungslauf
`GLOSSARY_TERM_MISSED` und `GLOSSARY_FORBIDDEN_TERM` markiert. Es liest nichts.

```ts title="Signatur"
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. |

**Rückgabe:** `GlossaryDraftCheck`

### normalizeGlossary [#normalizeglossary]

<AvailableFrom version="0.12.0" />

Wandelt ein Glossar in beiden Formen, eine flache Zuordnung der Version 1 oder eine Definition der
Version 2, in das normalisierte `Glossary` um, das `readGlossaryFile` zurückgibt, mit allen
Standardwerten. Nutze es, um ein Inline-Glossar genauso anzuzeigen wie ein dateibasiertes. Es
validiert nicht erneut; das hat `loadConfig` schon getan.

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

**Rückgabe:** `Glossary`

### sharedGlossaryTranslations [#sharedglossarytranslations]

<AvailableFrom version="0.12.0" />

Bildet ein normalisiertes `Glossary` auf eine flache Zuordnung ab: jeder Begriff mit einem
gemeinsamen `target` zu dieser Übersetzung, in Glossarreihenfolge. Übersetzungen pro Locale,
verbotene Wiedergaben und Begriffe aus `doNotTranslate` fehlen darin, nutze es also nur dort, wo
ein Verbraucher nichts als eine flache Begriffszuordnung zeigen kann. Ein Begriff namens
`__proto__` bleibt ein eigener Key.

```ts title="Signatur"
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. |

**Rückgabe:** `Readonly<Record<string, string>>`

### redactGlossary [#redactglossary]

<AvailableFrom version="0.12.0" />

Schickt jeden Quellbegriff, jede Übersetzung, verbotene Wiedergabe, Notiz, Wortart und jeden Begriff
aus `doNotTranslate` eines normalisierten `Glossary`
durch `redact` und gibt `{ glossary, redactedTerms }` zurück, wobei `redactedTerms` jeden Begriff
nennt, bei dem ein Wert ersetzt wurde, einen geschwärzten Quellbegriff selbst als `[REDACTED]`, damit
die Liste nie ein Secret wiederholt. Der MCP-Server und Studio nutzen es, bevor ein Glossar den Prozess verlässt; nutze es in
deinem eigenen Werkzeug genauso.

```ts title="Signatur"
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. |

**Rückgabe:** `RedactedGlossary`

### readCurrentGlossary [#readcurrentglossary]

<AvailableFrom version="0.12.0" />

Liest das Glossar, das eine geladene Konfiguration nennt, so wie es jetzt ist:
`readCurrentGlossary({ loaded })`, wobei `loaded` das ist, was `loadConfigWithMeta`
zurückgibt. Ein dateibasiertes Glossar wird frisch von der Festplatte gelesen, ein Inline-Glossar
kommt aus der Konfiguration, und in beiden Fällen ist das Ergebnis das normalisierte `Glossary` oder
`undefined`, wenn die Konfiguration keins angibt. Um zu sehen, woran eine Ziel-Locale gebunden ist,
gib das Ergebnis an `glossaryForLocale` weiter.

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

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

**Rückgabe:** `Glossary | undefined`

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

### editConfiguredGlossaryTerm [#editconfiguredglossaryterm]

<AvailableFrom version="0.12.0" />

`updateGlossaryTerm` für ein Werkzeug mit geladener Konfiguration: nimmt `loaded` statt `glossary`
mit denselben Änderungsfeldern, behandelt ein auf `undefined` gelassenes Feld als nicht angegeben
und prüft `locale` zuerst gegen die konfigurierten Ziel-Locales; ist es keine davon, scheitert es mit
`UNKNOWN_LOCALE` und schreibt nichts. Der MCP-Server und Studio schreiben das Glossar darüber.

```ts title="Signatur"
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. |

**Rückgabe:** `Glossary`

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

## Schreiben, Erkennen und rein menschlicher Modus [#schreiben-erkennen-und-rein-menschlicher-modus]

### defineConfig [#defineconfig]

Ein Identitätshelfer für eine typisierte `verbatra.config.ts`: er gibt sein Argument unverändert
zurück, für Typinferenz und Editor-Autovervollständigung, einschließlich der bekannten Modell-IDs
des gewählten Providers (nur beim Schreiben; zur Laufzeit besteht jeder nicht-leere String). Jeder
Provider außer `opencode`, `openai-compatible`, `libretranslate` und `none` bekommt zusätzlich eine Überladung
mit `AuthoringConfigFor<"<id>">`, etwa `AuthoringConfigFor<"anthropic">`, die den `provider`-Block
auf die Optionen dieses Providers einschränkt; diese vier nutzen den Rückfall mit `AuthoringConfig`
unten.

```ts title="Signatur"
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;
```

**Rückgabe:** `VerbatraConfigInput`

**Beispiel:** [Eine Quelldatei und eine Konfiguration anlegen](https://verbatra.kreitz-webdev.de/de/docs/sdk-quickstart.md#eine-quelldatei-und-eine-konfiguration-anlegen)

### verbatraConfigSchema [#verbatraconfigschema]

Das zod-Schema, mit dem `loadConfig` validiert, exportiert, damit dein eigenes Tooling ein
Konfigurationsobjekt genauso validieren kann wie das SDK. Unbekannte Top-Level-Keys werden
abgelehnt, ein verirrtes Secret kann sich also nicht in der Konfiguration verstecken, außer
`$schema`: ein optionaler, zur Laufzeit ignorierter String, mit dem eine JSON- oder
YAML-Konfiguration einen Editor auf das mitgelieferte `@verbatra/sdk/config-schema.json` zeigt.

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

Der `rates`-Block ist eine `RateCard`, die Preisliste, die eine [Schätzung](https://verbatra.kreitz-webdev.de/de/docs/estimating-cost.md) in Geld umrechnet:

| 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" />

Nur lesbare Metadaten, aus denen der CLI-Befehl `init` seine Abfragen ableitet:
`providerEnv` (Provider-ID zur Umgebungsvariable, aus der sein Key gelesen wird),
`scaffoldModels` (ein Standard-Scaffold-Modell pro LLM-Provider), `providerTokenLimitKeys` (der
Option-Key, unter dem jeder LLM-Provider sein Ausgabe-Token-Limit entgegennimmt) und
`supportedFormats` (die geschlossene Menge der Format-IDs). Lies den Token-Limit-Key aus
`providerTokenLimitKeys`, statt einen anzunehmen, denn die Keys unterscheiden sich
([Provider](https://verbatra.kreitz-webdev.de/de/docs/providers.md)); DeepL und Google Cloud Translation haben keinen Eintrag, weil sie kein
Token-Limit entgegennehmen. Der Typ `ScaffoldableProviderId` ist
`Exclude<ProviderId, "openai-compatible" | "libretranslate" | "none">`: jeder Provider, der nur
seine Id braucht. `openai-compatible` und `libretranslate` brauchen je eine `baseUrl`, die nur du
kennst, und haben keine verpflichtende Umgebungsvariable, und `none` ruft gar keinen Provider auf.

```ts title="Signatur"
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` ist `"none"`, die ID, die Maschinenübersetzung abschaltet. Sie hat keinen Eintrag in `providerEnv`, weil sie keinen Key liest.

<AvailableFrom version="0.12.0" />

`scaffoldingMetadata.libreTranslateKeyEnv` ist `"LIBRETRANSLATE_API_KEY"`, die Variable, aus der ein `libretranslate`-Provider seinen Key liest. Sie ist optional: Ein Server, der ohne `--api-keys` gestartet wurde, braucht keinen, ein Generator sollte sie also nicht setzen.

`scaffoldingMetadata.openAiCompatibleKeyEnv` ist `"OPENAI_COMPATIBLE_API_KEY"`, die Variable, die ein `openai-compatible`-Provider liest, wenn seine Optionen kein `apiKeyEnvVar` nennen. `scaffoldingMetadata.configSearchPlaces` listet jeden Dateinamen, unter dem `loadConfig` nach einer Konfiguration sucht, in der Reihenfolge, in der es sie prüft; ein Generator, der `verbatra.config.ts` schreibt, sollte ablehnen, wenn eine andere davon schon existiert, weil die zuerst gefundene gewinnt.

### detectProject [#detectproject]

<AvailableFrom version="0.12.0" />

Erkennt Format und Layout der Locale-Dateien eines Projekts anhand seiner Dateien, so wie `verbatra init` es tut, bevor es eine Konfiguration schreibt. Es schreibt nichts und ruft keinen Provider auf. Es durchsucht das Verzeichnis (versteckte Verzeichnisse, `node_modules` und Build-Ausgabe ausgenommen, mit begrenzter Tiefe und Eintragszahl) nach Dateien, die ein registrierter Adapter beansprucht, findet in jeder das Pfadsegment, das eine Locale ausschreibt, und behält das Dateimuster, das die meisten Locales abdeckt. Das Format ist dasjenige, dessen Adapter mit `canHandle` jede gefundene Datei anhand ihres Inhalts beansprucht; bei JSON, wo das jeder JSON-Adapter tut, entscheidet eine einzelne passende i18n-Bibliothek in `package.json`.

```ts title="Signatur"
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. |

**Rückgabe:** `ProjectDetection`

```ts title="Beispiel"
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"
```

Das Ergebnis trägt `format` (mit `from`: `input`, `files` oder `dependencies`), `layout` (`pattern`, `localeStyle`, `locales`, `sourceLocale`, `files`, `unqualifiedSourceFile`), `ambiguities` (jeweils mit einem `subject` von `format` oder `layout` und seinen `candidates`), eine `confidence` von `high`, `medium`, `low` oder `none` und `reasons`, einen Satz pro Entscheidung. Gleichstände werden als Mehrdeutigkeiten gemeldet, nie geraten. Die optionalen Eingaben `format`, `pattern` und `sourceLocale` grenzen die Suche ein, und `deps.fs` und `deps.adapterRegistry` tauschen Dateisystem und Adapter aus, sodass auch die Dateien eines Drittanbieter-Adapters erkannt werden. Eine fehlende, unlesbare oder fehlerhafte Datei wirft nie; der Bericht wird nur dünner. `layout.unqualifiedSourceFile` nennt eine Datei neben dem Layout mit Strings unter keinem Locale-Namen, etwa `messages.properties` oder eine gettext-Vorlage `.pot`; die Quell-Locale bleibt dann offen, da die Quelle aus der Datei gelesen wird, die das Muster dafür benennt.

### isMachineTranslationEnabled [#ismachinetranslationenabled]

<AvailableFrom version="0.12.0" />

Gibt genau dann `false` zurück, wenn die Konfiguration `provider: { id: "none" }` setzt, den [rein menschlichen](https://verbatra.kreitz-webdev.de/de/docs/human-only-workflow.md) Modus, in dem nie ein Provider erzeugt und kein API-Key gelesen wird. Eine Oberfläche, die kostenpflichtige Provider-Aktionen anbietet, liest es, um sie ganz wegzulassen. So halten Studio und der MCP-Server Ausgaben auch mit `--allow-spend` zurück.

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

**Rückgabe:** `boolean`

### assertMachineTranslationEnabled [#assertmachinetranslationenabled]

<AvailableFrom version="0.12.0" />

Nimmt die Konfiguration und eine kurze Beschreibung der Aktion und wirft unter `provider: { id: "none" }` einen `SdkError` mit `MACHINE_TRANSLATION_DISABLED`. Ruf es auf, bevor du `translate` in eine ausdrückliche Aktion "alles Ausstehende übersetzen" verpackst, damit diese Aktion genauso fehlschlägt wie `retranslateEntry`, statt still nur aus dem Translation Memory zu füllen.

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

**Rückgabe:** `void`

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

### assertTargetLocale [#asserttargetlocale]

<AvailableFrom version="0.12.0" />

Nimmt die Konfiguration und eine Locale und wirft einen `SdkError` mit `UNKNOWN_LOCALE`, wenn die Locale nicht zu den konfigurierten `targetLocales` gehört, mit derselben Meldung, die jede SDK-Funktion mit einem `locales`-Filter verwendet. Ruf es in einer Oberfläche auf, die selbst eine einzelne Locale annimmt, wie `glossary.get` im MCP-Server, damit eine falsche Locale genauso fehlschlägt wie im SDK.

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

**Rückgabe:** `void`

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