---
title: "Handoff and exchange"
description: "SDK entry points for workbook and TMX import and export, plus locale-file snapshots and the paths verbatra resolves for each locale."
type: "reference"
---
# Handoff and exchange

SDK entry points for workbook and TMX import and export, plus locale-file snapshots and the paths verbatra resolves for each locale.

<SdkAnchorForward />

## Locale-file snapshots [#locale-file-snapshots]

The building blocks of a live-refresh watcher such as Studio's: capture a locale file's state, then
count what changed since.

### readLocaleFileSnapshot [#readlocalefilesnapshot]

<AvailableFrom version="0.5.0" />

Reads one locale file (the source locale or any target locale) and reduces it to a content hash per
key. A file that does not exist yet reads as an empty snapshot rather than throwing.

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

**Returns:** `LocaleFileSnapshot`

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

Returns `{ locale, hashes }`.

### diffLocaleSnapshots [#difflocalesnapshots]

<AvailableFrom version="0.5.0" />

Compares two snapshots of the same file, taken at different times, and counts the keys added,
changed, and removed between them. A plain synchronous function: `diffLocaleSnapshots(previous,
current)` returns `{ added, changed, removed }`. Counts only, never key names.

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

**Returns:** `LocaleSnapshotDelta`

## Locale paths [#locale-paths]

### createLocalePathResolver [#createlocalepathresolver]

<AvailableFrom version="0.7.0" />

Resolves the project's locale-to-path mapping in both directions, from `files.pattern`, the
configured locales, and `files.localeStyle`. `createLocalePathResolver(cwd, config)` returns
`{ pathFor, localeFor }`: `pathFor(locale)` is the absolute path of one locale's file, and
`localeFor(path)` is the locale that owns a path, or `undefined` for a path this project does not
own, and always `undefined` for a shared-catalogue format such as `apple-xcstrings`. Every SDK entry point resolves paths through it, so a watcher or dashboard built on the SDK
sees exactly the paths a run writes.

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

**Returns:** `LocalePathResolver`

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

Every check runs when the resolver is created, before any file is read: a pattern and style that
cannot be combined, or a locale the style has no correct spelling for, throws
`LOCALE_LAYOUT_INVALID`, and two locales resolving to one path throws `LOCALE_PATH_COLLISION`.

## The workbook pair [#the-workbook-pair]

