i18next is the default choice for i18n in most React and Vue apps for good reason: it is flexible, framework-agnostic at its core, and its JSON-based resource format is simple enough to hand-edit on day one. The problems show up later, once you have real scale: hundreds of keys, plural forms across a dozen locales, and a team that is no longer just you. Here is what actually keeps an i18next setup healthy as it grows.
Namespace early, not "eventually"
A single giant translation.json works fine for a prototype and becomes unmanageable fast. Split resources into namespaces that mirror your app's structure (common, auth, billing, settings), so a translator (or an AI pass) working on billing copy is not scrolling past five hundred unrelated keys to find the ten that matter.
Namespacing also maps cleanly onto how a translation platform organizes work: keys stay grouped, filtering by "untranslated in billing" is a meaningful question, and reviewers can reason about one feature area at a time instead of the whole app.
Get plural rules right from the start
i18next's per-category key suffixes (as in seats.remaining_one and seats.remaining_other above, the JSON v4 form) are straightforward for English, but plural rules are genuinely different across languages: some have two forms, some have six (Arabic's zero/one/two/few/many/other, for example). If your editing workflow only ever shows you the English "singular vs. plural" split, you will ship broken pluralization the moment you add a language with more categories than that.
This is one of the places a dedicated translation tool earns its keep over hand-editing JSON: editing plural forms per CLDR category (not just singular/plural) means a translator working on Arabic or Polish sees exactly the categories that language requires, and nothing gets silently dropped.
Protect your placeholders
Interpolation tokens like {{count}}, {{date}}, or {{userName}} are the single most common thing that breaks in translation: a token gets mistranslated, reordered incorrectly, or dropped entirely, and you find out in production. Two habits help a lot: keep token names in English and semantically meaningful ({{userName}}, not {{x}}), and if you use AI-assisted first-pass translation, make sure it is running through a pipeline built to preserve tokens structurally rather than treating the string as free text.
Transglot's AI translation pipeline uses structured JSON output specifically designed to preserve placeholders and tokens, batching roughly 30 keys per chunk through Glossa. It is not a substitute for a human pass on customer-facing copy, but it removes the class of bug where a token silently disappears.
Keep your resource files in native i18next JSON: don't detour through CSV
A common anti-pattern: exporting strings to a spreadsheet for translators, then hand-converting back to JSON. Every round trip through CSV is a chance to lose nesting, mangle a plural key, or break a placeholder. Whatever tool manages your translations, favor one that reads and writes i18next's native JSON format directly (flat or nested, i18next supports both), so the file that comes back is the file your app actually loads, with no conversion step in between.
Make "add a language" a cheap operation
The real test of an i18n setup is not the first language. It is the fifth. When you add a new locale, every existing key needs a translation, and manually copying a few hundred keys into a new file is exactly the kind of work that gets postponed and then forgotten. Look for a workflow where adding a locale automatically surfaces (and ideally auto-backfills) the missing keys against your source language, rather than leaving you to diff two JSON files by hand.
Search and filter matter more than they seem to
At a few hundred keys, Ctrl+F in your editor is fine. At a few thousand, spread across namespaces and a dozen locales, you need typo-tolerant search (so "invocie" still finds "invoice") and a fast way to filter down to just what is untranslated. This is a small thing until it is the thing standing between you and shipping a release, at which point a virtualized, searchable grid genuinely beats scrolling a JSON file.
None of this requires abandoning i18next itself. It is still the right library for the runtime side of things. What changes as you scale is how you manage the resource files feeding it: namespaced, plural-aware, placeholder-safe, and editable by more than one person without a merge-conflict nightmare.