There's a lot of tutorials on how to setup multi-lingual support on client-side. But I didn't find any tutorial for doing it on nuxt server-side so I did it manually. So there it is!
Client-side setup
First of all let's look at how I did it on client-side
- Installing i18n module dependency
I used edge version
Manually adding to package.json
:
{
"devDependencies": {
"@nuxtjs/i18n": "npm:@nuxtjs/i18n-edge"
}
}
then npm i
- Configuring in
nuxt.config.ts
import locales from './locales'
export default defineNuxtConfig({
...
modules: ['@nuxtjs/i18n'],
i18n: {
lazy: true,
langDir: 'locales',
locales,
defaultLocale: 'en',
detectBrowserLanguage: false,
strategy: 'no_prefix',
},
...
})
I have chosen locales
folder for my .json translations and also have dedicated locales.ts
file to list them:
export default [
{
code: 'en',
name: 'English',
},
{
code: 'ru',
name: 'Русский',
},
].map(lang => ({ file: lang.code + '.json', ...lang }))
Example json translation files:
locales/en.json
{
"pageTitle": "Example page",
"unknownError": "Unknown error happend!"
}
locales/ru.json
{
"pageTitle": "Страница для примера",
"unknownError": "Произошла неизвестная ошибка!"
}
I extracted list of locales as locales.ts
to dedicated file because we will also use them in server-side
As you can see I have disabled detectBrowserLanguage
and strategy
to disable auto language detect and prefixes that allows to, for example, redirect from /en to / with the language set as English
The reason why is because right now it's buggy in nuxt and can't even detect my browser language so I implemented it on my own what you will see later
- In
app.vue
at the very end of script setup:
const { t } = useI18n()
await useConfigureI18n()
useHead({
title: computed(() => t('pageTitle')),
})
I called my custom useConfigureI18n
composable to detect browser's language and load/save it from/to cookie
Then I already used t
to set page title
Btw I strongly recommend using I18n Ally extension that can show translations in your code, automatically translate them for you using google translation for free and also find and extract raw strings into translations
-
composables/useConfigureI18n.ts
:
export default async () => {
const { getBrowserLocale, setLocale, locale } = useI18n()
const savedLang = useCookie('lang')
watch(locale, newLocale => {
if (savedLang.value != newLocale) savedLang.value = newLocale
})
await setLocale(savedLang.value || getBrowserLocale() || 'en')
}
Here I automatically detect browser language and syncronize it with cookie lang
- Language selector
We already can use t
to use translated messages but we also need to let users to select their language
<template>
<select v-model="locale">
<option
v-for="locale in locales"
:key="locale.code"
:label="locale.name"
:value="locale.code"
/>
</select>
</template>
<script setup lang="ts">
import locales from '@/locales'
const { locale } = useI18n()
</script>
Everything is ready on the client!
Server-side setup
For using I18n I decided to create my own middleware that will add $t
in event context for event handlers in our endpoints
server/middleware/i18n.ts
:
import { createI18n } from 'vue-i18n'
import locales from '../../locales'
import fs from 'fs-extra'
const i18n = createI18n({
fallbackLocale: 'en',
}).global
for (const locale of locales) {
i18n.setLocaleMessage(locale.code, fs.readJSONSync('locales/' + locale.file))
}
export default defineEventHandler(e => {
e.context.$t = (key: string) =>
i18n.t(key, getCookie(e, 'lang') || i18n.fallbackLocale.toString())
})
declare module 'h3' {
interface H3EventContext {
$t: typeof i18n.t
}
}
We already have user's language in cookie so we can use it to detect user's locale. So I created my wrapper of default t
that already passes user's locale
I used fs-extra
module. You can install it or use default fs
and then JSON.parse(fs.readFileSync('locales/' + locale.file))
And also we extending default H3EventContext
interface so TypeScript will know that we have $t
Then we can use it in our endpoints like so:
export default defineEventHandler(async e => {
return e.context.$t('unknownError')
})
You can check code in my cool pet project to compare
That's all! We finally have i18n in our app. Happy coding and using machine translation to make users tear their hair out!
Top comments (0)