---
title: "Übergabe und Austausch"
description: "SDK-Einstiegspunkte für Import und Export von Arbeitsmappen und TMX, dazu Schnappschüsse von Locale-Dateien und die Pfade, die verbatra je Locale auflöst."
type: "reference"
---
# Übergabe und Austausch

SDK-Einstiegspunkte für Import und Export von Arbeitsmappen und TMX, dazu Schnappschüsse von Locale-Dateien und die Pfade, die verbatra je Locale auflöst.

<SdkAnchorForward />

## Locale-Datei-Schnappschüsse [#locale-datei-schnappschüsse]

Die Bausteine eines Live-Refresh-Watchers wie dem von Studio: den Zustand einer Locale-Datei
erfassen und dann zählen, was sich seitdem geändert hat.

### readLocaleFileSnapshot [#readlocalefilesnapshot]

<AvailableFrom version="0.5.0" />

Liest eine Locale-Datei (die Quell-Locale oder eine beliebige Ziel-Locale) und reduziert sie auf
einen Inhalts-Hash pro Key. Eine noch nicht existierende Datei liest sich als leerer Schnappschuss,
statt zu werfen.

```ts title="Signatur"
function readLocaleFileSnapshot(
  input: ReadLocaleFileSnapshotInput,
  deps?: ReadLocaleFileSnapshotDeps,
): Promise<LocaleFileSnapshot>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `locale` | `string` | yes | The locale file to snapshot. Unlike most entry points this is not checked against the configured target locales, so the source locale can be snapshotted too. |
| `cwd` | `string` | no | Directory the `files.pattern` is resolved against. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |

**Rückgabe:** `LocaleFileSnapshot`

**Wirft:** [`UNKNOWN_FORMAT`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#unknown_format), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_path_collision)

Gibt `{ locale, hashes }` zurück.

### diffLocaleSnapshots [#difflocalesnapshots]

<AvailableFrom version="0.5.0" />

Vergleicht zwei Schnappschüsse derselben Datei zu verschiedenen Zeitpunkten und zählt die
zwischen ihnen hinzugefügten, geänderten und entfernten Keys. Eine schlichte synchrone Funktion:
`diffLocaleSnapshots(previous, current)` gibt `{ added, changed, removed }` zurück. Nur Zähler,
nie Key-Namen.

```ts title="Signatur"
function diffLocaleSnapshots(
  previous: LocaleFileSnapshot,
  current: LocaleFileSnapshot,
): LocaleSnapshotDelta;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `locale` | `string` | yes | The locale this snapshot was taken for. |
| `hashes` | `ReadonlyMap<string, string>` | yes | Content hash per key, in the order the adapter read them. |

**Rückgabe:** `LocaleSnapshotDelta`

## Locale-Pfade [#locale-pfade]

### createLocalePathResolver [#createlocalepathresolver]

<AvailableFrom version="0.7.0" />

Löst die Locale-zu-Pfad-Zuordnung des Projekts in beide Richtungen auf, aus `files.pattern`, den
konfigurierten Locales und `files.localeStyle`. `createLocalePathResolver(cwd, config)` liefert
`{ pathFor, localeFor }`: `pathFor(locale)` ist der absolute Pfad der Datei einer Locale, und
`localeFor(path)` ist die Locale, zu der ein Pfad gehört, oder `undefined` für einen Pfad, der
nicht zu diesem Projekt gehört, und bei einem Format mit gemeinsamem Katalog wie `apple-xcstrings` immer `undefined`. Jeder SDK-Einstiegspunkt löst Pfade darüber auf, sodass ein
Watcher oder ein Dashboard auf Basis des SDK genau die Pfade sieht, die ein Lauf schreibt.

