Lingvit
  • Vue
  • i18n
  • Guide

Vue i18n vs automatic translation: choosing the right approach for your Vue app (2026)

8 min read

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-extract helps 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 datetimeFormats and numberFormats configuration 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.html before </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-if reveals a section, v-for renders 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.script in nuxt.config.ts with tagPosition: 'bodyClose'. For Nuxt 2 use the head property in nuxt.config.js.

Setup comparison

vue-i18n setup

  1. Install vue-i18n and configure createI18n in main.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 to index.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.