Skip to content
July 8, 20265 min readGuides

i18n Without Translation Files? You Can Do That With i18next Today

"Translation files are the problem." It is a popular pitch in 2026: your components are the source of truth, so stop hand-maintaining per-locale JSON, let tooling generate translations, and treat locale files as build artifacts. A new wave of i18n tools is built on that argument.

The diagnosis is partly right. Hand-editing seventeen JSON files to add one sentence is nobody's favorite job. The part the pitch usually leaves out: the i18next ecosystem has supported exactly this workflow for years, with plain open-source libraries, and it can go one step further, because with CDN delivery there are no translation files in your repo at all, not even generated ones. Here is the recipe, followed by the honest trade-offs.

Key facts
  • Natural-language keys: t('Add to cart') with keySeparator: false; the source text is the key, and a missing translation renders the source. No English file needed.
  • Rich text stays in code: the Trans component serializes JSX children into the key, indexed tags and all.
  • New strings translate themselves: saveMissing reports them; automatic translation (your own LLM key or built-in) fills every target language; Quality Estimation scores each result.
  • No files, or files as artifacts, your choice: CDN delivery at runtime means zero locale files in the repo; CI extraction (i18next-cli) produces them as generated artifacts if you prefer.
  • What "no files" doesn't solve: terminology consistency, review, and "who approved this?". Files were never the real problem; ungoverned output is.

Step 1: make the code the source of truth

Two lines of configuration turn i18next into a natural-language-key system:

i18next.init({
  keySeparator: false,
  nsSeparator: false
})

Now the English text is the key:

t('Add to cart')

There is no en.json entry behind this. When no translation exists, i18next falls back to the key, and the key is the source text, so the app renders correctly from the first second. Rich text works the same way through the Trans component, which serializes its JSX children, markup included, into the key:

<Trans>Hello <strong>{{name}}</strong>, you have {{count}} unread messages.</Trans>

Translators see Hello <1>{{name}}</1>, you have {{count}} unread messages. and reorder the markup freely per language; your components keep owning the actual tags. Plurals and context suffixes keep working on top of natural keys, because they are key decorations, not separate files.

Step 2: let new strings report themselves

This is the piece that replaces "maintain the files": saveMissing. With saveMissing: true and i18next-locize-backend, every string your app renders for the first time is reported to Locize automatically, typically gated to development so production stays read-only:

i18next.init({
  saveMissing: process.env.NODE_ENV === 'development'
})

On the Locize side, automatic translation picks up each new source string and fills all target languages, on your own OpenAI, Gemini, Mistral or DeepL key if you bring one, with your glossary and styleguide injected into every request. Quality Estimation scores each result from 0 to 1, so confident translations save directly and doubtful ones route to review.

You write t('Your trial ends tomorrow'), reload the page, and the string exists in every language, scored, a few seconds later. Nobody opened a JSON file.

Step 3: deliver without files (or with them, generated)

At runtime, the same backend loads translations from the Locize CDN. Which means the strongest version of "translation files are build artifacts" is available here too, and then some: there are no locale files in your repository at all. A translation fix published in the editor is live without a commit, a build, or a redeploy.

Prefer a static pipeline, or need files for SSR/SSG? Take the CI path instead: i18next-cli extracts the same strings statically (it understands t() scopes and serializes Trans children exactly like react-i18next does), and the free locize/translate GitHub Action runs extract, sync, auto-translate and download on every push. The downloaded files are generated artifacts: commit them, or gitignore them and download at build time. Starting from an app that is not instrumented yet? npx i18next-cli localize takes it from hardcoded strings to localized in one command, and npx i18next-cli localize --print-agent-prompt prints the same flow as a runbook for your AI coding agent.

The honest trade-offs

Natural-language keys are a trade, not a free upgrade, and it is worth knowing what you pay. (For the full decision framework on key strategies, including when content-as-key is the right call and when it is not, see our guide to i18n key naming.)

  • Editing copy re-keys the string. Change "Add to cart" to "Add to basket" and it is a new key: freshly translated, while the old one is removed on the next sync. Translation memory softens this, prior reviewed translations come back as high-score matches, but for copy that churns weekly, stable keys with defaultValue are the better tool. i18next lets you mix both styles in the same project; many teams use natural keys for stable UI text and stable keys for marketing copy.
  • Long text makes long keys. A three-paragraph terms blurb as its own key is unpleasant in every tool that displays keys. Give those strings a stable key and a defaultValue.
  • Ambiguity needs context. English "Open" as a verb and as an adjective may need two different translations. i18next's context feature (t('Open', { context: 'button' })) covers it, but you have to notice the ambiguity; a file-first workflow does not save you from this either.

What "no files" does not solve

Removing file maintenance removes a chore. It does not remove the actual hard problems of localization, and this is where the "your code is the source of truth" pitch quietly ends: terminology that must not drift, formality that must not flip mid-app, legal strings that need human eyes, and the question "who approved this translation?", which a pipeline of unreviewed bot output answers with a commit hash. We wrote up what actually breaks in AI-only pipelines, and none of the failure modes involve file formats.

That is the real difference between workflows, files or not: whether translated output lands in a governed layer, with glossary-enforced consistency, quality scores, selective human review and an audit history, or lands directly in production. Keyless input plus ungoverned output is just faster drift.

Try the whole loop in an afternoon

Wire up natural-language keys and saveMissing in a branch, create a free Locize project, enable automatic translation, and watch new strings appear translated and scored as you click through your app. If you already run an AI-in-CI pipeline and wonder what state your locale files are in, the free i18n health check runs entirely in your browser and shows missing keys, duplicates and interpolation mismatches before you change anything.

Translation files were never the point. Trusted translations in production are, whether the files exist or not.

Tired of managing translations by hand?

Locize is the translation management backend by the i18next team: CDN delivery, AI translation, in-context editing, no redeploys.

Start your free 14-day trial