```ts title="Signatur"
function createLocalePathResolver(
  cwd: string,
  config: LocalePathResolverConfig,
): LocalePathResolver;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `sourceLocale` | `string` | yes | The source locale, which some styles spell differently from the targets. |
| `targetLocales` | `readonly string[]` | yes | Every target locale. All of them are mapped up front so collisions are caught immediately. |
| `format` | `FormatId` | yes | The configured format. Every format maps each locale to a distinct path except a shared-catalogue format (one holding every locale in a single file, such as `apple-xcstrings`), which maps every locale to the same path. A `custom:` format is always treated as one file per locale. Under the `posix` locale style, the `gettext-po` format also spells a script the gettext way (`sr-Latn` as `sr@latin`) rather than the ICU way (`sr_Latn`). |
| `files` | `object` | yes | The file layout. |

**Rückgabe:** `LocalePathResolver`

**Wirft:** [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_path_collision)

Alle Prüfungen laufen beim Erzeugen des Resolvers, bevor eine Datei gelesen wird: ein Pattern und
ein Style, die sich nicht kombinieren lassen, oder eine Locale, für die der Style keine korrekte
Schreibweise hat, werfen `LOCALE_LAYOUT_INVALID`; zwei Locales, die auf denselben Pfad auflösen,
werfen `LOCALE_PATH_COLLISION`.

## Das Arbeitsmappen-Paar [#das-arbeitsmappen-paar]

Die Übergabe für menschliche Übersetzerinnen, als Excel-Arbeitsmappe oder als Text mit
Trennzeichen; siehe [Menschliche Übersetzung](https://verbatra.kreitz-webdev.de/de/docs/manual-translation.md).

### exportWorkbook [#exportworkbook]

<AvailableFrom version="0.2.0" />

Schreibt die noch zu übersetzenden Strings (fehlende und geänderte Keys pro Locale; unveränderte
kommen mit `includeUnchanged` dazu) in eine formatierte `.xlsx`-Arbeitsmappe. Die Zeilen tragen
dasselbe Review-Flag-Signal, das ein translate-Lauf berechnet. Kein Provider-Aufruf, kein
Lock-Schreiben.

```ts title="Signatur"
function exportWorkbook(
  input: ExportWorkbookInput,
  deps?: ExportWorkbookDeps,
): Promise<ExportWorkbookResult>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `cwd` | `string` | no | Directory the `files.pattern` and `out` are resolved against. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |
| `out` | `string` | no | Where to write the handoff. Defaults to DEFAULT_WORKBOOK_PATH for `xlsx` and to DEFAULT_DELIMITED_PATH for the delimited and XLIFF formats. Refused with `EXPORT_OUTPUT_CONFLICT`, before anything is read or written, when it resolves outside `cwd`, or when it or a file the export would write names a configured locale file, the lock file, the provenance file, the translation-memory cache, a file verbatra searches for its configuration, the ExportWorkbookInput.configPath file, or the ExportWorkbookInput.glossaryPath file. For `xlsx` it is also refused when it names no file (including one ending in a path separator) or names `cwd` itself; a delimited or XLIFF export may write into `cwd`. Names are compared case-insensitively, and, when the file-system port implements `realpath`, again after symbolic links are resolved, so a link cannot carry the handoff anywhere a plain path could not. |
| `configPath` | `string` | no | The configuration file `config` was loaded from, absolute or relative to `cwd`. It is refused as the output path even when its name is not one verbatra searches for. |
| `glossaryPath` | `string` | no | The glossary file the config names, absolute or relative to `cwd`, normally the `path` of a file-backed LoadedConfig.glossary. It is refused as the output path. |
| `locales` | `readonly string[]` | no | Restrict the export to these target locales. Defaults to every configured target locale. |
| `includeUnchanged` | `boolean` | no | Include keys that are already up to date, not just the missing and stale ones. Useful when a translator needs the surrounding context to translate consistently. Defaults to false. |
| `format` | `ExchangeFormat` | no | The handoff shape to write. Defaults to `xlsx`. |

**Rückgabe:** `ExportWorkbookResult`

