Platforms
Next.js
Localize a Next.js app through its next-intl messages. The source file is pushed from the repository and every other language is pulled before the build.
What you get
Everything the editor does, through the files you already ship.
AI drafts, a person verifies
Every language is drafted against your glossary and each key's length limit. A draft never ships until someone has verified it.
Five checks on every save
Placeholders, length, terminology, consistency and missing translations are flagged on the row they concern, not in production.
Pull a subset by tag
Tag keys by feature or platform and pull only those, so one project can serve several apps without shipping each other's strings.
Runs in CI
Push the source language on merge and pull every language before the release build, on any CI that can run a shell.
CI pipelines
Set it up
From nothing to every language.
Step 1: Wire next-intl to the messages folder
The plugin in
next.config.tsand a request config that loadsmessages/<locale>.json. That folder is what anylocale writes to; nothing else in the app changes.next.config.tsimport createNextIntlPlugin from "next-intl/plugin"; const withNextIntl = createNextIntlPlugin(); export default withNextIntl({});src/i18n/request.tsimport { getRequestConfig } from "next-intl/server"; export default getRequestConfig(async () => { const locale = "de"; return { locale, messages: (await import(`../../messages/${locale}.json`)).default, }; });Step 2: Use the strings in a component
Namespaces follow the object path in the file; plurals resolve from the count.
src/app/page.tsximport { useTranslations } from "next-intl"; export default function Home() { const t = useTranslations("paywall"); return <button>{t("subscribe_cta")}</button>; }Step 3: Install the CLI and log in
Homebrew or the one-line installer, then a token issued per project under Settings, Integrations. The read scope pulls; push writes source files and values; manage creates and deletes keys.
shellbrew install anylocale/tap/anylocale anylocale login --project my-appStep 4: Push the source file
The push is additive: keys missing from the file stay in place, so a truncated file cannot empty a project. Descriptions in the file become translator notes.
shellcurl -fsS -X POST "https://anylocale.com/api/loc/push?project=my-app&format=next-intl" \ -H "Authorization: Bearer $ANYLOCALE_TOKEN" \ --data-binary @messages/en.jsonStep 5: Pull every language before the build
A script over the project's locales, run by npm before
next buildthrough the prebuild hook. Locally it runs on demand; in CI the token comes from a secret.package.json{ "scripts": { "prebuild": "sh scripts/pull-messages.sh", "build": "next build" } }scripts/pull-messages.sh#!/bin/sh set -e for locale in de fr ja; do anylocale pull --project my-app --locale $locale \ --format next-intl --out messages/$locale.json done
Good to know
- ICU plural and select syntax is stored as written and returned as written.
- Commit the source messages file and ignore the pulled ones, or commit them all; the pull overwrites a file only when it arrived complete.
- Every pull carries the current text of every key, verified or not. Only over-the-air delivery is limited to verified strings.
Questions
- When should the pull run?
- As the build's first step, so next build picks up every language. Locally, run it whenever a translation was verified and you want to see it.
- App Router or Pages Router?
- Both. The pull writes the messages files next-intl loads, and which router loads them makes no difference to the file.
- Can the web app share a project with the mobile apps?
- Yes. Tag the keys the web app uses and pull with --tag web, so the messages file carries only those.
Start with the file your app already ships.
After checkout, import one strings file and read the first drafts within minutes.
Nothing to connect and nothing to install. The CLI is optional.