Skip to content

Installation

Requirements

Peer dependencyVersionRequired
vue^3.3.0yes
vue-i18n^11.0.0yes
vite>=5.0.0only for the Vite plugin

Neither vue nor vue-i18n is bundled — they must be installed in the consuming project.

Installation

bash
npm install vue-i18n-kit vue vue-i18n

Quick start

1. Create locale files

src/
└── locales/
    ├── en.json
    └── ru.json
json
// locales/en.json
{
  "buttons": {
    "submit": "Submit",
    "cancel": "Cancel"
  },
  "greeting": "Hello, {name}!",
  "items": "{count, plural, one {# item} other {# items}}"
}
json
// locales/ru.json
{
  "buttons": {
    "submit": "Отправить",
    "cancel": "Отмена"
  },
  "greeting": "Привет, {name}!",
  "items": "{count, plural, one {# товар} few {# товара} many {# товаров} other {# товаров}}"
}

Tip: Run vue-i18n-kit init to scaffold step 1 automatically (locale files, config, Vite plugin). The wizard detects your entry file and prints the ready-to-paste snippet for step 2 below.

2. Register the plugin

This step is always manualvue-i18n-kit init never modifies main.ts, it only prints the snippet so you can paste it yourself.

ts
// main.ts
import { createApp } from 'vue'
import { createVueI18nPlugin } from 'vue-i18n-kit'
import App from './App.vue'

const app = createApp(App)

app.use(
  createVueI18nPlugin({
    defaultLocale: 'en',
    fallbackLocale: 'en',
    locales: {
      en: {
        messages: () => import('./locales/en.json'),
        meta: { display: 'English', flag: '🇬🇧' },
      },
      ru: {
        messages: () => import('./locales/ru.json'),
        meta: { display: 'Русский', flag: '🇷🇺' },
      },
    },
    persistLocale: true,
  }),
)

app.mount('#app')

3. Use composables in components

vue
<script setup lang="ts">
import { useT, useLocale, useAvailableLocales } from 'vue-i18n-kit'

const { t, tm } = useT()
const { locale, setLocale, isLoading, localeMeta } = useLocale()
const { availableLocales } = useAvailableLocales()
</script>

<template>
  <div>
    <p>{{ t('greeting', { name: 'Alice' }) }}</p>
    <p>{{ tm('items', { count: 5 }) }}</p>

    <select :value="locale" @change="setLocale(($event.target as HTMLSelectElement).value)">
      <option v-for="loc in availableLocales" :key="loc.code" :value="loc.code">
        {{ loc.meta?.flag }} {{ loc.meta?.display ?? loc.code }}
      </option>
    </select>

    <span v-if="isLoading">Loading…</span>
    <button :disabled="isLoading">{{ t('buttons.submit') }}</button>
    <p>Active: {{ localeMeta?.flag }} {{ localeMeta?.display }}</p>
  </div>
</template>