Skip to main content

Start here

For your first project, copy the tested configuration from Translate your first file. You need only source and target locales, a source-to-target file mapping, and an AI provider profile. The sections below are the complete field reference. Add advanced settings only when your workflow needs them.

File overview

i18n.yml controls locales, file mapping, model profiles, and optional advanced routing. i18n.jsonc is still supported for compatibility.

CLI version pin

Pin the Hyperlocalise CLI version at the top of i18n.yml, similar to packageManager in package.json:
When set, commands that load the config (run, check, status, pack, sync, and others) fail if the running CLI version does not match the pinned value. The hl alias is also accepted (hl@1.13.3). In GitHub Actions, set hyperlocalise-version: config to install the version declared in your i18n config file.

Starter config

This is the shape written by hyperlocalise init. When groups is omitted, Hyperlocalise automatically uses one implicit default group with:
  • all locales from locales.targets
  • all bucket names from buckets

Locales

  • locales.source: source locale.
  • locales.targets: list of target locales.
  • optional locales.fallbacks: fallback order per locale.
  • optional locales.copies: map a target locale to another locale whose catalog should be copied instead of translated. Use this when one locale should ship as a duplicate of another, for example en-AU copying en-GB.
run still writes a catalog for the copy locale. It does not call an LLM or MT provider for that locale. After the origin locale is translated (or when its files already exist), Hyperlocalise copies those values into the copy locale’s output paths. The copy replaces the destination catalog: keys that exist only on the destination are removed. Image copies convert the origin bytes into the destination file format when the extensions differ, for example banner.png to banner-en-AU.webp. The copy key must be in locales.targets. The origin must be locales.source or another target that is not itself a copy. A locale cannot be both a copy and a locales.fallbacks key. Copy locales need their own output files, so the bucket to path must include {{target}}, {{localeDir}}, or [locale]. Include copy locales in groups.*.targets (or omit groups so the implicit default group includes every target). hl run --locale en-AU copies from existing origin files and does not translate the origin. Translate the origin first, or run both locales together.

Buckets

buckets map source files to target output templates. Each file mapping uses:
  • from: source path template
  • to: target path template
  • optional srx: built-in sentence-break template (default, html, markdown) or a project-relative SRX 2.0 file. When set, run splits string values into sentence spans before translation and joins them back to the original keys on write. JSON and YAML stay unsplit unless srx is set. Already-segmented formats (XLIFF, PO, SRT, VTT, xcstrings, stringsdict) and FormatJS/ARB parser modes ignore srx. ICU, printf, and Fluent { $var } values stay one unit. hl run --srx overrides this field for the whole invocation.
Use {{source}}, {{target}}, and {{localeDir}} in templates. {{localeDir}} resolves to an empty segment when target equals source, and to the target locale otherwise.

PHP array locale mapping patterns

Laravel-style locale arrays can be mapped directly when each file returns one static PHP array.
Supported PHP locale files must begin with <?php and return a static [...] or array(...) literal. Hyperlocalise translates string leaves, flattens nested keys with dotted paths, and preserves comments, ordering, and array syntax when writing. Dynamic PHP such as variables, function calls, constants, declare(...), or interpolated double-quoted strings is intentionally rejected. See File formats for the complete list of supported extensions, source examples, and writeback limitations. YAML/YML locale files should be mapping-shaped 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 silently corrupting metadata.
Generic XML mappings can point at non-Android XML locale files:
XML entries must be text-only leaf elements keyed by key, id, or name, or nested path-shaped leaves. Android <resources> files, mixed-content XML, and CDATA-preserving writeback are not handled by the generic XML parser. Windows Runtime .resw files use the same parser. Map one file per locale, typically under Strings/<locale>/:
Qt Linguist .ts catalogs use a dedicated parser. Map one file per locale. The CLI detects Qt from a <TS> root so TypeScript locale modules that also use .ts stay on the JavaScript parser:

CSV file mapping patterns

Use bucket file mappings to model CSV workflows. Per-locale files:
Shared multi-locale file:
For shared multi-locale CSV files, keep one key column and one target locale column that run can update consistently.

