Reference / SDK
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.
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 Available from 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.
function readLocaleFileSnapshot(
input: ReadLocaleFileSnapshotInput,
deps?: ReadLocaleFileSnapshotDeps,
): Promise<LocaleFileSnapshot>;Prop
Type
Returns: LocaleFileSnapshot
Throws: UNKNOWN_, LOCALE_, LOCALE_
Returns { locale, hashes }.
diffLocaleSnapshots Available from 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.
function diffLocaleSnapshots(
previous: LocaleFileSnapshot,
current: LocaleFileSnapshot,
): LocaleSnapshotDelta;Prop
Type
Returns: LocaleSnapshotDelta
Locale paths
createLocalePathResolver Available from 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.
function createLocalePathResolver(
cwd: string,
config: LocalePathResolverConfig,
): LocalePathResolver;Prop
Type
Returns: LocalePathResolver
Throws: LOCALE_, LOCALE_
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_, and two locales resolving to one path throws LOCALE_.
The workbook pair
The translator handoff, as an Excel workbook or as delimited text; see Manual translation.
exportWorkbook Available from 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.
function exportWorkbook(
input: ExportWorkbookInput,
deps?: ExportWorkbookDeps,
): Promise<ExportWorkbookResult>;Prop
Type
Returns: ExportWorkbookResult
Throws: UNKNOWN_, LOCALE_, LOCALE_, SOURCE_, SOURCE_, LOCK_, UNKNOWN_, EXPORT_, EXPORT_
Example: 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_ (verbatra-translations.xlsx) or, for the delimited
and XLIFF formats, DEFAULT_ (verbatra-translations), both exported as constants. The accepted values are exported as EXCHANGE_ and the default as DEFAULT_, 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_ 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_ naming
the file and the file-system code, with the file-system error as its cause.
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.
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.
importWorkbook Available from 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.
function importWorkbook(
input: ImportWorkbookInput,
deps?: ImportWorkbookDeps,
): Promise<RunSummary>;Prop
Type
Returns: RunSummary
Throws: LOCK_, REVIEWER_, UNKNOWN_, SOURCE_, SOURCE_, LOCALE_, LOCALE_, LOCK_, PROVENANCE_
Example: 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_ as data on the summary, not a throw.
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_ 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.
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.
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_), and reported with the notice HANDOFF_.
The TMX pair Available from 0.11.0
importTmx and exportTmx move the translation memory 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
Reads a TMX file into the project's memory.
function importTmx(
input: ImportTmxInput,
deps?: ImportTmxDeps,
): Promise<ImportTmxResult>;Prop
Type
Returns: ImportTmxResult
Throws: UNKNOWN_, CONFIG_, UNKNOWN_, SOURCE_, SOURCE_, LOCALE_, LOCALE_, MEMORY_
Example: 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_ 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.
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
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_ 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.
function tmxErrorLocation(
error: unknown,
): TmxErrorLocation | undefined;Returns: TmxErrorLocation | undefined
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
Writes the memory out as TMX 1.4b. out defaults to DEFAULT_ (verbatra-memory.tmx),
exported as a constant. Before the memory is read, TMX_ 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_ 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_ becomes en-US), which does not
change how the memory is keyed. An empty memory produces a valid, empty file rather than an error.
function exportTmx(
input: ExportTmxInput,
deps?: ExportTmxDeps,
): Promise<ExportTmxResult>;Prop
Type
Returns: ExportTmxResult
Throws: UNKNOWN_, CONFIG_, TMX_, TMX_, LOCALE_, LOCALE_
Example: 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.
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.