Skip to main content
This tutorial connects an app that uses i18next to Hyperlocalise Platform. You keep nested JSON catalogs in the repository, review interpolations such as {{name}} in Platform, and load the approved files at runtime. The same placeholder rules apply to other libraries that interpolate with double braces instead of ICU, including mustache, Handlebars, and many Polyglot-style catalogs that already use %{name}. hl extract scans React Intl descriptors in .ts and .tsx files. It does not scan t('key') calls. Treat the locale JSON as the source of truth, and fail the pull request when components introduce keys that are missing from locales/en-US.json.

Prerequisites

You need:
  • an app using i18next or a compatible interpolation library;
  • the Hyperlocalise CLI;
  • a Platform project with en-US as source and fr-FR and de-DE as targets; and
  • HYPERLOCALISE_API_KEY and HYPERLOCALISE_PROJECT_ID in your environment.
The example uses:

1. Keep copy in locale JSON

Write nested JSON with stable keys. i18next resolves dotted paths such as filters.saved.title. locales/en-US.json:
Use those keys in the app:
Keep interpolations in the catalog, not in concatenated strings. Translators may change the prose and move {{name}}, but they must keep the placeholder name, any format ({{val, number}}), unescape prefixes ({{- html}}), and $t(...) nesting calls.
i18next plurals are sibling keys (count_one, count_other), not one ICU {count, plural, ...} message. Cover 0, 1, and several items in tests. hl check reports placeholder mismatches on each key; it does not apply icu_shape_mismatch to these suffixes.

2. Load catalogs in the app

3. Map the catalogs

Create i18n.yml:
Hyperlocalise treats nested JSON as dotted keys such as filters.saved.title. It rewrites string leaves and keeps object structure. If you prefer TypeScript locale modules instead of JSON, map .ts files as described in i18n configuration.

4. Catch missing keys in the source pull request

Install i18next ESLint rules or eslint-plugin-i18next and fail CI when a component calls a key that is missing from the English catalog:
Then preview the Platform upload:
Commit locales/en-US.json with the component change.

5. Push and review

After the source pull request merges:
Start generation through a Source upload automation or New Request. In Content Editor, review:
  • interpolations such as {{name}}, {{count}}, and {{val, number}};
  • unescape prefixes such as {{- html}};
  • nesting calls such as $t(filters.saved.title);
  • plural sibling keys for one and other; and
  • labels that must fit compact layouts.
Approve the translations before pulling them back.

6. Pull and validate translations

Run:
hl check reports missing target keys and placeholder mismatches. Interpolation libraries do not use ICU plural blocks, so cover _one / _other branches in tests instead of expecting icu_shape_mismatch.
Open a translation pull request containing the pulled JSON. Run unit, build, and visual tests before merging it.

Troubleshooting

A component shows the key instead of copy

Confirm locales/en-US.json contains the nested path, i18next.init loads that file, and the t() call uses the same dotted key.

Content Editor flags {{name}} as invalid ICU

Hyperlocalise treats mustache and i18next interpolations as placeholders. If a string also contains real ICU ({count, plural, ...}), keep that ICU valid. Do not rewrite {{name}} to {name}; the runtime looks up name through interpolation, not ICU.

Nested $t(...) disappeared after translation

Restore the exact $t(key) call from the source. Nesting is a runtime lookup, not text to translate.

Pull writes FormatJS-shaped JSON

That happens when the source catalog is strict FormatJS (defaultMessage per id). i18next expects nested string leaves. Keep source JSON in the nested shape shown above.

Next