Fluent file mapping patterns

Use .ftl mappings for Mozilla Fluent locale files:
Hyperlocalise supports Fluent messages, attributes, multiline values, and select/plural values as full translation units. Attributes use dotted keys such as brand.title. Fluent terms are not supported and fail during parsing.

Subtitle file mapping patterns

Use .srt, .vtt, or .sbv mappings for SubRip, WebVTT, and YouTube SBV caption files:
Hyperlocalise translates cue payload text and preserves cue numbers, timestamps, WebVTT headers, and NOTE / STYLE / REGION blocks. Cues use sequential keys such as srt.0001 and sbv.0001. SBV files use comma-separated H:MM:SS.mmm timestamps and have no cue numbers.

JS/TS locale module patterns

Use JavaScript or TypeScript locale module mappings when your app imports locale objects directly:
Supported modules must export one static object, for example:
Hyperlocalise preserves comments, imports, export syntax, and non-message module text. It rejects dynamic values, computed keys, spread properties, multiple exported locale objects, and interpolated template literals.

Apple string catalog mapping patterns

Use .xcstrings mappings for Xcode string catalogs:
Hyperlocalise writes target values into localizations[targetLocale] and preserves catalog metadata. status and check read the requested target locale from the catalog. Variant and substitution source entries must include a source-language localization so Hyperlocalise can extract the source forms safely.

Android XML string resource mappings

Android XML support is intentionally scoped to string resource files named strings.xml under res/values* directories. Use Android locale qualifier names in your target paths:
Supported resource entries are <string name="..."> and <plurals name="..."><item quantity="...">. Resources marked translatable="false" are preserved and skipped. Unsupported translatable resource shapes such as <string-array> fail closed so they are not silently dropped.

INI file mapping patterns

Use .ini mappings for Windows-style localization files with one file per locale:
Keys before the first [section] stay unprefixed. Keys inside a section flatten as section.key. Hyperlocalise preserves sections, comments, separators, and key order on write.

Java properties file mapping patterns

Use .properties mappings for Java resource bundles with one file per locale:
Supported entries are flat Java properties keys with string values. Hyperlocalise preserves comments, separators, and key order on write; translated values are written as escaped single-line .properties values.

Groups

groups.<name> defines what to process together.
  • targets: subset of locales.targets
  • buckets: list of bucket names
groups is optional for beginner configs. Add it when you want to split execution by locale or file set.

LLM profiles

llm.profiles.<name> fields:
  • provider: openai, azure_openai, anthropic, gemini, bedrock, lmstudio, groq, mistral, ollama, openrouter, or ai_gateway
  • model: provider model id
  • system_prompt (optional): explicit system-message template
  • user_prompt (optional): explicit user-message template
  • prompt (deprecated, optional): legacy prompt template used as system fallback
Prompt variables:
  • {{source}}
  • {{target}}
  • {{input}}

Rules

llm.rules choose profile per group.
  • priority: higher wins
  • group: group name
  • profile: profile name
llm.rules is optional. When no rule matches a group, Hyperlocalise falls back to llm.profiles.default.

Translation routing

translation chooses, per group, whether tasks route to an LLM profile or a machine translation (MT) profile. It configures routing only; llm.profiles still defines provider/model/prompt behavior for every type: llm selection, and mt.profiles defines MT engines (see below).
  • translation.default (required): fallback selection used when no rule matches a group.
    • type: llm or mt
    • profile: profile name, resolved against llm.profiles when type: llm, or mt.profiles when type: mt
  • translation.rules (optional): ordered list of per-group overrides.
    • priority: higher priority wins. Priorities must be unique within the same group.
    • group: group name (must exist in groups, or be the implicit default group when groups is omitted)
    • type: llm or mt
    • profile: profile name, resolved the same way as translation.default.profile
For each group, Hyperlocalise uses the highest-priority translation.rules entry whose group matches. If no rule matches, it falls back to translation.default. When translation is omitted entirely, Hyperlocalise uses the legacy llm.rules/llm.profiles.default routing described above, unchanged.

