Nuxt.js Internationalization without route param
Nuxt.js Internationalization without route param
The code is available in a Github repository
There is an example in the official Nuxt.js documentation on how to implement i18n (Internationalization) in Nuxt.js.
This example shows you how to setup i18n in Nuxt.js so that you can add a parameter to your routes which determines the language of the page (e.g. /en/about
for english and /fr/about
for french).
However the disadvantage of putting the language in the route is that if for e.g. a french user shares the page to an english user, the english user will see the page in french and then has to switch the language.
The advantage of this approach is tho, that the site can be generated statically with Nuxt.js.
An alternative
If you do not need to generate your site statically, there is an alternative approach, which I will guide you through in this post:
- Omit putting the language in the route
- Use a cookie to let the backend know your prefered language
- Use the
accept-language
header as fallback if no prefered language is set in the cookies - If the prefered language in the cookie or the
accept-language
header is not available, fallback to a specified language
Here is how
Initialize a new Project
Create a new nuxt project and install the dependencies
vue init nuxt-community/starter-template <project-name>
cd <project-name>
npm install
Install i18n
Install the vue-i18n
npm package
npm install vue-i18n --save
Create an i18n plugin
Create the i18n plugin in plugins/i18n.js
with the following content
import Vue from 'vue';
import VueI18n from 'vue-i18n';
Vue.use(VueI18n);
export default ({ app, store }) => {
// Set i18n instance on app
// This way we can use it in middleware and pages asyncData/fetch
app.i18n = new VueI18n({
locale: store.state.locale,
fallbackLocale: 'en',
messages: {
'de': require('~/locales/de.json'),
'en': require('~/locales/en.json'),
'ru': require('~/locales/ru.json')
}
});
app.i18n.path = (link) => {
if (app.i18n.locale === app.i18n.fallbackLocale) {
return `/${link}`;
}
return `/${app.i18n.locale}/${link}`;
}
}
Create the store
Create the vuex store in store/index.js
with the following content
export const state = () => ({
locales: [
{
code: 'de',
name: 'DE'
},
{
code: 'en',
name: 'EN'
},
{
code: 'ru',
name: 'RU'
}
],
locale: 'en'
});
export const mutations = {
SET_LANG(state, locale) {
if (state.locales.find(el => el.code === locale)) {
state.locale = locale
}
}
};
- The
locales
array holds our available locales as javascript objects which both have acode
and aname
property- The
code
will be sent to the backend eventually to determine the language - The
name
will be used in the frontend in our Language Switcher
- The
- The
locale
property holds the currently active language - The
SET_LANG
mutation can be used to set the currently active language
Create the middleware
Create the middleware in middleware/i18n.js
with the following content
export default function ({ isHMR, app, store, route, params, req, error, redirect }) {
if (isHMR) { // ignore if called from hot module replacement
return;
}
if (req) {
if (route.name) {
let locale = null;
// check if the locale cookie is set
if (req.headers.cookie) {
const cookies = req.headers.cookie.split('; ').map(stringCookie => stringCookie.split('='));
const cookie = cookies.find(cookie => cookie[0] === 'locale');
if (cookie) {
locale = cookie[1];
}
}
// if the locale cookie is not set, fallback to accept-language header
if (!locale) {
locale = req.headers['accept-language'].split(',')[0].toLocaleLowerCase().substring(0, 2);
}
store.commit('SET_LANG', locale);
app.i18n.locale = store.state.locale;
}
}
};
- This middleware
- Checks if the
locale
cookie is set - If no
locale
cookie is set, use theaccept-language
header - Uses the
SET_LANG
mutation to set the currently active language depending on the previous checks
- Checks if the
Adjust the nuxt.config.js
Add the following to your nuxt.config.js
to implement the installed i18n library, the created middleware and the plugin
build: {
vendor: ['vue-i18n'],
},
router: {
middleware: 'i18n'
},
plugins: ['~/plugins/i18n.js'],
Create the locale files
- Create the file
locales/de.json
with the following content
{
"test": "german"
}
- Create the file
locales/en.json
with the following content
{
"test": "english"
}
- Create the file
locales/ru.json
with the following content
{
"test": "russian"
}
Display strings and create language switcher
Now we want the pages/index.vue
file to do the following
- Display the
test
language key defined in the locales files - Iterate through the
locales
array from the store- Display the
name
attribute of thelocale
object - Attaches a click listener to each
locale
which will execute theswitchLanguage
function - Adds the
active
class if thelocale
is the currently active one
- Display the
- The
switchLanguage
function will- Set the locale cookie to the selected
locale
’scode
value - Reload the page
- Set the locale cookie to the selected
Add the following to your pages/index.vue
file
<template>
<div class="language-switcher">
<div class="languages-label">{{ $t('test') }}: </div>
<div class="languages">
<div
class="language"
v-for="el in locales"
:key="el.code"
:class="{ active: (el.code === locale) }"
@click="switchLanguage(el.code)"
>
<span>{{ el.name }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
computed: {
locales() { return this.$store.state.locales },
locale() { return this.$store.state.locale }
},
methods: {
switchLanguage (localeCode) {
document.cookie = `locale=${localeCode}`;
location.reload();
}
}
}
</script>
<style>
.language-switcher {
display: flex;
padding: 1rem;
}
.languages {
display: flex;
justify-content: flex-end;
}
.language {
padding-left: .25rem;
cursor: pointer;
}
.language.active {
text-decoration: underline;
}
.language:hover span {
text-decoration: underline;
}
.language:not(:last-child):after {
content: '|';
padding-left: .25rem;
}
</style>
Test it
Run npm run dev
to try it out.
On the first visit, you should see the value of the test
key of your language (because of the fallback to use accept-language
header).
If your language however is not available, it will fallback to english.
You can switch the language by clicking on one of the displayed locale
names. This will set the locale
cookie and will therefore be persisted.