Translate Vue.js applications with gettext.
- Start with
- Installation
- Basic usage
- Workflow
- Configuration
- Annotating strings
- Message extraction and compilation
- Dependencies
To work correctly, you need to update NPM
to version 7+
.
For Windows, you can simply update Node.js to the latest stable version, or any other 15 +
version.
This is directly related to the fact that 3 ≤ npm version < 7
doesn't support installing peerDependencies
.
Before using the extract or compilation, in the root of the project, you need to create a locales
folder with the languages.json
file, where you describe a list of all languages used:
{
"ru_RU": "Русский",
"en_US": "English"
}
npm i github:alexshink/vue3-gettext
import { createApp } from 'vue';
import { createGettext } from '@jshmrtn/vue3-gettext';
import translations from './../locales/translations.json';
import languages from './../locales/languages.json';
const gettext = createGettext({
availableLanguages: languages,
defaultLanguage: 'en_US',
translations
});
createApp(App)
.use(gettext)
.mount('#app')
After installation, you need to do the first extraction and compilation to create the necessary files.
Use the component or directive to annotate translatable strings:
<translate>Hello!</translate>
<span v-translate>Hello!</span>
Or inject the plugin using useGettext
(Example of a language switcher):
<template>
<div class="language-switcher">
<select v-model="language.current">
<option v-for="(language, key) in language.available" :key="key" :value="key">{{ language }}</option>
</select>
</div>
</template>
<script>
import { useGettext } from '@jshmrtn/vue3-gettext';
export default {
name: 'LanguageSwitcher',
data() {
return {
language: useGettext()
}
}
}
</script>
-
Annotating strings: annotate all the translatable strings in your project using the
<translate>
component, thev-translate
directive or by calling the gettext functions (gettext
,pgettext
,ngettext
,npgettext
) directly. -
Extracting strings: you can now extract all strings to create message files. A message file is just a plain-text file with a
.po
file extension, representing a single language, that contains all available translation strings as keys and how they should be represented in the given language.vue3-gettext
provides scripts to make this straightforward. Take a look at the Message extraction and compilation section. -
Translating message files: a translator needs to fill out the translations of each generated
.po
files. I recommend you use software like poedit (some alternatives are listed on wikipedia here). -
Compiling translations: once all message files have been translated, use
gettext-compile
to make the translated.po
files usable in a Vue app. This will merge all translated.po
files into a.json
file ready to be used byvue3-gettext
.
The options you can pass to createGettext
are:
Type: { [key: string]: string }
Default: { en_US: "English" }
An object that represents the list of the available languages for the app whose keys are local names (e.g. en
or en_US
) and whose values are language names used for the display in UI, e.g. English (United States)
. It's exposed in all Vue instances via vm.$language.available
availableLanguages: {
en_GB: 'British English',
fr_FR: 'Français',
it_IT: 'Italiano',
},
Type: string
Default: 'en_US'
The local name of the default language, e.g. en_US
. This will be the current active language. It's exposed in all Vue instances via vm.$language.current
defaultLanguage: 'ru_RU',
Type: { [key: string]: { [key: string]: any } }
Default: {}
The JSON file of the application's translations (produced by gettext-compile
).
translations: {
"en_Use": {
"Color": "Color",
...
},
"de_DE": {
"Color": "Farbe",
...
}
},
Type: string[]
Default: []
Discard warnings for missing translations for all languages of the list. This is useful to avoid messages from the language used in source code.
mutedLanguages: ['fr_FR', 'de'],
Type: boolean
Default: false
Enable or disable logs/warnings for missing translations and untranslated keys.
silent: true,
Type: boolean
Default: true
Sets the options $gettext
$pgettext
$ngettext
$npgettext
$gettextInterpolate
$language
on app.config.globalProperties
, making the globally available in your templates. It is not recommended to disable this as easygettext
will not extract strings if your functions are not named exactly like this.
Type: boolean
Default: true
Registers the v-translate
directive on you application. If you disable this option and want to provide the directive yourself, you must make sure to name it translate
otherwise extraction will fail.
Type: boolean
Default: true
Registers the <translate>
component on you application. If you disable this option and want to provide the component yourself, you must make sure to name it translate
otherwise extraction will fail.
import { createApp } from 'vue';
import { createGettext } from '@jshmrtn/vue3-gettext';
import translations from './../locales/translations.json';
import languages from './../locales/languages.json';
const gettext = createGettext({
availableLanguages: languages,
defaultLanguage: 'en_US',
mutedLanguages: ['fr_FR'],
translations,
silent: true
});
createApp(App)
.use(gettext)
.mount('#app')
-
-
gettext-extract
to extract annotated strings from template files and produce a.pot
(Portable Object Template) file. -
gettext-compile
to produce the sanitized JSON version of a.po
file.
-
-
Some GNU gettext utilities to extract annotated strings from JavaScript files and generate
.po
files
vue3-gettext
exposes two scripts to simplify this process:
The extract script will create an output directory containing a .pot
file, directories and a .po
file for each locale. You can now edit the .po
files to translate your app before compiling them.
You may set a source directory to extract messages from, an output directory and a comma separated list of all the locales in your application.
By default, if you do not specify a list of locales, work is performed with all languages specified in the languages.json
file.
Extract for all languages:
vue-gettext-extract --src ./src --out ./locales
Extract for specified languages only:
vue-gettext-extract --src ./src --out ./locales --locales "de_CH,en_US"
The compile script will merge the contents of all the .po
files and combine them into a single translations.json
file that you can use with vue3-gettext
(in the createGettext
function).
You may set the directory where all your locales are located (the --out
directory of the extract script) and the locales.
By default, if you do not specify a list of locales, work is performed with all languages specified in the languages.json
file.
Compile for all languages:
vue-gettext-compile --dir ./locales
Compile for specified languages only:
vue-gettext-compile --dir ./locales --locales "de_CH,en_US"
Recommended setting up the scripts in your package.json
:
"scripts": {
"gettext": "npm run gettext:extract && npm run gettext:compile",
"gettext:extract": "vue-gettext-extract --src ./src --out ./locales",
"gettext:compile": "vue-gettext-compile --dir ./locales"
},
Strings are marked as translatable in your templates using either the translate
component or the v-translate
directive:
<translate>Hello!</translate> <span v-translate>Hello!</span>
This will automatically be translated. For instance, in French, it might read Bonjour!.
<translate>Hello!</translate>
<translate :translate-n="count" translate-plural="%{ count } cars">%{ count } car</translate>
<translate translate-context="Verb">Foo</translate>
<translate translate-comment="My comment for translators">Foo</translate>
You can set up translation strings that are agnostic to how your app state is structured. This way you can change variable names within your app, it won't break your translation strings.
<translate :translate-params="{name: userFullName}">Foo %{name}</translate>
It proves to be tricky to support interpolation with HTML content in Vue.js components because it's hard to access the raw content of the component itself.
So if you need to include HTML content in your translations you may use the directive.
The directive has the same set of capabilities as the component, except for translate-params which should be passed in as an expression.
<p
v-translate="{count: carNumbers}"
:translate-n="carNumbers"
translate-plural="<strong>%{ count }</strong> cars"
translate-comment="My comment for translators"
>
<strong>%{ count }</strong> car
</p>
When rendered, the content of the translate
component will be wrapped in a span
element by default. You can also use another tag:
<translate tag="h1">Hello!</translate>
You can use the tokens %{
and }
to for string interpolation within messages:
<translate>Hello %{ name }</translate>
Raw HTML in data is interpreted as plain text, not HTML. In order to output real HTML, you will need to use the render-html
attribute and set it to true
.
<p v-translate render-html="true">Hello %{ openingTag }%{ name }%{ closingTag }</p>
Dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to XSS vulnerabilities. Only use HTML render-html="true"
on trusted content and never on user-provided content.
Caveat when using either the component <translate>
or directive v-translate
with interpolation inside v-for
It's not possible to access the scope within v-for
, example:
<p>
<translate v-for="name in names">Hello %{name}</translate>
<span v-for="name in names" v-translate>Hello %{name}</span>
</p>
Will result in all Hello %{name}
being rendered as Hello name
.
You need to pass in custom parameters for it to work:
<p>
<translate v-for="name in names" :translate-params="{name: name}">Hello %{name}</translate>
<span v-for="name in names" v-translate="{name: name}">Hello %{name}</span>
</p>
It's not possible to support components or attributes like v-bind
and v-on
. So make sure that your HTML translations stay basic for now.
For example, this is not supported:
<p v-translate>Please <button @click="doSomething">click</button> here to view <my-account></my-account></p>
Strings are marked as translatable in your Vue instances JavaScript code using methods from the plugin.
const { $gettext } = useGettext();
$gettext(msgid);
const { $ngettext } = useGettext();
$ngettext(msgid, plural, n);
const { $pgettext } = useGettext();
$pgettext(context, msgid);
const { $npgettext } = useGettext();
$npgettext(context, msgid, plural, n);
You can use interpolation in your JavaScript using the method interpolate
in combination with one of the annotation functions.
const { $ngettext, interpolate } = useGettext();
const translated = $ngettext("%{ n } foo", "%{ n } foos", n);
const interpolated = interpolate(translated, { n: n });
interpolate
dynamically populates a translation string with a given context object.
Please make sure your code is properly formatted (the project contains a prettier
config) and all the tests run successfully (npm run test
) when opening a pull request.
Please specify clearly what you changed and why.
This plugin heavily relies on the work of the original vue3-gettext
.