How to Translate i18next JSON Files in React & Next.js (2026)

You just wrapped up a React app that needs to ship in 12 languages by next Friday. Your locale files live in public/locales/en/common.json, you have 340 keys per locale, and the tokens inside your strings look like {{userName}} and {{count}} scattered across nested objects. You paste the JSON into ChatGPT, and it comes back with {{ nombreUsuario }}, extra spaces, and half the pluralization keys renamed. Your app crashes on build.
If you've tried to automate i18next JSON translation, you know this pain. The JSON format is flexible, which is exactly why most translation tools mangle it. The real problem is not the language model quality - it's that consumer-grade AI tools don't understand i18next's structural rules.
This guide walks through what makes i18next JSON different from other locale formats, why naive translation approaches break React and Next.js apps, and how to automate translation safely across dozens of locales without manually reviewing every key.
What Is i18next JSON and Why Translation Is Tricky
i18next is the most widely used i18n library in the JavaScript ecosystem. It powers React (react-i18next), Next.js (next-i18next, App Router next-intl), Vue, and Node backend services. It stores translatable strings in flat or nested JSON files, one per locale.
A typical file looks like this:
{
"welcome": "Welcome, {{userName}}!",
"cart": {
"empty": "Your cart is empty",
"items_one": "{{count}} item in your cart",
"items_other": "{{count}} items in your cart"
},
"errors": {
"network": "Network error. <strong>Please retry</strong>."
}
}
This looks simple, but three things make it dangerous to translate with general-purpose AI.
Interpolation Tokens Are Structural, Not Text
The sequence {{userName}} is not a word - it is a placeholder the runtime replaces with data. Add a space ({{ userName }}), rename it, or translate the inner identifier and the runtime fails silently or throws. Some translators helpfully convert {{count}} to {{conteo}} in Spanish. Your app now tries to interpolate a variable that does not exist and renders the raw placeholder to your user.
Pluralization Keys Are Magic Suffixes
i18next detects plurals by suffixes: _zero, _one, _two, _few, _many, _other. These are not arbitrary strings - they must match the CLDR plural categories for the target locale. English uses only _one and _other. Russian, Arabic, and Polish use up to six categories. If your translator drops _other or renames it, the fallback chain breaks.
Nested Keys Must Stay Intact
Unlike Gettext .po files, which are flat key-value pairs, i18next files can nest arbitrarily. A lazy translator might flatten the structure, change key names to match translated text, or reorder objects. Your t('cart.items_other') call in code no longer resolves.
Bad Solutions Developers Try First
Every team goes through the same three-stage failure cycle before they invest in a real solution.
Stage One: Paste into ChatGPT
You copy 200 keys into ChatGPT, ask "translate this JSON to Spanish," and paste the result back. It works for 180 keys. Twenty have spaces added inside {{...}}, three have plural suffixes rewritten, and one <strong> tag got translated to <fuerte>. Your build either fails or ships silently broken strings to production.
Stage Two: Google Translate API
You wire up the Google Translate REST API, iterate over your JSON, and send each value. Speed is great. Quality is not. Google's API treats each string in isolation - no context about your app, no understanding that {{count}} is a placeholder, no awareness that key cart.empty is different from cart.items_one. You still need human review on every key.
Stage Three: Commercial TMS Platforms
You sign up for a translation management system. They charge per word, require GitHub integrations, and lock you into monthly seats. For a side project or an indie app, the economics break down fast - and you still hit the same placeholder corruption problems if their engine does not parse i18next format specifically.
The same failure modes show up in Gettext workflows too. Our guide on how to translate .po files without breaking code variables covers the parallel problem for WordPress and other Gettext-based stacks.
The Safe Approach: Syntax-Aware Translation
The only reliable way to translate i18next JSON at scale is with a tool that parses the format first, locks the syntax, and only sends translatable text to the AI.
Here is what syntax-aware processing does under the hood:
- Parses the JSON into an abstract tree, preserving key paths and nesting.
- Identifies interpolation tokens (
{{name}},{{count, number}},{{date, datetime}}) and replaces them with placeholder IDs. - Identifies HTML tags inside Trans components (
<0>,<strong>,<br/>) and locks them. - Detects plural keys by suffix and maps them to CLDR rules for the target locale.
- Sends only the cleaned text to the LLM with context about the key path.
- Reinserts the original tokens and tags in their exact positions.
- Validates the output - if any placeholder is missing or malformed, reverts to source.
This is the same principle that makes cloud-based PO translation safe. If you are curious about the underlying architecture, our AI translation quality comparison breaks down how different LLMs handle these constraints.
Step-by-Step: Translate i18next JSON with SimplePoTranslate
SimplePoTranslate supports i18next JSON natively on Pro and Lifetime plans. Free tier currently covers .po and .pot - upgrade or use a trial to access JSON.
1. Prepare Your Source File
Use your English (or source locale) file as the master. Make sure it is valid JSON and contains all keys your app uses. A common mistake is leaving stale or unused keys, which burns your translation quota for strings you will never render.
# From your project root
cp public/locales/en/common.json ~/Desktop/common.json
2. Upload to SimplePoTranslate
Log in to your dashboard, click New Translation, and upload common.json. The platform auto-detects the i18next format. Pick your target language from the 41 supported locales, select a tone (professional, casual, marketing), and submit.
3. Let the Engine Work
Under the hood, the file is parsed, chunked into safe batches, and translated in parallel. Interpolation tokens are locked. Plural suffixes are preserved and mapped to the target locale's CLDR rules. HTML inside Trans components stays intact.
4. Download the ZIP
You get back a ZIP containing the translated JSON plus alternate formats (.php for PHP apps, .po for cross-tool compatibility). Drop the JSON into public/locales/es/common.json and redeploy.
unzip common_es.zip
mv common.json public/locales/es/common.json
npm run build
5. Repeat or Batch
For all 12 target locales, submit 12 jobs. Pro plan quotas cover dozens of typical SaaS apps. For monorepos with multiple namespace files, upload each separately or batch them sequentially.
Integrating Translations Back into Your App
Once you have translated JSON files, the integration is the easy part. A few gotchas:
- Verify plural categories. Run a quick smoke test per locale: render a component with
count={0},count={1},count={5}and confirm all three produce the right string. - Check RTL locales. If you translated to Arabic, Hebrew, or Persian, your UI needs RTL-aware CSS. Our WordPress RTL translation guide covers the CSS patterns that apply to React apps as well.
- Set up a fallback chain. Configure i18next to fall back to English if a key is missing, so mid-deploy states do not crash users.
- Lock your source file in CI. Add a check that rejects PRs where
en/common.jsonchanges without regenerating other locales. Translation drift is the single biggest cause of production i18n bugs.
For teams shipping across React, Next.js, and the server side, producing every format from one source is a huge win. Our post on one file in, five formats out explains why multi-format output matters for long-term maintenance.
When JSON Isn't Enough: Handling Complex Cases
A few edge cases need extra care.
ICU MessageFormat
If your project uses ICU syntax ({count, plural, one {1 item} other {# items}}), i18next treats it as interpolation but the structure is more complex. Make sure your translation tool recognizes ICU parameters and does not translate category names like one, other, or format identifiers like plural, number, date.
Trans Component with React Nodes
<Trans> renders React components inside translated strings, keyed by index (<0>, <1>). The translator must preserve the exact tag order. SimplePoTranslate's syntax lock handles this, but if you use a different tool, verify before shipping.
Namespace Files
Large apps split locales into namespaces: common.json, dashboard.json, checkout.json. Translate each file independently - do not merge them. Context quality is higher when each namespace's key paths stay scoped.
Putting It All Together
Translating i18next JSON for a React or Next.js app is not about picking the best AI model. It is about respecting the format's structural rules: interpolations, plural suffixes, nested keys, and HTML tags must survive the round trip. Consumer AI tools treat JSON as unstructured text. Syntax-aware tools parse it as structured data and only touch translatable surfaces.
If you are shipping a multilingual app and have been copy-pasting JSON into chat interfaces, you already know the cost: hours of manual review per locale, random production bugs, and a growing stack of broken plural forms. A format-aware pipeline removes every one of those failure modes.
Ready to translate your i18next JSON files safely? Try SimplePoTranslate free - no credit card required. Upload once, ship in 41 languages.