**Wirft:** [`UNKNOWN_FORMAT`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#unknown_format), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_path_collision), [`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#source_unreadable), [`SOURCE_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#source_invalid), [`LOCK_FILE_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#lock_file_invalid), [`UNKNOWN_LOCALE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#unknown_locale), [`EXPORT_OUTPUT_CONFLICT`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#export_output_conflict), [`EXPORT_UNWRITABLE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#export_unwritable)

**Beispiel:** [Der Arbeitsmappen-Roundtrip](https://verbatra.kreitz-webdev.de/de/docs/programmatic-api.md#der-arbeitsmappen-roundtrip)

`format` ist standardmäßig
`xlsx`; `csv` und `tsv` schreiben stattdessen eine `<locale>.csv` bzw. `<locale>.tsv` pro Locale, `out`
benennt dafür also ein Verzeichnis (das angelegt wird, falls es fehlt) und bei `xlsx` einen Dateipfad.
`out` ist standardmäßig `DEFAULT_WORKBOOK_PATH` (`verbatra-translations.xlsx`) oder, bei den
Getrennt- und XLIFF-Formaten, `DEFAULT_DELIMITED_PATH` (`verbatra-translations`), beide als Konstanten exportiert. Die zulässigen Werte werden als `EXCHANGE_FORMATS` und der Standardwert als `DEFAULT_EXCHANGE_FORMAT` exportiert, damit ein Werkzeug, das als Wrapper über dem SDK sitzt, ein Format-Argument prüfen kann, ohne die Liste fest zu verdrahten. Gibt
`{ path, locales }` zurück: den absoluten geschriebenen Pfad und eine Zeilenzahl pro Locale.

Bevor irgendetwas gelesen wird, weist `EXPORT_OUTPUT_CONFLICT` ein `out` zurück, das außerhalb von
`cwd` landet, und eines, das selbst oder über eine Datei, die der Export hineinschreiben würde, eine
konfigurierte Locale-Datei, die Lock-Datei, die Herkunftsdatei, den Übersetzungsspeicher-Cache, eine
Datei, nach der verbatra seine Konfiguration sucht, die `configPath`-Datei oder die
`glossaryPath`-Datei benennt, ohne Beachtung der Groß- und Kleinschreibung und, wenn `deps.fs`
`realpath` implementiert wie die Voreinstellung, noch einmal nach dem Auflösen symbolischer Links.
Ein `xlsx`-Pfad wird außerdem abgelehnt, wenn er keine Datei benennt (auch einer, der auf ein
Pfadtrennzeichen endet) oder `cwd` selbst benennt; ein `csv`-, `tsv`- oder XLIFF-Verzeichnis darf `cwd`
sein. Scheitert das Schreiben, weil das Verzeichnis nicht schreibbar ist, ein Verzeichnis oder eine
Datei im Weg liegt oder die Platte voll ist, wirft es `EXPORT_UNWRITABLE` mit der Datei und dem
Dateisystem-Code in der Message und dem Dateisystem-Fehler als `cause`.

<AvailableFrom version="0.12.0" />

`format: "xliff2"` und `format: "xliff12"` schreiben für ein CAT-Tool eine XLIFF-2.0- bzw. 1.2-Datei `<locale>.xlf` pro Locale in das Verzeichnis `out`: eine Unit pro Key, Platzhalter und Markup als geschützte `<ph>`-Inline-Codes, Beschreibung und Bedeutung des Keys als Notizen, den Quell-Hash in den Metadaten der Unit und einen Segmentstatus aus dem Lock- und Review-Status (`initial` für einen fehlenden oder veralteten Key, `translated` wenn aktuell, `reviewed` wenn freigegeben). Beide Typen werden exportiert, `XliffFormat` benennt die zwei XLIFF-Mitglieder von `ExchangeFormat`. Siehe [An eine Übersetzungsagentur übergeben](https://verbatra.kreitz-webdev.de/de/docs/translation-agency.md).

Jede Unit mit einem Ziel trägt außerdem ihre Herkunft: XLIFF 1.2 kennzeichnet ein nicht freigegebenes Ziel der maschinellen Klasse mit `state-qualifier="mt-suggestion"`, und XLIFF 2.0 ergänzt die `verbatra`-Metagruppe der Unit um die Einträge `origin` und `review-state`. Das Ergebnis trägt dann auch `provenanceMarkers`: `"written"`, oder `"unavailable"`, wenn sich die Herkunftsdatei nicht lesen ließ und keine Markierung geschrieben wurde. Siehe [Nachweis maschineller Übersetzungen](https://verbatra.kreitz-webdev.de/de/docs/provenance-evidence.md#markierungen-in-exporten).

### importWorkbook [#importworkbook]

<AvailableFrom version="0.2.0" />

Liest eine ausgefüllte Arbeitsmappe zurück in die Locale-Dateien und führt dieselben Prüfungen auf
Quelldrift und Integrität aus wie `translate`. Nur akzeptierte Zeilen rücken ihre
Lock-Baseline vor; eine leere oder abgelehnte Zeile wird weiter exportiert, bis sie wirklich
erledigt ist.

```ts title="Signatur"
function importWorkbook(
  input: ImportWorkbookInput,
  deps?: ImportWorkbookDeps,
): Promise<RunSummary>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `workbook` | `string` | yes | Path to the filled handoff. For a delimited or XLIFF import the path is tried as a single file first, so one individual `<locale>.<csv\|tsv\|xlf>` file can be imported on its own, with the locale taken from its file name. A single XLIFF file whose name is not a configured target locale is matched by the target language it declares instead. If no file exists there, the path is treated as the directory the per-locale files were written into and every configured target locale found inside is read. |
| `cwd` | `string` | no | Directory the `files.pattern` and `workbook` are resolved against. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |
| `dryRun` | `boolean` | no | Read and validate the handoff but write nothing. The returned RunSummary reports what would have been applied, which is the safe way to inspect a handoff before trusting it. Defaults to false. |
| `format` | `ExchangeFormat` | no | The handoff shape to read. Defaults to the shape the extension of ImportWorkbookInput.workbook names: `csv` for `.csv`, `tsv` for `.tsv`, `xliff2` for `.xlf` or `.xliff`, and `xlsx` for `.xlsx` or any other file. For a directory it is the format of the export manifest inside, else of the `<locale>` files inside; a directory holding two formats, or none, is refused. `xliff2` and `xliff12` both read either XLIFF version, which is taken from the file. |
| `reviewer` | `string` | no | Free text naming the reviewer, 1 to 64 characters with no control characters, recorded on each value an XLIFF handoff marks `reviewed` or `final` (1.2: `signed-off`, `final`, or `approved="yes"`). It is stored in the committed provenance file, so it is public. Other handoff formats carry no review state, so it is not used for them. |
| `onLockWait` | `LockWaitListener` | no | Called while waiting on another process's write lock, so a CLI can explain a stall instead of appearing to hang. Never called for a lock this process holds itself. |
| `lockAcquireTimeoutMs` | `number` | no | How long, in milliseconds, to wait for a locale's write lock before that locale fails with `LOCK_CONTENDED`. The wait happens before the locale file is written. Defaults to ten minutes. It does not bound the lock-file guard a locale takes to record its result once its target file is written: that wait always allows the ten-minute default, so a written file is not left unrecorded. Not used on a dry run, which takes no lock. |

**Rückgabe:** [`RunSummary`](https://verbatra.kreitz-webdev.de/de/docs/sdk/run-summary.md)

**Wirft:** [`LOCK_TIMEOUT_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#lock_timeout_invalid), [`REVIEWER_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#reviewer_invalid), [`UNKNOWN_FORMAT`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#unknown_format), [`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#source_unreadable), [`SOURCE_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#source_invalid), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_path_collision), [`LOCK_FILE_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#lock_file_invalid), [`PROVENANCE_FILE_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#provenance_file_invalid)

**Beispiel:** [Der Arbeitsmappen-Roundtrip](https://verbatra.kreitz-webdev.de/de/docs/programmatic-api.md#der-arbeitsmappen-roundtrip)

Bei `csv` und `tsv` ist `workbook` entweder
eine einzelne Übergabedatei oder das Verzeichnis mit einer Datei pro Locale, und die Locale kommt aus
dem Dateinamen. Eine Datei auf `.csv` oder `.tsv` wird ohne `format` in diesem Format gelesen, ein Verzeichnis im Format seines Export-Manifests oder seiner Locale-Dateien. Gibt dieselbe `RunSummary`-Form zurück wie
`translate` (mit `needsReview` immer leer, da kein Provider beteiligt ist). Ein Blatt für eine
Locale, die kein konfiguriertes Ziel ist, lässt diese Locale mit `CONFIG_INVALID` als Daten auf der
Zusammenfassung fehlschlagen, statt zu werfen.

<AvailableFrom version="0.12.0" />

`onLockWait` und `lockAcquireTimeoutMs` verhalten sich genau wie bei `translate`.
`lockAcquireTimeoutMs` begrenzt das Warten auf die Schreibsperre einer Locale, die genommen wird,
bevor die Datei dieser Locale geschrieben wird. Eine Locale, deren Sperre danach noch belegt ist,
schlägt mit `LOCK_CONTENDED` auf ihrer eigenen Zusammenfassung fehl, während die anderen Locales
importiert werden. Das Eintragen einer geschriebenen Datei in die Lock-Datei wartet immer bis zum
Standard von zehn Minuten. Ein Dry-Run nimmt keine Sperre, daher gilt keine der beiden Optionen für
ihn.

<AvailableFrom version="0.12.0" />

`integrityRefusals` jeder Locale nennt die Zeilen, die das Integritäts-Gate abgelehnt hat, mit dem
Grund und seinen `details`, etwa jedem ICU-Zweig, der nicht zur Zielsprache passt. Eine Zeile, die
zurückgehalten wurde, weil sich ihre Quelle seit dem Export geändert hat, steht nur in
`integrityMismatches`. `exportWorkbook` markiert eine aktuelle Übersetzung mit falschen Zweigen in den
Review-Spalten als `icu-arms`.

<AvailableFrom version="0.12.0" />

Mit `xliff2` oder `xliff12`, die beide jede Version lesen, und standardmäßig bei einem `workbook`-Pfad auf `.xlf` oder `.xliff` wird jeder Inline-Code vor denselben Prüfungen in seinen exakten Text zurückgeführt. Ein Ziel, das dem aktuellen Wert entspricht, ändert nichts, eine Unit, deren ID keinen Quell-Key nennt, erscheint in `malformedRows`, und eine Unit im Status `reviewed` oder `final` (1.2: `signed-off`, `final` oder `approved="yes"`) wird in der Herkunftsdatei als freigegeben festgehalten, mit `reviewer` als Namen, wenn angegeben (geprüft wie bei `approveEntry`, `REVIEWER_INVALID`), und mit dem Hinweis `HANDOFF_REVIEWS_RECORDED` gemeldet.

## Das TMX-Paar [#das-tmx-paar]

<AvailableFrom version="0.11.0" />

`importTmx` und `exportTmx` bewegen den [Übersetzungsspeicher](https://verbatra.kreitz-webdev.de/de/docs/the-cache.md) in TMX hinein und
wieder heraus, also in das Austauschformat, das die gängigen Übersetzungsplattformen erzeugen und
lesen. Keine der beiden Funktionen konstruiert einen Provider, liest einen API-Key oder stellt eine
Netzwerkanfrage: jeder Wert kommt aus der Datei oder aus dem Übersetzungsspeicher, der ohnehin schon
auf der Platte liegt. Das ist nicht das Arbeitsmappen-Paar in einem anderen Format. Das
Arbeitsmappen-Paar übergibt einer Übersetzerin einen Ausschnitt des offenen Deltas pro Locale;
dieses Paar bewegt den ganzen Übersetzungsspeicher als eine mehrsprachige Datei zwischen Werkzeugen.

### importTmx [#importtmx]

Liest eine TMX-Datei in den Übersetzungsspeicher des Projekts.

```ts title="Signatur"
function importTmx(
  input: ImportTmxInput,
  deps?: ImportTmxDeps,
): Promise<ImportTmxResult>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `file` | `string` | yes | Path to the TMX file, resolved against `cwd`. |
| `cwd` | `string` | no | Directory the file and the memory are resolved against. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |
| `dryRun` | `boolean` | no | Read and validate the file but write nothing. Defaults to false. |
| `overwrite` | `boolean` | no | Let an imported unit replace a translation the memory already holds for the same source and locale. Off by default, so the project's own memory wins a collision. |
| `locales` | `readonly string[]` | no | Subset of configured target locales to import. Defaults to all of them. |

**Rückgabe:** `ImportTmxResult`

**Wirft:** [`UNKNOWN_FORMAT`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#unknown_format), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#config_invalid), [`UNKNOWN_LOCALE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#unknown_locale), [`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#source_unreadable), [`SOURCE_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#source_invalid), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_path_collision), [`MEMORY_UNWRITABLE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#memory_unwritable)

**Beispiel:** [Der TMX-Roundtrip](https://verbatra.kreitz-webdev.de/de/docs/programmatic-api.md#der-tmx-roundtrip)

Nichts aus der Datei gilt als vertrauenswürdig. Das XML wird unter der Härtung des
Interchange-Pakets geparst, sodass eine Entity-Deklaration, ein internes DTD-Subset, eine zu große
oder eine fehlerhafte Datei mit einem strukturierten `SOURCE_INVALID`-Fehler abgelehnt statt geparst
wird. Hat das Problem einen Ort in der Datei, nennt die Meldung Zeile, Spalte und, innerhalb einer
Übersetzungseinheit, deren Ordnungszahl ab 1, und `tmxErrorLocation(error)` liefert denselben Ort
als `TmxErrorLocation`, bei jedem anderen Fehler `undefined`, sodass du weder den Fehler noch seinen
`cause` casten musst. Ein Sprach-Tag wird nach einer ausdrücklichen Regel einer konfigurierten
Locale zugeordnet: exakte Schreibweise nach Kleinschreibung und Faltung von Unterstrichen zu
Bindestrichen; sonst die längste konfigurierte Locale, die ein Subtag-Präfix des Tags ist (Lookup
nach RFC 4647), oder andernfalls eine konfigurierte Locale, die das Tag nur um Regions- oder
Varianten-Subtags erweitert, nie um eine Schrift, sodass zwei Tags mit unterschiedlichen Schrift-
oder Regions-Subtags (`sr-Latn` und `sr-Cyrl`, `de-AT` und `de-CH`) nie zusammenpassen; und ein Tag wird nur dann als
mehrdeutig gemeldet, wenn die Locales, die es erreichen könnte, nicht auf einer Präfix-Kette liegen.
Segmente einer Einheit, die auf dieselbe Locale auflösen, die Quell-Locale eingeschlossen, lassen
nie das letzte gewinnen: Ein exaktes Tag schlägt einen Präfix-Treffer, und zwei gleichrangige
Segmente mit unterschiedlichen Werten speichern für diese Locale nichts und werden als `conflicting`
gezählt (bei der Quell-Locale wird die Einheit abgelehnt und in `conflictingSourceUnits` gezählt).
Jeder Übersetzungskandidat durchläuft dann dasselbe Gate für Platzhalter, Inline-Markup, ICU,
Degeneriertheit und Leere, dem Provider-Ausgabe und eine ausgefüllte Arbeitsmappenzeile schon
unterliegen, geprüft beim Eintritt in den Übersetzungsspeicher, statt dem Lauf überlassen zu
werden, der ihn später liest.

Widerspricht eine importierte Einheit einer Übersetzung, die der Übersetzungsspeicher schon hat,
gewinnt der Übersetzungsspeicher, sofern `overwrite` nicht gesetzt ist. Einheiten werden unter dem
aktuellen Konfigurations-Fingerprint gespeichert, demselben Key, den ein echter Lauf schreibt, und hören
deshalb auf zu passen, sobald sich Provider, Modell, Tonfall, die Glossarbegriffe, die verbatra senden würde, oder das `localeMap` des Providers ändern. Dieselbe Datei ein
zweites Mal zu importieren ändert nichts.

Gibt bei beschädigten Daten einen Bericht zurück, statt zu werfen: wie viele Einheiten gelesen
wurden, eine Abrechnung pro Locale über `added`, `unchanged`, `overwritten`, `kept`, `duplicates`,
`conflicting` und `rejected` nach Grund, dazu die Einheiten, die übersprungen wurden, kein
Quellsegment hatten, Inline-Markup verloren oder deren `sub`-Text weggelassen wurde
(`subflowDroppedUnits`), sowie die Sprach-Tags, die zu nichts passten oder mehrdeutig passten.
`memoryWritable` ist false, wenn die Datei des Übersetzungsspeichers von einem neueren verbatra
geschrieben wurde; sie bleibt dann unangetastet. Die Zählungen pro Locale werden trotzdem gemeldet,
wie bei einem Probelauf, sodass `added` und `overwritten` beschreiben, was gelandet wäre; bei
`memoryWritable` false ist nichts gelandet.

<AvailableFrom version="0.12.0" />

Jede Locale listet außerdem ihre `refusals`, ein `TmxUnitRefusal` pro Einheit, die unter einem
Gate-Grund gezählt wurde: `{ unit, reason, details? }`, wobei `unit` die 1-basierte Position der
Einheit in der Datei ist und `details` nennt, was falsch ist, etwa jeden ICU-Zweig, der nicht zur
Zielsprache passt.

### tmxErrorLocation [#tmxerrorlocation]

Liest aus dem, was `importTmx` geworfen hat, wo eine abgelehnte TMX-Datei schiefging. Gibt für eine
`SOURCE_INVALID`-Ablehnung mit einem Ort in der Datei eine `TmxErrorLocation` zurück
(`{ line, column, unit? }`, alle ab 1 gezählt) und bei jedem anderen Fehler `undefined`, auch bei
einer fehlenden oder zu großen Datei, sodass du weder den Fehler noch seinen `cause` casten musst.

```ts title="Signatur"
function tmxErrorLocation(
  error: unknown,
): TmxErrorLocation | undefined;
```

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

```ts title="Beispiel"
import { importTmx, tmxErrorLocation, type VerbatraConfig } from "@verbatra/sdk";

declare const config: VerbatraConfig;

try {
  await importTmx({ config, file: "legacy.tmx" });
} catch (error) {
  const at = tmxErrorLocation(error);
  if (at !== undefined) console.error(`line ${at.line}, column ${at.column}`);
}
```

### exportTmx [#exporttmx]

Schreibt den Übersetzungsspeicher als TMX 1.4b heraus. `out` fällt auf `DEFAULT_TMX_PATH`
(`verbatra-memory.tmx`) zurück, das als Konstante exportiert wird. Bevor der Übersetzungsspeicher gelesen wird, weist
`TMX_OUTPUT_CONFLICT` ein `out` zurück, das keine Datei benennt (auch eines, das auf ein
Pfadtrennzeichen endet), außerhalb von `cwd` oder auf `cwd` selbst landet oder eine konfigurierte
Locale-Datei, die Lock-Datei, die Herkunftsdatei, den Übersetzungsspeicher-Cache, eine Datei, nach der verbatra seine
Konfiguration sucht, die `configPath`-Datei oder die `glossaryPath`-Datei benennt, ohne Beachtung
der Groß- und Kleinschreibung und, wenn `deps.fs` `realpath` implementiert wie die Voreinstellung,
noch einmal nach dem Auflösen symbolischer Links. Scheitert das Schreiben, weil das Verzeichnis
nicht schreibbar ist, an dem Pfad ein Verzeichnis liegt oder die Platte voll ist, wirft es
`TMX_UNWRITABLE` mit der Datei und dem Dateisystem-Code in der Message. Geschrieben werden nur
Einträge unter dem aktuellen Konfigurations-Fingerprint, also dieselbe Menge, die ein Lauf
wiederverwenden würde. Sprach-Tags werden in BCP-47-Form geschrieben (`en_US` wird zu `en-US`), was
nichts daran ändert, woraus der Key des Übersetzungsspeichers gebildet wird. Ein leerer
Übersetzungsspeicher ergibt eine gültige, leere Datei statt eines Fehlers.

```ts title="Signatur"
function exportTmx(
  input: ExportTmxInput,
  deps?: ExportTmxDeps,
): Promise<ExportTmxResult>;
```

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `VerbatraConfig` | yes | The resolved project config, normally from loadConfig. |
| `out` | `string` | no | Where to write the file. Defaults to DEFAULT_TMX_PATH, resolved against `cwd`. Refused with `TMX_OUTPUT_CONFLICT`, before anything is read or written, when it names no file, resolves outside `cwd` or to `cwd` itself, or names a configured locale file, the lock file, the translation-memory cache, a file verbatra searches for its configuration, the ExportTmxInput.configPath file, or the ExportTmxInput.glossaryPath file. Names are compared case-insensitively, and, when the file-system port implements `realpath`, again after symbolic links are resolved, so a link cannot carry the file anywhere a plain path could not. |
| `configPath` | `string` | no | The configuration file `config` was loaded from, absolute or relative to `cwd`. It is refused as the output path even when its name is not one verbatra searches for. |
| `glossaryPath` | `string` | no | The glossary file the config names, absolute or relative to `cwd`, normally the `path` of a file-backed LoadedConfig.glossary. It is refused as the output path. |
| `cwd` | `string` | no | Directory the output path and the memory are resolved against. Defaults to the project root of the config object loadConfig returned, else the process working directory; a copied or rebuilt config loses that root, so pass `cwd` from resolveProjectRoot. |
| `locales` | `readonly string[]` | no | Subset of configured target locales to export. Defaults to all of them. |
| `toolVersion` | `string` | no | Value for the TMX header's `creationtoolversion`. Defaults to `unknown`. |

**Rückgabe:** `ExportTmxResult`

**Wirft:** [`UNKNOWN_LOCALE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#unknown_locale), [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#config_invalid), [`TMX_OUTPUT_CONFLICT`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#tmx_output_conflict), [`TMX_UNWRITABLE`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#tmx_unwritable), [`LOCALE_LAYOUT_INVALID`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_layout_invalid), [`LOCALE_PATH_COLLISION`](https://verbatra.kreitz-webdev.de/de/docs/error-codes.md#locale_path_collision)

**Beispiel:** [Der TMX-Roundtrip](https://verbatra.kreitz-webdev.de/de/docs/programmatic-api.md#der-tmx-roundtrip)

Gibt `{ path, units, locales, withoutSource, illegalCharactersRemoved, provenanceMarkers }` zurück; `withoutSource` zählt Einträge, die ausgelassen wurden, weil der Übersetzungsspeicher keinen Quelltext zu ihnen hat, was nur bei Einträgen aus einem Cache passiert, der noch vor dem Speichern des Quelltexts geschrieben wurde, und `illegalCharactersRemoved` zählt die Zeichen, die XML 1.0 nicht darstellen kann und die aus dem Segmenttext entfernt wurden.

<AvailableFrom version="0.12.0" />

Jedes Zielsegment trägt `<prop type="x-origin">` (`machine`, `human`, `import` oder `unknown`, der
Typ `TmxOrigin`) und ein `machine`-Segment zusätzlich `<prop type="x-review">` (`approved`,
`unreviewed` oder `rejected`, der Typ `TmxReview`), abgeleitet aus jedem Key, dessen Lock-Eintrag die
Quelle des Segments nennt und dessen Eintrag genau seinen Text beschreibt. `provenanceMarkers` ist
`"unavailable"`, wenn sich die Herkunftsdatei oder die Lock-Datei nicht lesen ließ; dann trägt kein
Segment eine Property.
