Multi-language support
- Install the Internationalization plugin for Vue
ps
npm install vue-i18n
npm install @intlify/unplugin-vue-i18n
- Add plugin to
./vite.config.ts
ts
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
// ...
export default defineConfig({
plugins: [
// ... other plugins
VueI18nPlugin({}),
],
})
- Create some initial localization files.
@/i18n/en.json
- / EN file
json
{
"welcome": "Welcome",
"logout": "Logout",
"login": "Login",
"app.actions.login": "App actions login",
"app.actions.logout": "App actions logout",
"app.messages.welcome": "App messages welcome",
"Request failed with status code 403": "Request failed with status code 403",
"you.are.not.allowed.to.access.this.page": "You are not allowed to access this page",
"copied.to.clipboard": "Copied to clipboard"
}
@/i18n/en.json
- / FR file
json
{
"welcome": "Bienvenue",
"logout": "\"Déconnexion\"",
"login": "Connexion",
"app.actions.login": "\"Actions d'application connexion\"",
"app.actions.logout": "\"Actions de l'application déconnexion\"",
"app.messages.welcome": "\"Messages d'application bienvenus\"",
"Request failed with status code 403": "La requête a échoué avec le code d'état 403",
"you.are.not.allowed.to.access.this.page": "Vous n'êtes pas autorisé à accéder à cette page",
"copied.to.clipboard": "Copié dans le presse-papiers"
}
@/i18n/sandbox/en.json
- /sandbox EN file
json
{
"sandbox.title": "Sandbox title",
"sandbox.content": "Sandbox content",
"sandbox.missing": "Sandbox missing",
"View": "View",
"": "",
"Delete": "Delete",
"This is a snack message": "This is a snack message",
"close": "Close",
"unauthorized": "Unauthorized"
}
@/i18n/sandbox/fr.json
- /sandbox FR file
json
{
"sandbox.title": "\"Titre du bac à sable\"",
"sandbox.content": "\"Content of the sandbox\"",
"sandbox.missing": "\"Bac à sable manquant\"",
"View": "Vue",
"": "You didn't write any text that needs translation. Could you please provide the text?",
"Delete": "Supprimer",
"This is a snack message": "\"C'est un message de collation\"",
"close": "Fermer",
"unauthorized": "Unauthorized"
}
Translation File Structure:
src/i18n/
├── en.json # Base English translations
├── fr.json # Base French translations
└── moduleA/ # Module-specific translations
├── en.json
└── fr.json
⚠️ translation structure can be only one level deep, so everything under moduleA
has to be included in either base or module translation files.
- Create i18n configuration
@/plugins/i18n.ts
ts
import { createI18n } from 'vue-i18n'
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: 'en',
fallbackLocale: 'en',
messages: {
en: {},
fr: {},
},
fallbackWarn: false,
missing: handleMissing,
})
export default i18n
function handleMissing(locale: string, key: string) {
//eslint-disable-next-line
//@ts-ignore
const i18nStore = useI18nStore()
i18nStore.addTranslation(locale, key)
}
- Initialize i18n in main.ts
ts
// ...
import i18n from './plugins/i18n'
// ...
app.use(i18n)
// ...
- Test
Modify @/App.vue
vue
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
import { useI18n } from 'vue-i18n'
const { t, locale } = useI18n()
function toggleLocale() {
locale.value = locale.value === 'en' ? 'fr' : 'en'
}
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<HelloWorld msg="You did it!" />
<nav>
<v-btn @click="toggleLocale()">{{ locale }}</v-btn>
<RouterLink to="/">{{ t('app.home') }}</RouterLink>
<RouterLink to="/about">{{ t('app.about') }}</RouterLink>
<RouterLink to="/sandbox">Sandbox</RouterLink>
</nav>
</div>
</header>
<RouterView />
</template>
And @/pages/sandbox/index.vue
vue
<template>
<v-card :style="useCardBackground('#00AA00')">
<v-card-title><v-icon icon="$mdiHome" />{{ t('sandbox.title') }}</v-card-title>
<v-card-text>{{ t('sandbox.content') }}</v-card-text>
<!-- ... -->
</v-card>
</template>
<script setup lang="ts">
// ...
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
// ...
</script>