Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Translation CLI

Translation commands import X-Ray XML string tables, maintain XRF JSON translation sources, and compile them back to gamedata. Start with Parse for an existing game or mod; use Format, Verify, and Build for an existing JSON project.

Examples run from a working directory containing a translations source folder. Import examples additionally assume a stalker-anomaly installation beside it.

Initialize

Add missing language keys as null placeholders in the JSON sources:

xrf-cli translation initialize --path ./translations

This updates files in place. Running it again on the same initialized sources makes no further change. A null marks a missing translation; it does not supply fallback text.

Format

Normalize source layout, then use check mode in automation:

xrf-cli translation format --path ./translations
xrf-cli translation format --path ./translations --check

Example output — check unformatted JSON sources:

Checking 2 translation source(s)
Not formatted: ./translations\st_items.json
Not formatted: ./translations\st_ui.json

Stderr:

Format issues with 2/2 translation source(s) in 2 ms
Check failed: 2 finding(s)

Exit code: 3.

The formatter sorts ids and language keys naturally, uses two-space indentation, and adds a trailing newline. Natural order places st_thanks2 before st_thanks10, and ammo-5.45x39-ap before ammo-11.43x23-fmj. Check mode writes nothing and exits 3 when selected files need formatting.

Repeat --path for multiple inputs. Directories select JSON files recursively; an explicitly named file is accepted regardless of its extension.

By default, each file uses its dominant LF or CRLF line ending; a tie or a file without line breaks selects LF. Mixed line endings are normalized to that choice. Check mode ignores line-ending differences unless --line-endings lf or --line-endings crlf explicitly requires one convention.

What it does not touch

Formatting preserves JSON values and their representation as strings or arrays. A one-element ["text"] stays an array. The build joins array elements with the literal \n sequence used by string values, so formatting does not choose between these authoring forms.

It does not add null placeholders; use initialize or parse for that. Files already matching the selected format are not rewritten, preserving their timestamps.

When it refuses

Selecting no sources or encountering an unparseable source exits 1. A parse failure stops the run at that file; files formatted earlier remain changed. Each replacement is staged as a whole file.

Build

Compile JSON sources into one XML string table per source and selected language, using that language’s code page:

xrf-cli translation build --path ./translations --output ./gamedata/configs/text --language ukr

Example output — build Ukrainian string tables:

Building translations in ./translations (ContainingInstallation), language - ukr, sorted - true
Building 2 translation source(s)
Built translation files in 2 ms

Exit code: 0.

A missing translation compiles to its id. The report summarizes tables written and ids compiled per language.

Build and verify accept a single source file or roots read through the virtual file system. Layered roots resolve winning files by priority, including files from mounted archives. The build output is a plain directory and must be outside every source root.

Verify

Check completeness for a language:

xrf-cli translation verify --path ./translations --language ukr --strict `
  --report ./translation-report.json

Example output — find missing Ukrainian text:

Verifying translations in ./translations (ContainingInstallation), language - ukr
Verifying 2 translation source(s)
Verified translation files in 0 ms, 4 checked, 2 missing

Stderr:

Translation key missing: st_medkit_name ukr in st_items.json
Translation key missing: st_ui_quit ukr in st_ui.json
Check failed: 2 finding(s)

Exit code: 3. Both the absent key and the explicit null are reported as missing.

Both an absent language key and an explicit null count as missing. Without --strict, missing translations are reported while a completed check succeeds. With --strict, those gaps produce exit 3.

The report contains a finding per missing id and a languages array with summary rows per file and language. Use the summary rows to review large imports, then inspect findings for the files being translated. An unreadable source is an execution failure; malformed source content can fail verification independently of --strict.

Parse

Import XML tables once per language into a shared JSON output directory:

xrf-cli translation parse --path ./stalker-anomaly --language eng --output ./translations
xrf-cli translation parse --path ./stalker-anomaly --language ukr --output ./translations

XML tables do not declare their language. --language labels the imported text, so select the language that the input actually contains. Installations with tables in db/configs archives are read through the same virtual file system as loose trees.

What it writes

Each table becomes a JSON source with its subdirectory path preserved. Imports into the same output merge languages. Ids and language keys use the same canonical order as Format, independently of import order. A record missing one of the languages represented in its file receives an explicit null.

Existing text that differs from the import is preserved and counted as a conflict. Add --overwrite to replace it. Reimporting unchanged tables into an unchanged output is idempotent.

Finding the tables

--path names the input root. The importer looks under configs/text when present, then selects the directory named for the requested language. Use --prefix for a different layout. A selected scope that still contains another language’s directory is refused to prevent labeling its strings with the wrong language.

Before writing anything

Add --dry-run to inspect the proposed import without writing. Use --file to select one table. Unreadable tables are reported; --strict makes those findings fail the run.

Notes

In the engine repository, npm run cli -- verify translations wraps verification, and the translations build target wraps compilation. Call xrf-cli directly for formatting, initialization, and imports.

Command reference

xrf-cli translation build

Command to build translation files into gamedata

xrf-cli translation build [OPTIONS] --path <path>... --output <output>
OptionRequiredDefaultDescription
-p, --path <path>...yesRoot holding translation sources, or one source file. Repeat to layer roots, highest priority first
--source <source>containing-installationHow to read the path: auto treats it as an installation only when it declares one, directory ignores any declaration, volumes mounts every archive volume beneath it, installation requires one, containing-installation searches parent directories for one. Possible values: auto, directory, volumes, installation, containing-installation.
--prefix <prefix>Limit to one logical subtree, such as translations
-o, --output <output>yesPath to output translation
-l, --language <language>allTarget language to translate
--no-sortPreserve source order instead of sorting dynamic translation files
-s, --silentTurn off logging
-v, --verboseTurn on verbose logging
--jsonWrite the run’s JSON report to stdout, moving human output to stderr
--report <PATH>Write the run’s JSON report to a file

xrf-cli translation format

Command to normalize json translation sources

xrf-cli translation format [OPTIONS] --path <path>...
OptionRequiredDefaultDescription
-p, --path <path>...yesPaths to json translation sources or folders holding them
-c, --checkRun formatter in check mode
--line-endings <line-endings>Write these line endings instead of preserving each file’s own, and judge them in check mode. Possible values: lf, crlf.
-s, --silentTurn off logging
-v, --verboseTurn on verbose logging
--jsonWrite the run’s JSON report to stdout, moving human output to stderr
--report <PATH>Write the run’s JSON report to a file

xrf-cli translation initialize

Command to initialize translation files

xrf-cli translation initialize [OPTIONS] --path <path>
OptionRequiredDefaultDescription
-p, --path <path>yesPath to translation folder
-s, --silentTurn off logging
-v, --verboseTurn on verbose logging
--jsonWrite the run’s JSON report to stdout, moving human output to stderr
--report <PATH>Write the run’s JSON report to a file

xrf-cli translation parse

Command to parse xml translations into json sources

xrf-cli translation parse [OPTIONS] --path <path>... --language <language> --output <output>
OptionRequiredDefaultDescription
-p, --path <path>...yesRoot holding raw xml translations. Repeat to layer roots, highest priority first
--source <source>containing-installationHow to read the path: auto treats it as an installation only when it declares one, directory ignores any declaration, volumes mounts every archive volume beneath it, installation requires one, containing-installation searches parent directories for one. Possible values: auto, directory, volumes, installation, containing-installation.
--prefix <prefix>Limit to one logical subtree, such as configs\text\eng
-l, --language <language>yesLanguage every entry read by this run is filed under. Raw xml carries no language, so it is declared rather than guessed
-o, --output <output>yesDirectory the json sources are written to, merging with any already there
--file <file>Restrict the run to one string table, by file name
--overwriteReplace existing text that differs, instead of keeping what is already there
--dry-runReport what would be written without writing it
--strictAnswer with a check failure when anything was unreadable or off schema
-s, --silentTurn off logging
-v, --verboseTurn on verbose logging
--jsonWrite the run’s JSON report to stdout, moving human output to stderr
--report <PATH>Write the run’s JSON report to a file

xrf-cli translation verify

Command to verify translation files integrity

xrf-cli translation verify [OPTIONS] --path <path>...
OptionRequiredDefaultDescription
-p, --path <path>...yesRoot holding translation sources, or one source file. Repeat to layer roots, highest priority first
--source <source>containing-installationHow to read the path: auto treats it as an installation only when it declares one, directory ignores any declaration, volumes mounts every archive volume beneath it, installation requires one, containing-installation searches parent directories for one. Possible values: auto, directory, volumes, installation, containing-installation.
--prefix <prefix>Limit to one logical subtree, such as translations
-l, --language <language>allTarget language to translate
--strictFail with non 0 error code if translation are missing
-s, --silentTurn off logging
-v, --verboseTurn on verbose logging
--jsonWrite the run’s JSON report to stdout, moving human output to stderr
--report <PATH>Write the run’s JSON report to a file