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

to let the backend know your prefered language Use the accept-language header as fallback if no prefered language is set in the cookies

header as fallback if no prefered language is set in the 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 }) => { 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 a code and a name 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

array holds our available locales as javascript objects which both have a and a property The locale property holds the currently active language

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) { return ; } if (req) { if (route.name) { let locale = null ; 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 (!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 the accept-language header Uses the SET_LANG mutation to set the currently active language depending on the previous checks



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

language key defined in the Iterate through the locales array from the store Display the name attribute of the locale object Attaches a click listener to each locale which will execute the switchLanguage function Adds the active class if the locale is the currently active one

array from the store The switchLanguage function will Set the locale cookie to the selected locale 's code value Reload the page

function will

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.