A basic sample using Locize with next-intl — the App Router counterpart of locize-react-intl-example. Same demo project, same keys, same texts. Walkthrough of this setup: next-intl + Locize guide.
Features supported:
- splitting translations into multiple namespaces (
common,anotherNamespace,macroNamespace) - in-context editor (
?incontext=true) - loading translations from the Locize CDN at runtime
- automatically pushing missing reference-language keys back to Locize in
dev (the next-intl equivalent of
saveMissing) - submit of description / context info alongside new keys
- detection of user language via the next-intl proxy (Next 16) / middleware
- ICU plural, select, number and date formatting
- ICU rich text (named tags) via
t.rich() - static prerendering of every locale
- works on Edge and Node.js runtimes (uses native
fetch)
-
Create a user account and a project at www.locize.com, then copy your project id and an API key from the developer page.
-
Either set the values directly in
src/locize-helper.ts, or export them as environment variables:export NEXT_PUBLIC_LOCIZE_PROJECTID=... export LOCIZE_APIKEY=... # server-only — never NEXT_PUBLIC_ export NEXT_PUBLIC_LOCIZE_VERSION=latest export NEXT_PUBLIC_LOCIZE_CDN_TYPE=pro # or 'standard' for the lite CDN
-
npm install && npm run devand http://localhost:3000 opens. Visit http://localhost:3000/de for the German variant. -
Refresh the page after editing strings in your Locize project to see the updated translations.
Out of the box this example targets the same public demo project as
locize-react-intl-example (da028c03-435a-4587-af3a-086de8c7bd9b). Most
keys in that project are empty by design — the example falls back to the
defaults declared in src/defaults.ts, and if you set
LOCIZE_APIKEY on first run, those defaults get pushed to Locize
automatically (mirroring react-intl's saveMissing flow).
This example expects the Locize project to be configured as icu /
messageformat with json flat publish format — same as the react-intl
example. The flat keys (app.title, app.intro, …) are unflattened in
src/locize-helper.ts before being passed to
next-intl, which expects a nested message tree.
If you're coming from i18next, two ICU differences to watch for:
| Concept | next-intl (ICU) | react-intl | i18next |
|---|---|---|---|
| Interpolation | {name} |
{name} |
{{name}} |
| Rich text element | <code>text</code> |
same | (not native) |
| Plural | {count, plural, …} |
same | key_one/_other |
| Number / date | {n, number} |
same | (via plugin) |
On dev boot, src/locize-helper.ts walks the
defaults in src/defaults.ts and:
- calls
locizer.add(ns, key, value, description)for any key that doesn't yet exist in the Locize reference language - calls
locizer.update(ns, key, value)for any key whose default value has changed since the last push
This only runs when NODE_ENV !== 'production' AND LOCIZE_APIKEY is set —
production builds never carry the API key and never write back. Keep your
write-enabled keys server-side; that's why the env var is LOCIZE_APIKEY
(not NEXT_PUBLIC_LOCIZE_APIKEY).
Append ?incontext=true to any URL (e.g.
http://localhost:3000/en?incontext=true) to launch the Locize InContext
editor. Login in the popup, then click any rendered string on the page to
edit it directly in Locize. Reload the browser to pick up the updated
translation.
This works because src/locize-helper.ts wraps
every leaf string with
i18next-subliminal
markers in development. The wrapping is automatically skipped in production
builds — none of the marker characters ship to your end users.
Translate via the Locize UI, then add the locale code to
src/i18n/routing.ts. Visit
http://localhost:3000/de (or whichever code you added) to see it.
Locize's languages list is cached for performance and may take up to an
hour to reflect the newly added language.
All Locize wiring is in src/locize-helper.ts — a
~150-line file. It uses the generic
locizer client to load each
namespace from the Locize CDN, overlays it on the local defaults, unflattens
the result, optionally wraps each leaf for the InContext editor, and hands
the tree to next-intl's
getRequestConfig.
// src/i18n/request.ts
import { getRequestConfig } from 'next-intl/server'
import { loadMessages } from '../locize-helper'
export default getRequestConfig(async ({ requestLocale }) => {
const locale = (await requestLocale) ?? 'en'
return { locale, messages: await loadMessages(locale) }
})That's the whole integration. No bespoke adapter package — locizer
handles the CDN, the cdnType variants, language detection, and write-back.
src/locize-helper.ts— all the Locize wiringsrc/defaults.ts— reference-language defaults for every demo keysrc/i18n/request.ts— next-intl request configsrc/i18n/routing.ts— supported localessrc/i18n/navigation.ts— locale-aware<Link>src/proxy.ts— next-intl proxy (Next 16 convention; formerlymiddleware.ts)src/components/LocizeInContext.tsx— bootstraps the InContext editorsrc/app/[locale]/layout.tsx— locale layoutsrc/app/[locale]/page.tsx— demo page
MIT — see LICENSE.
Built and maintained by the Locize team — the translation management service from the i18next maintainers.