A small package for implementing translations in Vue.js. Instead of using a dot based key to fetch a translated string, it just uses the default string itself as the key.
In short {{ $t('Hello world') }}
instead of {{ $t('messages.hello_world') }}
.
Better yet: {{ 'Hello world' | translate }}
Designed for Vue 1, currently does not support Vue 2.
npm install voo-i18n
import Vue from 'vue'
import i18n from 'voo-i18n'
const translations = {
'es': {
'Hello world': 'Hola Mundo'
},
'fr': {
'Hello world': 'Bonjour le monde'
},
'pirate': {
'Hello world': 'Land ho!'
}
}
Vue.use(i18n, translations)
Set a default locale in the root data of your application.
<template>
<h1>{{ 'Hello world' | translate }}</h1>
</template>
<script>
export default {
data() {
return {
locale: 'en'
}
}
}
</script>
And then the translations will be reactive to changes in the locale
value.
You can override the root locale by passing in the locale param
<h1>{{ $t('Hello world', { locale: 'es' }) }}</h1>
Localization carries the problem of different languages having different dialects. For example, french vs. canadian french. You can make distinctions as such:
export default {
'fr': {
'Hello world': 'Bonjour le monde',
'Goodbye': 'Au Revoir'
},
'fr_CA': {
'Hello world': 'Bonjour tout le monde, du Canada'
}
}
When the locale is set to fr_CA
, {{ 'Goodbye' | translate }}
still translates to 'Au Revoir'
. You can also use a hyphen instead of an underscore if you prefer: fr-CA
.
Don't do this
<p>{{ 'You have used' | translate }} {{ count }} {{ 'out of' | translate }} {{ limit }}</p>
'es': {
'You have used': 'Ha utilizado',
'out of': 'fuera de'
},
Do this
<p>{{ $t('You have used {count} out of {limit}', {count, limit}) }}</p>
'es': {
'You have used {count} out of {limit}': 'Ha utilizado {count} de los {limit}'
},
It's often the case that your sentences will not form nice little compartmentalized strings like Hello world
. Often you'll get HTML spliced in the middle.
Don't do this
<p>{{ 'Please perform' | translate }} <a href="#" @click.prevent="action">{{ 'this action' | translate }}</a> {{ 'to complete the task' | translate }}</p>
'es': {
'Please perform': 'Por favor, realice',
'this action': 'esta acción',
'to complete the task': 'para completar la tarea'
},
Do this
<p v-locale="$root.locale" key="Please perform |this action| to complete the task">
<span></span>
<a href="#" @click.prevent="action"></a>
<span></span>
</p>
'es': {
'Please perform |this action| to complete the task': 'Por favor, realice |esta acción| para completar la tarea'
},
The directive element only expects to have children 1 level deep. So <span v-locale="es" key="a|b"><a><b></b></a></span>
will incorrectly render as <span><a>a</a></span>
. I haven't found an elegant solution around this yet. The main goal of this repo is to retain lingual context in translations and logical context in components, so it's an acceptable sacrifice for the time being, but if you have a solution please notify me.
<div v-locale="$root.locale" key="Thanks for signing up! Confirm |{email} is correct| to continue to the site." :replace="{ email: email }">
<span></span>
<a href="#" @click="confirm"></a>
<span></span>
</div>
'es': {
'Thanks for signing up! Confirm |{email} is correct| to continue to the site': 'Gracias por registrarte! Confirmar |{email} es correcta| para continuar al sitio'
},
If you provide translations for a locale and attempt to translate a string that is missing from the set that your provided, it will just fall back to the original string. If you have debug mode enabled, a warning will be sent to the browser console to help you maintain translations.
In the root of your main javascript folder, create an i18n folder. Create map.js
import es from './es'
import it from './it'
export let locales = [
{
value: 'es',
name: 'Spanish',
native: 'Español',
},
{
value: 'it',
name: 'Italian',
native: 'italiano',
}
]
export default {
es, it
}
And the respective translation files es.js
and it.js
// es.js
export default {
'Hello world': 'Hola mundo',
...
(however many hundreds more translations)
}
This way you can hand a single file to a human translator, and you can just import all translations.
import translations from './i18n/map'
Vue.use(i18n, translations)
later you can import the locales separately to list a dropdown or something
<template>
<a v-for="locale in locales" @click.prevent="setLanguage(locale.value)">
{{ locale.native }}
</a>
</template>
<script>
import { locales } as locale_list from './i18n/map'
export default {
computed: {
locales() {
return locale_list;
}
},
methods: {
setLanguage(value) {
this.$root.locale = value;
}
}
}
</script>