Skip to main content
This tutorial connects a Next.js app that uses next-intl to Hyperlocalise Platform. You keep nested JSON catalogs in the repository, review ICU messages and rich-text tags in Platform, and load the approved files at runtime. hl extract scans React Intl descriptors in .ts and .tsx files. It does not scan t('title') or useTranslations. Treat the locale JSON as the source of truth, and fail the pull request when a component key is missing from messages/en-US.json.

Prerequisites

You need:
  • a Next.js App Router app using next-intl;
  • 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. next-intl resolves dotted paths such as filters.saved.title. messages/en-US.json:
Use those keys in a component:
ICU keeps plural branches in one message. Translators may change the prose, but they must keep {name}, {count}, valid plural syntax, and rich-text tag names such as <guidelines>.
Do not set the file’s message format to i18next. next-intl uses ICU {name} and tags, not {{name}}. Leave the format on Auto or ICU.

2. Load catalogs in the app

Server Components can also call getTranslations from next-intl/server. Wrap Client Components in NextIntlClientProvider so they inherit the same messages.

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 split messages into several files per locale, add one mapping per file or merge the files before getRequestConfig loads them.

4. Catch missing keys in the source pull request

Type the English catalog into next-intl so TypeScript fails when a component calls a missing key:
Then preview the Platform upload:
Commit messages/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:
  • ICU arguments such as {name} and {count};
  • plural and select branches, including locale-specific categories;
  • rich-text tags such as <guidelines>;
  • labels that must fit compact layouts.
Approve the translations before pulling them back. A Japanese target may drop English one and keep other. hl check reports unreachable_plural_case when a translation keeps a category the locale never selects.

6. Pull and validate translations

Run:
hl check reports missing target keys, placeholder mismatches, icu_shape_mismatch, and unreachable_plural_case.
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 messages/en-US.json contains the nested path, getRequestConfig imports that file, and useTranslations uses the same namespace.

Content Editor flags <guidelines> as an HTML mismatch

Keep the same tag names in the translation. next-intl maps those names to React at the call site. Do not translate guidelines inside the angle brackets.

Pull writes FormatJS-shaped JSON

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

icu_shape_mismatch after a locale-specific plural

Argument names, block types, offsets, and exact matches such as =0 must still match the source. CLDR categories may differ by locale. If hl check reports unreachable_plural_case, delete the unused case from the translation.

Next