SaaS localization guide: go global without rewriting your app (2026)
Most SaaS products delay internationalization for years — not because it's unimportant, but because the conventional approach requires a full engineering project before a single user sees a translated string. This guide shows you what the alternatives look like in practice.
The SaaS localization problem
The standard advice for SaaS localization is to adopt an i18n library: react-i18next, i18next, or formatjs. Each of these libraries requires the same multi-step migration:
- →Wrap every UI string in a
t()call, touching hundreds of components across the codebase. - →Create and maintain a JSON translation file per target language.
- →Add type-safe key definitions so missing translations surface at compile time.
- →Implement pluralization rules — which differ significantly between languages.
- →Set up a translation workflow so new UI strings get translated before they ship.
For a typical SaaS product with a year or two of development behind it, this is a 2–4 week engineering project before any user sees a translated string. Teams rationally deprioritize it until international revenue becomes impossible to ignore.
What actually needs to be translated
Before picking an approach, it helps to enumerate what “the product” actually means in translation terms. For a typical SaaS application:
| Content type | In DOM? | Widget approach |
|---|---|---|
| UI strings, navigation, buttons | Yes | Covered automatically |
| Error messages and notifications | Yes (when shown) | Covered via MutationObserver |
| Onboarding flows and help text | Yes | Covered automatically |
| Dynamic content after API responses | Yes (after render) | Covered via MutationObserver |
| Email templates | No | Out of scope — needs separate solution |
| Strings hardcoded in JS bundles | Only if rendered | Covered when rendered to DOM |
Scroll horizontally to view every column.
The vast majority of what users interact with in a web app renders into the DOM. That makes DOM-based translation a practical starting point even when it can't cover every edge case.
The DOM-based alternative
A script-tag translation widget takes a different approach: instead of instrumenting your source code, it observes the rendered HTML in the browser and translates it in place.
The mechanism works like this:
- 1On page load, the script walks the DOM and collects text nodes, grouping them into blocks for efficient API calls.
- 2Translated strings are returned from the API and swapped into the DOM. The original text is preserved in memory.
- 3A MutationObserver watches for new DOM nodes — triggered by navigation, modal opens, API responses populating a list — and translates them immediately.
- 4Stored translations can be reused without another provider-generation request.
Test switching behavior on representative devices and networks. The script-tag approach can leave the application source code untouched.
What to watch out for
The DOM-based approach handles the 80–90% case well, but there are specific situations to evaluate for your product:
Strings that never render to the DOM
If your app builds a string in JavaScript and passes it to a toast library or alert, the intermediate JS string may be constructed before it reaches the DOM. Once it hits a DOM text node, the widget covers it — but if the string is displayed in a native browser alert()or a non-DOM overlay, it won't be translated.
User-generated content
Content that users write — comments, notes, rich text editors — is translated when rendered, which may not be desirable. Use Lingvit's exclusion selectors to mark UGC containers as untranslatable.
Backend email templates
Transactional emails (welcome, invoice, password reset) are sent server-side and never pass through the DOM. These require separate handling — either through your email service's localization features or by maintaining separate email templates per language.
API response strings
If your backend returns strings that are displayed directly (e.g., status labels from an API), they are covered once rendered into the DOM. If the same strings appear in non-rendered contexts (downloaded CSVs, webhooks), those are out of scope.
Setup for a React/Next.js SaaS
Adding Lingvit to an existing React or Next.js application takes three steps and no code changes to your components.
- 1
Sign up and create a project
Create a project at app.lingvit.comand register your application's domain. You'll receive a project key.
- 2
Add the script tag to your root layout
In Next.js App Router, add it to
app/layout.tsx:<Script src="https://cdn.lingvit.com/widget.bundle.js?v=1" strategy="afterInteractive" />For Pages Router or vanilla React, paste the
<script>tag before the closing</body>. - 3
Select target languages in the dashboard
Choose your target languages from the dashboard. The language switcher is injected automatically. Translations start generating on the first page visit for each language.
Editorial control
Automatic translation handles the volume — but product names, legal terms, and branded language need human oversight. Lingvit provides several control mechanisms:
Translation browser
Review every translated string per language and override any automatic translation directly in the dashboard. Overrides are stored permanently and take precedence over automatic translations for that string.
Glossary terms
Define terms that must never be translated — product names, feature names, brand-specific terminology. Glossary entries are applied globally across all languages.
Publish controls
Translations go live only when you publish them. Draft and review a language before it's visible to users, then publish without a code deployment.
Frequently asked questions
- Does the widget work with React concurrent features and Suspense?
- Yes. The MutationObserver approach is framework-agnostic — it observes the final DOM output regardless of how React renders it. Concurrent Mode, Suspense boundaries, and streaming SSR all produce DOM nodes that the observer handles normally.
- What about SSR — will translated content be indexed by search engines?
- Client-side widget translation means the source HTML contains the original language. For SaaS dashboards behind authentication, this rarely matters. For public-facing marketing pages where multilingual SEO matters, a script-tag approach is less suitable than server-rendered i18n.
- Can I use this alongside an existing i18n library for new features?
- Yes. Lingvit translates whatever is in the DOM — it doesn't care whether strings come from an i18n library, a hardcoded string, or an API response. You can use react-i18next for new features and let Lingvit cover the rest during a migration period.
Related guides
Go global this week
Add translation to your SaaS without changing a line of code.