Give vue-i18n more superpowers❕

ew versions

So how does a basic vue-i18n setup look like?

Let’s get into it…

Prerequisites

Getting started

npx @vue/cli create vue-starter-project
# select vue 3 preset
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n';
import App from './App.vue'
export const i18n = createI18n({
locale: 'en', // set locale
fallbackLocale: 'en', // set fallback locale
messages: {
en: {
message: {
welcome: 'Welcome to Your Vue.js App'
}
},
de: {
message: {
welcome: 'Willkommen zu Deiner Vue.js App'
}
}
}
// If you need to specify other options, you can set other options
// ...
})
createApp(App).use(i18n).mount('#app')
<template>
<div class="hello">
<h1>{{ $t("welcome") }}</h1>
</div>
</template>
<script>
export default {
name: 'TranslationShowCase'
}
</script>
<template>
<img alt="Vue logo" src="./assets/logo.png">
<TranslationShowCase />
</template>
<script>
import TranslationShowCase from './components/TranslationShowCase.vue'
export default {
name: 'App',
components: {
TranslationShowCase
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Language Switcher

<template>
<div class="hello">
<h1>{{ $t("welcome") }}</h1>
</div>
<hr />
<div>
<div>
<a v-if="$i18n.locale !== 'de'" v-on:click="changeLanguage('de')">DE</a>
<strong v-if="$i18n.locale === 'de'">DE</strong>
&nbsp;|&nbsp;
<a v-if="$i18n.locale !== 'en'" v-on:click="changeLanguage('en')">EN</a>
<strong v-if="$i18n.locale === 'en'">EN</strong>
</div>
</div>
</template>
<script>
export default {
name: 'TranslationShowCase',
methods: {
changeLanguage(lang) {
this.$i18n.locale = lang
}
}
}
</script>

Component interpolation and directive

<template>
<div class="hello">
<h1>{{ $t("welcome") }}</h1>
</div>
<p>
<i18n-t keypath="descr" tag="label" for="doc">
<a href="https://cli.vuejs.org" target="_blank">{{ $t('doc') }}</a>
</i18n-t>
</p>
<div>
<div>
<span v-t="{path:'end'}" /> <!-- can also be written like: <i v-t="'end'" /> -->
</div>
</div>
<hr />
<div>
<div>
<a v-if="$i18n.locale !== 'de'" v-on:click="changeLanguage('de')">DE</a>
<strong v-if="$i18n.locale === 'de'">DE</strong>
&nbsp;|&nbsp;
<a v-if="$i18n.locale !== 'en'" v-on:click="changeLanguage('en')">EN</a>
<strong v-if="$i18n.locale === 'en'">EN</strong>
</div>
</div>
</template>
<script>
export default {
name: 'TranslationShowCase',
methods: {
changeLanguage(lang) {
this.$i18n.locale = lang
}
}
}
</script>
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
import App from './App.vue'
export const i18n = createI18n({
locale: 'en', // set locale
fallbackLocale: 'en', // set fallback locale
messages: {
en: {
message: {
welcome: 'Welcome to Your Vue.js App',
descr: 'For a guide and recipes on how to configure / customize this project, check out the {0}.',
doc: 'vue-cli documentation',
end: 'have fun!'
}
},
de: {
message: {
welcome: 'Willkommen zu Deiner Vue.js App',
descr: 'Eine Anleitung und Rezepte für das Konfigurieren / Anpassen dieses Projekts findest du in der {0}.',
doc: 'vue-cli Dokumentation',
end: 'habe Spass!'
}
}
}
// If you need to specify other options, you can set other options
// ...
})
createApp(App).use(i18n).mount('#app')

Where are the additional superpowers?

How does this look like?

import { createI18n } from 'vue-i18n'
import locizer from 'locizer'
const namespace = 'messages' // your namespace name added in locize
locizer.init({
projectId: 'your-locize-project-id'
})
export const i18n = createI18n({
locale: locizer.lng, // locizer.lng is the language detected in your browser.
fallbackLocale: 'en' // set fallback locale
// If you need to specify other options, you can set other options
// ...
})
// called from within setup hook in App.vue
export const loadMessagesPromise = new Promise((resolve, reject) => {
locizer.loadAll(namespace, (err, messages) => {
if (err) return reject(err);
Object.keys(messages).forEach((l) => {
i18n.global.setLocaleMessage(l, messages[l])
})
resolve(messages)
})
})
<template>
<img alt="Vue logo" src="./assets/logo.png">
<TranslationShowCase />
</template>
<script>
import { loadMessagesPromise } from './i18n'
import TranslationShowCase from './components/TranslationShowCase.vue'
export default {
name: 'App',
components: {
TranslationShowCase
},
// used in combination with Suspense.
// useful when translations are not in-memory...
async setup() {
await loadMessagesPromise
return {}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<Suspense>
<template #default>
<App />
</template>
<template #fallback>
<span>Loading...</span>
</template>
</Suspense>
</template>
<script>
import App from './App.vue'
export default {
name: 'Suspenser',
components: {
App
}
}
</script>
import { createApp } from 'vue'
import { i18n } from './i18n'
import App from './Suspenser.vue'
createApp(App).use(i18n).mount('#app')

save missing translations

import { createI18n } from 'vue-i18n'
import locizer from 'locizer'
const namespace = 'messages' // your namespace name added in locize
const apiKey = 'my-api-key' // used for handleMissing functionality, do not add your api-key in a production build
locizer.init({
projectId: 'your-locize-project-id',
apiKey
})
export const i18n = createI18n({
locale: locizer.lng, // locizer.lng is the language detected in your browser.
fallbackLocale: 'en' // set fallback locale
// If you need to specify other options, you can set other options
// ...
})
// called from within setup hook in App.vue
export const loadMessagesPromise = new Promise((resolve, reject) => {
locizer.loadAll(namespace, (err, messages) => {
if (err) return reject(err);
Object.keys(messages).forEach((l) => {
i18n.global.setLocaleMessage(l, messages[l])
})
resolve(messages)
})
})
export function handleMissing (locale, key) {
if (!apiKey) return
if (locale !== locizer.referenceLng) return
locizer.add(namespace, key, key)
}
<template>
<img alt="Vue logo" src="./assets/logo.png">
<TranslationShowCase />
</template>
<script>
import { useI18n } from 'vue-i18n'
import { loadMessagesPromise, handleMissing } from './i18n'
import TranslationShowCase from './components/TranslationShowCase.vue'
export default {
name: 'App',
components: {
TranslationShowCase
},
// used in combination with Suspense.
// useful when translations are not in-memory...
async setup() {
useI18n().setMissingHandler(handleMissing)
await loadMessagesPromise
return {}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<div class="hello">
<h1>{{ $t("welcome") }}</h1>
<h2>{{ $t("How are you?") }}</h2>
</div>
<p>
<i18n-t keypath="descr" tag="label" for="doc">
<a href="https://cli.vuejs.org" target="_blank">{{ $t('doc') }}</a>
</i18n-t>
</p>
<div>
<div>
<span v-t="{path:'end'}" /> <!-- can also be written like: <i v-t="'end'" /> -->
</div>
</div>
<hr />
<div>
<div>
<a v-if="$i18n.locale !== 'de'" v-on:click="changeLanguage('de')">DE</a>
<strong v-if="$i18n.locale === 'de'">DE</strong>
&nbsp;|&nbsp;
<a v-if="$i18n.locale !== 'en'" v-on:click="changeLanguage('en')">EN</a>
<strong v-if="$i18n.locale === 'en'">EN</strong>
</div>
</div>
</template>
<script>
export default {
name: 'TranslationShowCase',
methods: {
changeLanguage(lang) {
this.$i18n.locale = lang
}
}
}
</script>

👀 but there’s more…

🎉🥳 Congratulations 🎊🎁

👍

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Adriano Raiano

Adriano Raiano

founder of locize.com; Software Architect, Bachelor in Computer Science #serverless #nodejs #cqrs #ddd always in search for #innovative and #disruptive stuff