Lingvit
  • React
  • i18n
  • Guide

React i18n vs automatic translation: which approach is right for your app? (2026)

10 min read

React teams have two fundamentally different paths to multilingual support: i18n libraries that instrument your source code, and automatic translation that works at the DOM level. Neither is universally better. This guide maps out when each approach is the right call.

The traditional React i18n approach

The standard libraries for React internationalization are react-i18next, react-intl (part of FormatJS), and LinguiJS. Despite their differences, they share the same core workflow:

  1. Replace every string in your components with a t() call: <p>Submit</p> becomes <p>{t('form.submit')}</p>.
  2. Create a JSON translation file per locale: en.json, fr.json, de.json, etc. Each key maps to a translated string.
  3. Handle pluralization per language — the rules for plurals in Polish or Arabic are significantly more complex than English.
  4. Add type-safe key definitions so TypeScript catches missing or mistyped translation keys at compile time (via typescript-i18n or i18next's own typing support).
  5. Configure the build or runtime to load the correct locale bundle, and set up a process so new strings added during development automatically surface in the translation workflow.

For a Next.js App Router project, add next-intl or next-i18next for locale routing and SSR-rendered translations.

The real cost of i18n libraries

The per-unit cost of each string wrapped in t() is small. The aggregate cost is significant:

Initial migration: 2–5 engineering days

For an existing React application with a year or more of UI development, auditing every component for hardcoded strings, wrapping them in t(), creating the initial translation namespace structure, and setting up the i18n provider is a multi-day project — even before any strings are translated.

Ongoing maintenance per new string

Every new UI string requires: a key definition, an English entry in the source locale file, and an update to every target language file. If the string is added in a PR on Tuesday, the translation files for French and German need to ship before the feature is visible to those users.

Context and namespace management

As translation files grow into hundreds or thousands of keys, namespace management becomes its own discipline. Keys need prefixes, namespaces need loading strategies, and the risk of key collision or unused-key accumulation increases over time.

RTL requires separate layout work

i18n libraries handle string translation but not layout direction. Supporting Arabic or Hebrew requires separate CSS work on top of the library setup — logical properties, icon mirroring, and testing under dir="rtl".

When i18n libraries are the right choice

There are specific situations where the overhead of a library is justified or even required:

  • Open-source projects When translation files are community-contributed on GitHub, a standard i18n library format (JSON or PO files) is the right interface for contributors. Automatic translation doesn't work for projects that want human community contributions.
  • Compliance-driven string review Regulated industries (legal, medical, financial) may require that every UI string is explicitly reviewed and approved before deployment. An i18n library makes this auditable — every string is a discrete artifact with a version history.
  • Heavy number, date, and currency formatting If your app displays formatted numbers, dates, and currency amounts throughout the UI (e.g., an analytics dashboard or accounting tool), libraries like FormatJS provide locale-aware formatting via the Intl API that DOM-based translation doesn't provide.
  • Offline-first apps Apps that must work offline (PWAs with full offline support) need bundled translation files because they can't call a translation API when there's no network. i18n libraries bundle translations at build time.

When automatic translation is better

The DOM-based approach is better suited to a different set of constraints:

  • Adding localization to an existing app without a rewrite The single strongest case for automatic translation. If you have a working React application and want to add five languages without touching 200 components, DOM-based translation is the only pragmatic option.
  • Teams without a dedicated i18n engineer Setting up and maintaining a library-based i18n system well requires expertise in the library, the translation workflow, and pluralization edge cases. A script-tag approach requires none of that.
  • Rapidly evolving UI When the product ships new UI every week, maintaining translation file parity is a constant friction. Automatic translation handles new strings on the first page visit with no additional steps.
  • Speed-to-market matters more than perfection A high-quality automatic translation live in a week beats a perfect i18n-library integration that ships in three months. For many international markets, the translation quality difference is not the deciding factor — presence is.

How DOM-based translation works in React

Lingvit uses a MutationObserver-based approach that integrates naturally with React's rendering model:

  1. On initial load, the script walks all existing text nodes in the DOM and sends them for translation. React's virtual DOM and rendering mechanism are invisible to this process — only the final rendered HTML matters.
  2. A MutationObserver watches for subsequent DOM mutations — new nodes added by React state changes, route transitions (client-side navigation in Next.js), lazy-loaded components, and dynamic content from API responses.
  3. Stored translations are fetched through the API. Switching languages does not require a page reload because translated strings are swapped in place.
  4. For RTL languages, document.documentElement.dir is set automatically, flipping any CSS logical properties in your layout.

Setup comparison

Supporting data for React i18n vs Automatic Translation: Which Approach Is Right for Your App? (2026)
Stepi18n libraryLingvit
Installnpm install react-i18next i18next1 script tag
Configurationi18n instance + provider + namespace config (~100 lines)Dashboard: pick languages
Instrument stringsWrap every string in t() across all componentsNo code changes
Translation filesJSON file per language, maintained in repoGenerated automatically, stored in Lingvit
Type safetyOptional via typescript-i18n (~50 lines config)Not applicable
New UI stringAdd key + update all locale filesTranslated on first page visit
RTL supportSeparate CSS work requiredAutomatic for Arabic, Hebrew, Persian, Urdu

Scroll horizontally to view every column.

Frequently asked questions

Does Lingvit work with React 18/19 Concurrent Mode and streaming SSR?

Yes. The MutationObserver approach is React-version-agnostic — it observes the final DOM output regardless of how React renders it. Concurrent Mode, Suspense, and streaming SSR all eventually produce DOM nodes, and the observer handles them normally. There are no React-version-specific APIs involved.

Does it work with Next.js App Router and server components?

Yes. Server Components produce HTML that is sent to the browser and inserted into the DOM just like any other HTML. The script tag in your root layout.tsx picks up this content normally. Client-side navigation handled by Next.js triggers the MutationObserver for the newly rendered content.

What about professional translators — can they still review strings?

Yes. Lingvit's dashboard provides a translation browser where professional translators can review, edit, and approve every string per language. Overrides are stored permanently and take precedence over automatic translations. This gives you the review workflow of an i18n library without maintaining translation files in your repository.