Start with a preview
From the directory containingi18n.yml, run:
Usage
Behavior
- load and validate config,
- plan tasks from groups and buckets,
- skip tasks already in
.hyperlocalise.lock.json, - execute remaining tasks,
- persist successful tasks to lock state.
Supported local file formats
run can read source and target files with these extensions:
.json.jsonc.yamland.yml.js,.jsx,.mjs,.cjs,.ts,.tsx,.mts, and.cts.arb.xlf,.xlif, and.xliff.po.html.liquid.md.mdx.adoc,.asciidoc, and.asc.strings.stringsdict.xcstrings.csv.tsv.toml.php.ftl- Android XML
strings.xmlfiles at**/res/values*/strings.xml .xml,.resx, and.reswfor generic XML locale files- Qt Linguist
.tscatalogs (detected from a<TS>root) .properties.ini.srt,.vtt, and.sbv.svg
.json), run supports:
- standard nested key/value JSON objects
- FormatJS message JSON when the root strictly matches:
{"[id]": {"defaultMessage": "[message]", "description": "[description]"}}
defaultMessage is translated. Keys (message IDs), description, and other non-message metadata are preserved.
For JavaScript and TypeScript locale modules (.js, .jsx, .mjs, .cjs, .ts, .tsx, .mts, .cts), run supports static locale object exports:
export default { ... }export const messages = { ... }module.exports = { ... }const messages = { ... }; export default messages
defaultMessage while preserving description metadata. Comments, imports, export syntax, and as const are preserved on write. Dynamic values, computed keys, spread properties, multiple exported locale objects, and template literals with ${...} interpolation fail with a parser error instead of being rewritten.
When an existing JS/TS target module has the same key set as the source, run writes into the target template so translator comments and existing module layout are kept. If the source key set changes, run falls back to the source template to avoid merging mismatched object shapes.
For YAML/YML (.yaml, .yml), run supports mapping-shaped locale files with string leaves. Nested mappings become dotted keys, sequences become [index] keys, and writeback rewrites existing string leaves while preserving key order/comments where possible. Mapping keys cannot contain ., [, or ] because those characters are reserved for flattened paths. Non-string scalar leaves such as numbers, booleans, nulls, timestamps, anchors, and aliases are rejected to avoid silent corruption.
For Flutter ARB (.arb), run translates only message keys, preserves metadata keys such as @key, and normalizes @@locale to the target locale on write.
For AsciiDoc (.adoc, .asciidoc, .asc), run translates titles, headings, paragraphs, lists, tables, and admonitions. It leaves comments, attributes, block macros, preprocessor directives, YAML front matter, and verbatim blocks unchanged. Inline macros, attribute references, and code spans are protected as placeholders. Translated paragraphs are written as one line.
For Markdown and MDX (.md, .mdx), run translates extracted prose and preserves non-translatable structure:
- frontmatter blocks (
---) - fenced code blocks (
```and~~~) - inline code spans
- Markdown anchors such as link destinations
- MDX
importandexportlines - JSX/MDX component tags and attribute values
.html), run translates visible text nodes and keeps tags as structure:
- Keys are dotted tag paths (
html.body.h1,html.p,html.p.strong,html.p.strong.2) - Inline tags (
<strong>,<em>,<a>, and others) start a new path segment; the markup stays in the file <script>,<style>,<pre>, and<head>content is never translated and is preserved verbatim, including<title><img alt="...">— thealtattribute value is extracted ashtml.*.img.alt; the rest of the tag is preserved verbatim- HTML entities (
&,<, etc.) are preserved as-is through the translation round-trip - HTML comments are preserved verbatim
.liquid), run translates hardcoded visible template text and preserves Liquid syntax:
- Liquid output delimiters (
{{ ... }}) are protected as placeholders and restored verbatim - Standalone Liquid tags (
{% ... %}) act as template boundaries; tags inside HTML attributes are protected inline and restored verbatim - Shopify locale-key calls such as
{{ 'header.title' | t }}are preserved as template structure, not translated as source text {% raw %},{% comment %},{% schema %},{% javascript %}, and{% stylesheet %}blocks are preserved verbatim- HTML-shaped Liquid templates use the same visible-text extraction behavior as HTML
.strings), run preserves comments and key/value formatting from the template while replacing value literals with translated text.
For PHP locale arrays (.php), run supports files that consist of a PHP opening tag and a single static return array:
return [ ... ];andreturn array(...);are supported- quoted string keys are flattened with dotted paths, such as
auth.failed - string values may use single or double quotes; comments, whitespace, key order, and array syntax are preserved when writing
- nested arrays can model plural or select variants with keys such as
items.oneanditems.other - executable PHP, variables, function calls, constants,
declare(...), and double-quoted interpolation are rejected with a clear parse error
.xcstrings), run reads catalog entries from strings[*].localizations[sourceLanguage] when present, falls back to the catalog key for simple source-only entries, and writes translated values under localizations[targetLocale]. Plural, device, and substitution leaves are exposed as stable keys such as item_count::plural.one, search_label::device.mac, and count_label::substitution.total::plural.other. Output is normalized as deterministic JSON; comments, extraction state, string-unit state, and unrelated catalog metadata are preserved as JSON fields, but original whitespace and object ordering are not byte-preserved.
For Android XML string resources (**/res/values*/strings.xml), run translates:
<string name="...">values<plurals name="..."><item quantity="...">values, using keys such asitem_count.oneanditem_count.other
formatted, tools:*, and translatable are preserved. Resources marked translatable="false" are skipped. Android placeholders such as %1$s and %d stay in the extracted text and are written back with the translated value.
Unsupported translatable Android resource shapes such as <string-array> fail with a clear parser error instead of being ignored.
For Java properties (.properties), run supports per-locale key/value resource bundles such as messages_en.properties -> messages_[locale].properties. It parses Java-style separators (=, :, or whitespace), escaped keys and values, \uXXXX unicode escapes, and line continuations. Comments beginning with # or ! are preserved and adjacent comments can be used as entry context. On write, existing key order, comments, separators, and spacing are preserved; translated values are normalized to single-line escaped values. Duplicate keys, malformed unicode escapes, invalid UTF-8 input, and dangling continuations fail with clear parse errors.
For INI files (.ini), run supports per-locale key/value files with optional [section] headers, such as messages_en.ini -> messages_[locale].ini. Keys before the first section stay unprefixed. Keys inside a section flatten as section.key. Comments beginning with ; or # are preserved and adjacent comments can be used as entry context. Quoted values and inline comments after whitespace are supported. On write, existing sections, key order, comments, separators, and spacing are preserved. New keys append to the matching section, and unknown sections are created at the end of the file. Duplicate flattened keys, empty section names, unclosed quotes or headers, missing separators, and invalid UTF-8 fail with clear parse errors.
For SVG (.svg), run translates visible text in text, tspan, textPath, title, and desc. Geometry, attributes, and style / script / metadata content stay in the file. Spans use sequential keys such as svg.0001. Writeback HTML-escapes translated text and ignores extra keys so markup stays aligned with the template.
For SubRip, WebVTT, and YouTube SBV subtitles (.srt, .vtt, .sbv), run translates cue payload text and preserves non-translatable structure:
- cue numbers, timestamps, and positioning or cue settings
- WebVTT
WEBVTTheaders,NOTE,STYLE, andREGIONblocks - HTML-like markup inside cues such as
<i>and<b> - WebVTT cue spans such as
<c.red>,<v Speaker>, and karaoke timestamps like<00:01.000>
srt.0001, vtt.0001, and sbv.0001. Timestamp lines are available as entry context. Writeback replaces cue text in place and ignores extra translation keys so cue counts stay aligned with the source file. Blank lines inside translated cue text are dropped so they cannot split cues. SBV cues use H:MM:SS.mmm,H:MM:SS.mmm timestamps and have no cue numbers.
Example config mapping:
.csv) and TSV (.tsv), run supports two layouts:
- key/value layout (for example:
key,value) - per-locale column layout (for example:
id,en,fr,de)
run preserves the existing header and non-target columns, updates matching keys in place, and appends new keys in deterministic sorted order. TSV uses tab delimiters.
For TOML (.toml), run translates string leaves in tables, inline tables, and string arrays. Nested tables flatten as dotted keys, and string arrays use bracket indexes such as home.items[0]. Numbers, booleans, dates, and comments stay in the file. Array-of-tables ([[name]]) and duplicate keys fail with a parser error. Writeback replaces existing string literals in place and appends new dotted keys at the end of the file.
For Mozilla Fluent (.ftl), run supports top-level messages, message attributes, multiline values, and select/plural patterns represented as full message values:
- attributes are exposed as dotted keys such as
brand.title - comments, blank lines, and unparsed metadata are preserved when values are replaced in an existing template
- Fluent terms (
-brand = ...) and term references are not supported and fail with a clear parser error - newly appended message keys are sorted deterministically; new attributes can only be appended when their parent message is not already present in the template
.xml, .resx, .resw), run translates text-only leaf elements and preserves unrelated XML structure:
- keyed leaves use
key,id, ornameattributes, for example<message key="checkout.cta">Checkout now</message> - nested path-shaped leaves use dotted element paths, for example
<home><title>Welcome</title></home>->home.title .resxand.resw<data name="home.title"><value>Welcome</value></data>entries are supported- comments, attributes, metadata elements such as
<metadata>,<comment>, and<resheader>are preserved when the target key set still matches the source - if the source gains keys,
runwrites from the source template, so target-only resources are not kept - mixed-content values such as
Hello <ph/>and Android<resources>files are rejected instead of being rewritten as generic XML
Flags
--config: path to config file (defaulti18n.yml, falling back toi18n.jsonc, in the current directory)--group: run only tasks for the given group name--bucket: run only tasks for the given bucket name--file: run only tasks for the given source file path (repeatable)--locale: run only tasks for the given target locale (repeatable);--target-localeis an alias--dry-run: print plan only, do not translate or write files--force: rerun all planned tasks and ignore lockfile skip state--keep-completed-on-failure: keep lockfile entries for successful keys when other keys in the same target fail; still rolls back if the target file cannot be written--prune: remove target keys that no longer exist in source files--prune-max-deletions: maximum stale keys deleted in one run before requiring an explicit override (default100)--prune-force: bypass the prune deletion safety limit--workers: number of parallel translation workers (defaults to CPU cores)--progress: progress rendering mode (auto|on|off, default:auto)--output: write machine-readable JSON run report to the given path--srx: overridebuckets.*.files[].srxfor this invocation. Accepts a built-in template (default,html,markdown) or a project-relative SRX 2.0 file. Mappingsrxstays off unless you set this flag or the file mapping.--experimental-context-memory: enable two-stage context memory generation before translating each scope--context-memory-scope: context sharing scope (file|bucket|group, defaultfile)--context-memory-max-chars: maximum context memory length injected into each translation request (default1200)
Sentence segmentation (srx)
See Tune translation behavior for configuration, limits, and examples.
Prompt contract for run
See Tune translation behavior for configuration, limits, and examples.
Machine translation (MT) execution
See Tune translation behavior for configuration, limits, and examples.Experimental context memory flow
See Tune translation behavior for configuration, limits, and examples.Scope runs to one group
Use--group when you want to run only one configured group.
run fails with an unknown group planning error.
Scope runs to one bucket
Use--bucket when you want to run only one configured bucket. This is useful for focused updates, CI partitioning, or validating a single area before a full run.
run fails with an unknown bucket planning error.
Scope runs to one source file
Use--file when you want to run only one configured source file. You can repeat the flag to select multiple source files, and you can combine it with --group, --bucket, and --locale.
run fails with an unknown source file planning error.
Scope runs to one target locale
Use--locale when you want to re-run only specific locales without changing group or bucket selection. You can repeat the flag to select multiple locales. The same filter is available as --target-locale for compatibility with older scripts.
locales.targets, run fails with an unknown target locale planning error. When combined with --group, only locales that belong to that group are planned.
When combined with --prune, stale-key detection is also limited to the selected target locales. run only scans and prunes target files that belong to the filtered locale set.
Force rerun all planned tasks
Use--force to ignore lockfile skip state and execute every planned task again.
Keep successful keys after a partial failure
By default, a failed key rolls back every lockfile entry for that target, so the nexthl run retranslates successes too. Pass --keep-completed-on-failure to leave successful keys in .hyperlocalise.lock.json and retry only leftover keys. A failed target-file write still rolls back this run’s entries for every target that was not written.
Output fields
planned_totalskipped_by_lockexecutable_totalsucceededfailedpersisted_to_lockprompt_tokenscompletion_tokenstotal_tokens
locale_usage locale=<locale> prompt_tokens=<...> completion_tokens=<...> total_tokens=<...>.
When you pass --output, the JSON report includes run metadata (generatedAt, configPath), aggregate token usage, per-locale usage, and per-entry batch usage.
MT usage is JSON-only (not printed to stdout) and appears under sourceChars/translatedChars/requestCount/durationMs at the run level, localeMTUsage (per target locale), and mtUsageByProfile (per MT profile). See “Machine translation (MT) execution” above.
Failure output
On task failure, output includesfailure target=<...> key=<...> reason=<...>.
Worker tuning guidance
Lower--workers when you hit provider rate limits or run in constrained CI environments. Start with 1 to stabilize retries and then increase gradually.
Raise --workers when your provider quota and machine resources allow more throughput. Increase in small steps and watch API error rates plus local CPU and memory usage.