Migrating from llm.rules

translation.rules and llm.rules cannot both be set. Setting both fails config validation with:
To migrate, move each llm.rules entry into translation.rules and add type: llm. llm.profiles itself does not change:

Machine translation (MT) profiles

mt.profiles.<name> defines an MT engine that translation.default/translation.rules can select with type: mt.
  • provider: google or deepl. These are the only supported providers today.
  • api_key_env (required): name of the environment variable that holds the API key. You choose this name yourself — unlike LLM providers, which read a fixed variable per provider (for example OPENAI_API_KEY), Hyperlocalise reads whatever variable name you put here. See Provider credentials for exported examples.
  • base_url:
    • Optional for google. Defaults to the real Google Cloud Translation endpoint when omitted.
    • Required for deepl, and must be exactly one of DeepL’s two API hosts: https://api.deepl.com (Pro accounts) or https://api-free.deepl.com (Free accounts). Any other value is rejected when the profile is selected.
A profile defined in mt.profiles is only checked and connected to when a translation rule or default actually selects it. Defining extra MT profiles you aren’t using yet does not require their environment variables to be set.

Mixed MT/LLM example

Here, the ui group has no matching rule and falls back to translation.default, so it routes to MT. The marketing group matches a rule and routes to the LLM profile instead — useful when some content (like marketing copy) needs LLM-quality nuance while the bulk of UI strings are translated more cheaply via MT. MT execution has no automatic fallback to an LLM profile on failure, batches requests, retries transient failures a bounded number of times, and reports character usage separately from LLM token usage. See run for the full execution behavior.

Hyperlocalise

hyperlocalise configures the public Hyperlocalise web API for sync push and sync pull when that block is present.
  • project_id (required unless project_id_env is set): Hyperlocalise project ID.
  • project_id_env (optional): environment variable that contains the project ID.
  • api_base_url (optional): API base URL. Defaults to https://hyperlocalise.com/api.
  • api_key_env (optional): environment variable that contains the API key. Defaults to HYPERLOCALISE_API_KEY.
  • timeout_seconds (optional): HTTP timeout for sync API calls. Defaults to 1200.
When hyperlocalise is set, sync push uploads source files and sync pull downloads translated files reconstructed by the API. Translation jobs are created by Hyperlocalise automation or in the web app, not by the CLI. A hyperlocalise block wins over storage.adapter when both are set. When hyperlocalise is absent, set storage.adapter so sync push and sync pull use TMS entry sync. That path uses the first bucket files[].to mapping and currently requires one concrete flat JSON locale file. Keep storage for provider-specific file commands as well. For API keys, sample config, and CI, see Connect the CLI.

Cache

cache configures the remote caching client.
  • enabled (optional): enable remote caching for run.
  • endpoint (optional unless enabled=true): remote cache service endpoint.
  • project_key_env (optional unless enabled=true): environment variable that contains the project cache key.
  • timeout_seconds (optional): remote cache request timeout in seconds.

Advanced example

QA policy

qa.policy_file points at a local snapshot of the project’s Cloud QA policy. check reads that path, and --qa-policy overrides it. validate takes the same file with --policy-file.
A relative path is resolved from the directory that contains the config file. The JSON file must be policy version 1 and list all 12 checks. See validate for the file shape, severities, glossary terms, and accepted spelling words.

Generate a starter

Then edit the generated i18n.yml for your project.

Validation tips

  • If you omit groups, every bucket runs for every target locale.
  • Keep group targets inside locales.targets.
  • Keep group buckets aligned with buckets keys.
  • Keep profile names consistent between profiles and rules.
  • Keep MT profile names consistent between mt.profiles and translation.rules/translation.default.
  • Do not set both llm.rules and translation — migrate llm.rules entries to translation.rules instead.
  • Use hyperlocalise when sync push and sync pull should talk to the Hyperlocalise API. That block wins if storage.adapter is also set.
  • Use storage.adapter without hyperlocalise when sync push and sync pull should run TMS entry sync. Keep storage for provider-specific file commands as well.