Add multilingual to your Next.js app.
Translate your locale files, Markdown content, and HTML pages through a single API call. Works with the App Router, next-intl, and any i18n routing setup.
Next.js gives you routing. It doesn't give you translations.
Next.js App Router has excellent built-in support for locale-based routing. Libraries like next-intl make managing translation files and locale switching straightforward. What they don't solve is the translation itself — someone has to produce the translated content in every language, and that someone is usually you. For most teams, the workflow is copy the English JSON into DeepL, fix the formatting it breaks, paste the result back, repeat for every language. It's slow, error-prone, and doesn't scale.
The most common workflow is to write all UI strings in English inside the source code, then translate the messages.json file for each target language. In theory this is straightforward. In practice, keeping 10+ locale files in sync with source changes becomes a recurring pain point. Every time English copy changes, every locale file needs updating. When using standard translation APIs for this, key names get corrupted, variable placeholders get translated, and the JSON structure drifts between locales — causing subtle runtime bugs that are hard to trace.
PolyLingo fits into your existing Next.js i18n setup.
If you use next-intl or any other i18n library, your messages are already in JSON. PolyLingo takes that JSON, sends it through the translation model, and returns translated copies for every target language — with keys untouched, nesting intact, and string values correctly translated. You can call it from a build script, a webhook, or the PolyLingo UI. The result drops directly into your messages directory.
The workflow: write your English messages.json. Run a single script that calls the PolyLingo API with your source file and all target language codes. Receive one translated JSON file per language, with identical structure. Write each to your messages/ directory. Commit. Done.
For content-heavy sites with Markdown in CMS (Sanity, Contentful), the same approach applies to content: export as Markdown or HTML, translate, write back to the CMS via its API. The whole pipeline can run as a build step or on a webhook trigger.
// This repository: frontend/scripts/translate-messages.mjs
// Chunks large namespaces (e.g. home) so the model stays within output limits.
//
// export POLYLINGO_API_KEY=pl_xxx
// npm run i18n:polylingo
//
// Writes messages/es.json, fr.json, … from messages/en.json via POST /v1/translate
// with format: "json". See MARKETING_I18N.md for options and CI notes.
//
// Minimal one-shot pattern (fine for small message files):
//
// const source = readFileSync('./messages/en.json', 'utf8')
// const { translations } = await fetch(apiUrl + '/translate', {
// method: 'POST',
// headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
// body: JSON.stringify({
// content: source, format: 'json', source: 'en',
// targets: ['es', 'fr', 'de'], model: 'standard',
// }),
// }).then((r) => r.json())
//
// for (const [lang, raw] of Object.entries(translations)) {
// const obj = typeof raw === 'string' ? JSON.parse(raw) : raw
// writeFileSync(`./messages/${lang}.json`, JSON.stringify(obj, null, 2))
// }// i18n.ts (next-intl v4)
import { getRequestConfig } from 'next-intl/server'
export const locales = ['en', 'es', 'fr', 'de', 'ja', 'zh', 'ko', 'pt', 'nl', 'it', 'ar'] as const
export type Locale = (typeof locales)[number]
export default getRequestConfig(async ({ requestLocale }) => {
const locale = await requestLocale
return {
locale,
messages: (await import(`./messages/${locale}.json`)).default,
}
})// package.json
{
"scripts": {
"dev": "next dev",
"build": "next build",
"i18n:polylingo": "node scripts/translate-messages.mjs",
"translate:build": "npm run i18n:polylingo && next build"
}
}Why PolyLingo fits the Next.js i18n workflow
- ✓Translate messages/*.json files directly — keys always preserved
- ✓Translate Markdown content for blog posts and docs pages
- ✓Works with next-intl, next-i18next, and custom setups
- ✓REST API integrates with build scripts and CMS webhooks
- ✓All 36 languages in a single request
- ✓Free tier — 100,000 tokens per month
- ✓This repo dogfoods the workflow: npm run i18n:polylingo regenerates marketing locales from messages/en.json (see MARKETING_I18N.md).
- ✓Works with App Router and Pages Router
- ✓Output files are ready to commit — no reformatting needed
Set up multilingual in your Next.js app
Set up next-intl with your English messages file
Install next-intl and configure your i18n.ts and middleware. Write all UI strings in messages/en.json. Structure the file however your app needs — flat or nested. This becomes your single source of truth.
Run the translate script
Use the PolyLingo JSON API from a small Node script (see code above). In this monorepo, run npm run i18n:polylingo from frontend/ with POLYLINGO_API_KEY set — it chunks large namespaces for reliability. Typical runs take well under a minute for a full marketing bundle.
Commit the locale files and deploy
The generated locale files are valid JSON with identical structure to your source. Commit them to your repo. Add the translate script to your CI pipeline to keep locales in sync with every content change.
Next.js multilingual use cases
SaaS apps and dashboards
Translate your entire UI string library in one script run. Supports all next-intl formatting features — dates, numbers, plurals — because the JSON structure is preserved exactly.
Content sites and blogs
For content-heavy Next.js sites using Sanity or Contentful, use PolyLingo to translate page content as well as UI strings — same API, same format preservation guarantees.
E-commerce with regional variants
Translate product names, descriptions, category pages, and checkout UI. Use the Advanced model for marketing copy where brand voice matters, Standard for functional UI strings.
Frequently asked questions
Does this work with the Next.js App Router?
Yes. The PolyLingo integration is just a script that reads and writes JSON files — it has no dependency on Next.js internals. It works with App Router, Pages Router, or any framework. The next-intl configuration example shown uses the v4 API with requestLocale, which is compatible with Next.js 13, 14, and 15.
What if my messages.json changes frequently?
The recommended pattern is to add the translate script to your CI/CD pipeline, triggered on changes to messages/en.json. This keeps all locale files in sync automatically. For teams with frequent copy changes, this prevents locale drift entirely.
Does PolyLingo work with next-i18next as well as next-intl?
Yes. next-i18next uses the same locale JSON structure. The translate script works identically — point it at your public/locales/en/ directory and write outputs to the other locale directories. The JSON format compatibility is the same.
What about dynamic content that is not in the messages file?
Dynamic content — blog posts, product descriptions, user-generated content — should be translated at the data layer, either in your CMS or via a build script that processes the content before it reaches Next.js. PolyLingo handles Markdown, HTML, and plain text equally well for this purpose.
Can I translate only the strings that have changed since the last run?
Incremental translation (only translating changed keys) is on the roadmap. Currently the script retranslates the full file. For most message files (under 20KB), this is fast enough to run on every commit. For very large files, splitting by namespace is the recommended approach.
Is there a way to review translations before they go to production?
The recommended pattern is to commit translated locale files to a separate branch or PR for review before merging to main. This is standard practice for teams that need human review on translation quality. PolyLingo generates a good first pass — for most UI strings the Standard model output requires no editing.
Related guides
Translate JSON locale files
How PolyLingo handles JSON structure, nested objects, and interpolation variables.
Multilingual for headless CMS
Translating content at the CMS level alongside UI string translation.
Translate Markdown without breaking formatting
For Next.js sites with Markdown blog posts or MDX pages.
Get your first locale file translated in under 5 minutes.
Free API key. No credit card. Paste your messages JSON and see the output immediately.
The translate script takes 5 minutes to set up. Free tier — no credit card required.