The translator handoff, as an Excel workbook or as delimited text; see [Manual translation](https://verbatra.kreitz-webdev.de/docs/manual-translation.md).

### exportWorkbook [#exportworkbook]

<AvailableFrom version="0.2.0" />

Writes the strings that still need translating (missing and changed keys per locale; add unchanged
ones with `includeUnchanged`) into a styled `.xlsx` workbook. Rows carry the same review-flag
signal a translate run computes. No provider call, no lock write.

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

**Returns:** `ExportWorkbookResult`

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

**Example:** [The workbook round-trip](https://verbatra.kreitz-webdev.de/docs/programmatic-api.md#the-workbook-round-trip)

`format` is `xlsx` by
default; `csv` and `tsv` write one `<locale>.csv` or `<locale>.tsv` per locale instead, so `out`
names a directory for them (created if missing) and a file path for `xlsx`. `out` defaults to
`DEFAULT_WORKBOOK_PATH` (`verbatra-translations.xlsx`) or, for the delimited
and XLIFF formats, `DEFAULT_DELIMITED_PATH` (`verbatra-translations`), both exported as constants. The accepted values are exported as `EXCHANGE_FORMATS` and the default as `DEFAULT_EXCHANGE_FORMAT`, so a tool that wraps the SDK can validate a format argument without hardcoding the list. Returns `{ path, locales }`: the absolute
path written and a per-locale row count.

Before anything is read, `EXPORT_OUTPUT_CONFLICT` refuses an `out` that resolves outside `cwd`, and
one that, or a file the export would write into it, names a configured locale file, the lock file,
the provenance file, the translation-memory cache, a file verbatra searches for its configuration,
the `configPath` file, or the `glossaryPath` file, compared case-insensitively and, when `deps.fs`
implements `realpath` as the default does, again after symbolic links are resolved. An `xlsx` path
is also refused when it names no file (including one ending in a path separator) or names `cwd`
itself; a `csv`, `tsv` or XLIFF directory may be `cwd`. A write that fails, because the directory is not
writable, a directory or file is in the way, or the disk is full, throws `EXPORT_UNWRITABLE` naming
the file and the file-system code, with the file-system error as its `cause`.

<AvailableFrom version="0.12.0" />

`format: "xliff2"` and `format: "xliff12"` write one XLIFF 2.0 or 1.2 `<locale>.xlf` per locale into the `out` directory, for a CAT tool: one unit per key, placeholders and markup as protected `<ph>` inline codes, the key's description and meaning as notes, the source hash in the unit's metadata, and a segment state from the lock and review state (`initial` for a missing or stale key, `translated` when up to date, `reviewed` when approved). Both types are exported, `XliffFormat` naming the two XLIFF members of `ExchangeFormat`. See [Hand off to a translation agency](https://verbatra.kreitz-webdev.de/docs/translation-agency.md).

Each unit with a target also carries its origin: XLIFF 1.2 qualifies an unapproved machine-class target with `state-qualifier="mt-suggestion"`, and XLIFF 2.0 adds `origin` and `review-state` entries to the unit's `verbatra` metadata group. The result then also carries `provenanceMarkers`: `"written"`, or `"unavailable"` when the provenance file could not be read and no marker was written. See [Machine-translation evidence](https://verbatra.kreitz-webdev.de/docs/provenance-evidence.md#markers-in-exports).

### importWorkbook [#importworkbook]

<AvailableFrom version="0.2.0" />

Reads a filled workbook back into the locale files, running the same source-drift and integrity
checks as `translate`. Only accepted rows advance their lock baseline; a blank or rejected
row keeps re-exporting until it is genuinely resolved.

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

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

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

**Example:** [The workbook round-trip](https://verbatra.kreitz-webdev.de/docs/programmatic-api.md#the-workbook-round-trip)

With `csv` or `tsv`, `workbook` is either
one interchange file or the directory holding one per locale, and the locale comes from the file
name. A file ending in `.csv` or `.tsv` is read in that format when `format` is left out, and a directory in the format of its export manifest or locale files. Returns the same `RunSummary` shape as `translate`
(with `needsReview` always empty, since no provider is involved). A sheet for a locale that is not
a configured target fails that locale with `CONFIG_INVALID` as data on the summary, not a throw.

<AvailableFrom version="0.12.0" />

`onLockWait` and `lockAcquireTimeoutMs` behave exactly as on `translate`. `lockAcquireTimeoutMs`
bounds the wait for a locale's write lock, taken before that locale's file is written, and a locale
still contended after it fails with `LOCK_CONTENDED` on its own summary while the other locales
import. Recording a written file in the lock file always allows the ten-minute default. A dry run
takes no lock, so neither option applies to it.

<AvailableFrom version="0.12.0" />

Each locale's `integrityRefusals` names the rows the integrity gate refused, with the reason and
its `details`, such as each ICU arm that does not fit the target language. A row withheld because
its source changed since the export is listed in `integrityMismatches` only. `exportWorkbook` flags
a current translation with the wrong arms as `icu-arms` in its review columns.

<AvailableFrom version="0.12.0" />

With `xliff2` or `xliff12`, either of which reads both versions, and by default for a `workbook` path ending in `.xlf` or `.xliff`, every inline code is resolved back to its exact text before the same checks. A target equal to the current value changes nothing, a unit whose id names no source key is reported in `malformedRows`, and a unit in state `reviewed` or `final` (1.2: `signed-off`, `final` or `approved="yes"`) is recorded as approved in the provenance file, naming `reviewer` when given (checked like `approveEntry`'s, `REVIEWER_INVALID`), and reported with the notice `HANDOFF_REVIEWS_RECORDED`.

## The TMX pair [#the-tmx-pair]

<AvailableFrom version="0.11.0" />

`importTmx` and `exportTmx` move the [translation memory](https://verbatra.kreitz-webdev.de/docs/the-cache.md) in and out of TMX, the
interchange format the mainstream translation platforms produce and consume. Neither constructs a
provider, reads an API key, nor makes a network call: every value comes from the file or from the
memory already on disk. This is not the workbook pair in another format. The workbook pair hands a
per-locale slice of the pending delta to a human translator; this pair moves the whole memory as one
multilingual file between tools.

### importTmx [#importtmx]

Reads a TMX file into the project's memory.

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

**Returns:** `ImportTmxResult`

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

**Example:** [The TMX round-trip](https://verbatra.kreitz-webdev.de/docs/programmatic-api.md#the-tmx-round-trip)

Nothing from the file is trusted. The XML is parsed under the interchange package's hardening, so an
entity declaration, an internal DTD subset, an oversized file, or a malformed one is refused with a
structured `SOURCE_INVALID` error rather than parsed. When the problem has a place in the file, the
message names its line, column and, inside a translation unit, the unit's 1-based ordinal, and
`tmxErrorLocation(error)` returns the same place as a `TmxErrorLocation`, or `undefined` for any
other error, so you never cast the error or its `cause`. A language tag is resolved to a configured
locale by an explicit rule: exact spelling after lowercasing and folding underscores to hyphens;
failing that, the longest configured locale that is a subtag prefix of the tag (RFC 4647 lookup), or
else a configured locale that extends the tag only by region or variant subtags, never by a script,
so two tags whose script or region subtags differ (`sr-Latn` and `sr-Cyrl`, `de-AT` and `de-CH`) never match; and a tag is
reported as ambiguous only when the locales it could reach do not lie on one prefix chain. Segments
of one unit that resolve to the same locale, the source locale included, never let the last one win:
an exact tag outranks a prefix match, and two equal-ranked segments with different values store
nothing for that locale and are counted as `conflicting` (for the source locale, the unit is refused
and counted in `conflictingSourceUnits`). Every candidate translation then passes the same
placeholder, inline markup, ICU, degeneracy, and emptiness gate that provider output and a filled workbook row
already face, checked as the record enters the memory rather than left to the run that later reads
it.

Where an imported unit disagrees with a translation the memory already holds, the memory wins unless
`overwrite` is set. Units are stored under the current configuration fingerprint, the same key a real
run writes, so they stop matching when the provider, model, tone, the glossary terms verbatra would send, or provider `localeMap` changes. Importing the
same file twice changes nothing the second time.

Returns a report rather than throwing on damaged data: how many units were read, a per-locale
account of `added`, `unchanged`, `overwritten`, `kept`, `duplicates`, `conflicting`, and `rejected`
by reason, plus the units that were skipped, carried no source segment, lost inline markup, or had
`sub` text left out (`subflowDroppedUnits`), and the language tags that matched nothing or matched
ambiguously. `memoryWritable` is false when the memory file was written by a newer verbatra, in
which case it is left untouched. The per-locale counts are still reported then, as on a dry run, so
`added` and `overwritten` describe what would have landed; with `memoryWritable` false, nothing did.

<AvailableFrom version="0.12.0" />

Each locale also lists its `refusals`, one `TmxUnitRefusal` per unit counted under a gate reason:
`{ unit, reason, details? }`, where `unit` is the unit's 1-based ordinal in the file and `details`
names what is wrong, such as each ICU arm that does not fit the target language.

### tmxErrorLocation [#tmxerrorlocation]

Reads where a refused TMX file went wrong from whatever `importTmx` threw. It returns a
`TmxErrorLocation` (`{ line, column, unit? }`, all 1-based) for a `SOURCE_INVALID` refusal that has
a place in the file, and `undefined` for any other error, including a missing or oversized file, so
you never cast the error or its `cause`.

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

**Returns:** `TmxErrorLocation | undefined`

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

Writes the memory out as TMX 1.4b. `out` defaults to `DEFAULT_TMX_PATH` (`verbatra-memory.tmx`),
exported as a constant. Before the memory is read, `TMX_OUTPUT_CONFLICT` refuses an `out` that names
no file (including one ending in a path separator), resolves outside `cwd` or to `cwd` itself, or
names a configured locale file, the lock file, the provenance file, the translation-memory cache, a file verbatra
searches for its configuration, the `configPath` file, or the `glossaryPath` file, compared
case-insensitively and, when `deps.fs` implements `realpath` as the default does, again after
symbolic links are resolved. A write that fails, because the directory is not writable, a directory
sits at that path, or the disk is full, throws `TMX_UNWRITABLE` naming the file and the file-system
code. Only entries under the current configuration fingerprint are written, which is the same set a
run would reuse. Language tags are written in BCP 47 form (`en_US` becomes `en-US`), which does not
change how the memory is keyed. An empty memory produces a valid, empty file rather than an error.

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

**Returns:** `ExportTmxResult`

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

**Example:** [The TMX round-trip](https://verbatra.kreitz-webdev.de/docs/programmatic-api.md#the-tmx-round-trip)

Returns `{ path, units, locales, withoutSource, illegalCharactersRemoved, provenanceMarkers }`; `withoutSource` counts entries left out because the memory holds no source text for them, which happens only for entries carried forward from a cache written before the memory stored source text, and `illegalCharactersRemoved` counts the characters XML 1.0 cannot represent that were removed from segment text.

<AvailableFrom version="0.12.0" />

Each target segment carries `<prop type="x-origin">` (`machine`, `human`, `import` or `unknown`,
the `TmxOrigin` type) and a `machine` one also `<prop type="x-review">` (`approved`, `unreviewed`
or `rejected`, the `TmxReview` type), derived from every key whose lock entry names the segment's
source and whose record describes exactly its text. `provenanceMarkers` is `"unavailable"` when the
provenance file or the lock file could not be read, in which case no segment carries a property.
