Vue i18n vs automatic translation: choosing the right approach for your Vue app (2026)
Vue has a mature, well-loved i18n library. It also has an ecosystem of DOM-based translation tools that require zero source-code changes. Which one is right for your project depends on factors most guides skip over — here's the honest breakdown.
Vue's i18n story
vue-i18n (created by kazupon, now maintained under the @intlify organisation as @intlify/vue-i18n-next) is the de facto standard for Vue internationalization. It has first-class support for both Vue 2 (vue-i18n v8) and Vue 3 (vue-i18n v9+).
The API is clean and well-documented. In a Vue 3 app with the Composition API:
// main.ts
import { createI18n } from 'vue-i18n'
const i18n = createI18n({
legacy: false,
locale: 'en',
fallbackLocale: 'en',
messages: { en, fr, de },
})
app.use(i18n)
Inside components you use the useI18n composable and the t() function:
<script setup lang="ts">
const { t } = useI18n()
</script>
<template>
<h1>{{ t('home.title') }}</h1>
<p>{{ t('home.description') }}</p>
</template>
In Vue 2 or the Options API, the same string is accessed as $t('home.title') in templates. The library is battle-tested, has an active community, and supports everything from simple string lookups to complex number/date formatting via the ECMAScript Internationalization API.
The maintenance burden
vue-i18n is powerful — but that power comes with a maintenance cost that compounds as your application grows:
- →JSON locale files per language. Every string in your app must be extracted into a key-value file for each supported language. A typical SaaS product has hundreds to thousands of keys. Each new feature means new keys in every locale file.
- →Keeping files in sync. When a developer adds a new UI string and forgets to update the French locale file, the fallback locale shows English to French users — often silently. Tooling like
vue-i18n-extracthelps but adds setup overhead. - →Bundle size and lazy-loading. Shipping all locale JSON upfront bloats the initial bundle. Lazy-loading per locale requires Vite/webpack async chunk configuration and handling the loading state during locale switches.
- →Plural rules per language. English has two plural forms; Russian has four; Arabic has six. vue-i18n handles this with ICU message syntax, but someone must write and verify the plural strings for each language.
- →Date and number formatting. Locale-aware formatting requires explicit
datetimeFormatsandnumberFormatsconfiguration per locale — hours of setup work before a user sees a correctly formatted date.
For a team without dedicated i18n engineers, this burden often means translation falls behind the product — shipping English strings to international users despite having “support” for their language.
When vue-i18n is the right choice
Open-source apps with community translations
If your project relies on community contributors to provide translations — common in open-source tools — vue-i18n's locale JSON files integrate cleanly with platforms like Crowdin or Weblate where translators work directly on the files.
Strict translation approval workflow
Legal, medical, or government applications where every string must be reviewed and approved before it reaches production benefit from the explicit, per-key control that vue-i18n provides.
Complex number, date, and currency formatting
Applications that display financial data, scientific measurements, or complex date ranges need per-locale formatting rules. vue-i18n's built-in ICU message support handles these cases systematically.
Apps requiring offline capability
If your Vue app must function offline (PWAs, Electron apps), all locale strings must be bundled and available without a network request. vue-i18n locale JSON files are bundled at build time.
When automatic translation wins
Existing Vue app adding multilingual without a rewrite
Retrofitting vue-i18n onto an existing Vue 2 or Vue 3 application means touching every component that renders text — often hundreds of files. A DOM-based translation widget requires a single script tag and zero component changes.
Teams without dedicated i18n engineers
Maintaining locale files accurately requires someone who understands both the product and each target language. Without that person, automatic translation produces better results than stale or incomplete locale files.
Rapid UI iteration
When the product is changing weekly, maintaining translation keys becomes a drag. Every UI copy change requires updating every locale file. Automatic translation handles new strings on first render without any developer action.
SaaS products prioritising speed to market
International revenue requires being live in those markets. A DOM-based approach gets you to “live in French” in an afternoon rather than after a 3-week engineering sprint.
How Lingvit works with Vue
Lingvit's widget is framework-agnostic — it operates at the DOM level, not the framework level. For Vue apps:
- →Add the script tag to your
index.htmlbefore</body>. Vue mounts after the script is parsed, and the widget initialises once the DOM is populated. - →A MutationObserver handles Vue's reactive rendering. When
v-ifreveals a section,v-forrenders a list, or a component mounts after an async operation, the new DOM nodes are translated immediately. - →Works with Vue 2 and Vue 3. The rendering internals differ, but the output is always DOM nodes — which is all the widget needs.
- →Nuxt.js is supported.For Nuxt 3 (server-rendered), add the script via Nuxt's
app.head.scriptinnuxt.config.tswithtagPosition: 'bodyClose'. For Nuxt 2 use theheadproperty innuxt.config.js.
Setup comparison
vue-i18n setup
- 1. Install
vue-i18nand configurecreateI18ninmain.ts - 2. Create
src/locales/en.json,fr.json, etc. - 3. Wrap every template string with
t()or$t()across every component - 4. Configure Vite plugin for lazy locale loading
- 5. Add locale switcher UI component
- 6. Fill in translation files per language
Lingvit setup
- 1. Add one
<script>tag toindex.html - 2. Select target languages in the dashboard
Frequently asked questions
- Does it work with Nuxt.js?
- Yes. For Nuxt 3, add the script via app.head.script in nuxt.config.ts with tagPosition: 'bodyClose'. Lingvit observes the final DOM after Nuxt's server-rendered HTML hydrates and after any client-side navigation via the Vue Router integration.
- Does it work with Vue 2?
- Yes. Lingvit is framework-agnostic and operates at the DOM level. Vue 2 and Vue 3 both produce standard DOM nodes, so the MutationObserver handles reactive updates regardless of which version your app uses.
- What about v-model inputs — will user-typed text be translated?
- No. Lingvit translates text nodes in the DOM but does not translate the value of input elements bound with v-model. User-entered content is excluded by default. You can also add the data-lingvit-ignore attribute to any element to exclude its subtree from translation.
Related guides
Add languages to your Vue app
Works with Vue 2, Vue 3, and Nuxt.js. One script tag, no rewrite.