Internationalization (i18n)
How to use Vue with i18n - free starter
This article will teach you how to integrate i18n with your project. You can start using directional classes with the latest Bootstrap 5.
Lets see how to integrate internationalization (i18n) with MDB 5 across our layout, components, and utilities.
Prerequisites
Before starting the project make sure to install the following utilities:
Creating a new project
First, we need to create a new Vite project.
Step 1
Init the project and choose vue framework. You can add a name for your project as we did in example below
npm init vite@latest my-vue-app
Step 2
Navigate to app's directory.
cd my-vue-app
Step 3
Install dependencies.
npm install
Step 4
Setup MDB.
npm install mdb-vue-ui-kit
Step 5
Import CSS. Add the following line at the beginning of your main.ts file:
import 'mdb-vue-ui-kit/css/mdb.min.css';
Step 6
Import Font Awesome and Roboto font. Add the following lines in public/index.html file inside
head
section:
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap" rel="stylesheet" />
Step 7
Enable sourcemaps during development.
export default defineConfig({
plugins: [vue()],
css: {
devSourcemap: true,
},
});
Step 8
Launch the application.
npm run dev
Installation
Once we have managed to launch our project, we have to add vite plugin vue i18n package.
Step 1
Navigate to your project and in your terminal run:
npm install --save-dev @intlify/vite-plugin-vue-i18n
And
npm install vue-i18n
Step 2
Create locales
folder inside your src
and create new json files with translations
{
"language": "English",
"date": "Date",
"question": "Please select a language",
"search": "Search",
"news1": "Some news",
"news2": "Another news",
"profile": "My profile",
"profileSettings": "Settings",
"profileLogout": "Logout",
"accordion1": "Item - One",
"accordion2": "Item - Two",
"accordion3": "Item - Three",
"accordionTxt": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae magna lacus. Fusce pretium urna id tellus ornare sagittis. Sed ac sagittis nibh, nec vehicula dolor. Cras et posuere mi",
"maskText": "Can you see me?",
"slide1Label": "First slide label",
"slide2Label": "Second slide label",
"slide3Label": "Third slide label",
"slide1Description": "English - Nulla vitae elit libero, a pharetra augue mollis interdum.",
"slide2Description": "English - Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"slide3Description": "English - Praesent commodo cursus magna, vel scelerisque nisl consectetur."
}
{
"language": "Polski",
"date": "Data",
"question": "Prosze wybrać język",
"search": "Wyszukaj",
"news1": "Wiadomości",
"news2": "Inne wiadomości",
"profile": "Mój profil",
"profileSettings": "Ustawienia",
"profileLogout": "Wyloguj",
"accordion1": "Przedmiot - Jeden",
"accordion2": "Przedmiot - Dwa",
"accordion3": "Przedmiot - Trzy",
"accordionTxt": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae magna lacus. Fusce pretium urna id tellus ornare sagittis. Sed ac sagittis nibh, nec vehicula dolor. Cras et posuere mi",
"maskText": "Czy mnie widzisz?",
"slide1Label": "Etykieta pierwszego slajdu",
"slide2Label": "Etykieta drugiego slajdu",
"slide3Label": "Etykieta trzeciego slajdu",
"slide1Description": "Polski - Nulla vitae elit libero, a pharetra augue mollis interdum.",
"slide2Description": "Polski - Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"slide3Description": "Polski - Praesent commodo cursus magna, vel scelerisque nisl consectetur."
}
{
"language": "日本語",
"date": "日にち",
"question": "言語を選択してください",
"search": "サーチ",
"news1": "ニュース",
"news2": "別のニュース",
"profile": "プロフィール",
"profileSettings": "セッティング",
"profileLogout": "ログアウト",
"accordion1": "アイテム - 1",
"accordion2": "アイテム - 2",
"accordion3": "アイテム - 3",
"accordionTxt": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae magna lacus. Fusce pretium urna id tellus ornare sagittis. Sed ac sagittis nibh, nec vehicula dolor. Cras et posuere mi",
"maskText": "私がみえますか?",
"slide1Label": "1 枚目のスライド ラベル",
"slide2Label": "2 番目のスライド ラベル",
"slide3Label": "3 番目のスライド ラベル",
"slide1Description": "日本語 - Nulla vitae elit libero, a pharetra augue mollis interdum.",
"slide2Description": "日本語 - Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"slide3Description": "日本語 - Praesent commodo cursus magna, vel scelerisque nisl consectetur."
}
{
"language": "Deutsch",
"date": "Datum",
"question": "Bitte wähle eine Sprache",
"search": "Suchen",
"news1": "Nachrichten",
"news2": "Andere Nachrichten",
"profile": "Mein Profil",
"profileSettings": "Einstellungen",
"profileLogout": "Ausloggen",
"accordion1": "Post - Ein",
"accordion2": "Post - Zwei",
"accordion3": "Post - Drei",
"accordionTxt": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae magna lacus. Fusce pretium urna id tellus ornare sagittis. Sed ac sagittis nibh, nec vehicula dolor. Cras et posuere mi",
"maskText": "Können Sie mich sehen?",
"slide1Label": "Etikett des ersten Objektträgers",
"slide2Label": "Etikett des zweiten Objektträgers",
"slide3Label": "Etikett des dritten Objektträgers",
"slide1Description": "Deutsch - Nulla vitae elit libero, a pharetra augue mollis interdum.",
"slide2Description": "Deutsch - Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"slide3Description": "Deutsch - Praesent commodo cursus magna, vel scelerisque nisl consectetur."
}
Step 3
Add vueI18n
property to your vite config file. It should look like in example below.
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "url";
import vueI18n from "@intlify/vite-plugin-vue-i18n";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueI18n({
// if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
// compositionOnly: false,
// you need to set i18n resource including paths !
include: resolve(
dirname(fileURLToPath(import.meta.url)),
"./src/locales/**"
),
}),
],
css: {
devSourcemap: true,
},
});
Step 4
Let's not forget to add our json files with translations to main.ts file
import "mdb-vue-ui-kit/css/mdb.min.css";
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
import { createI18n } from "vue-i18n";
import en from "./locales/en.json";
import pl from "./locales/pl.json";
import ja from "./locales/ja.json";
import de from "./locales/de.json";
const i18n = createI18n({
legacy: false,
locale: "en",
messages: {
en,
pl,
ja,
de,
},
});
createApp(App).use(i18n).mount("#app");
Adding new content
After we go through all the previous steps, we can start developing our application. Let's change the content of HelloWorld.vue so that we can check if the app is working properly
Before that, lets clear App.vue
file. You can also clear style.css
file to make it look like in our demo.
<template>
<HelloWorld />
</template>
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
</script>
And now you can try some example we have prepared for you. Just copy the code below.
<template>
<MDBNavbar expand="lg" light bg="light" container id="main-navbar">
<form class="d-none d-md-flex input-group w-auto my-auto">
<MDBInput
wrapperClass="col-auto"
:label="t('search')"
v-model="searchInput"
/>
<span class="input-group-text border-0">
<MDBIcon icon="search"></MDBIcon>
</span>
</form>
<MDBNavbarNav right class="d-flex flex-row">
<MDBDropdown v-model="dropdown1" class="nav-item me-3 me-lg-0">
<MDBDropdownToggle
tag="a"
class="nav-link"
@click="dropdown1 = !dropdown1"
>
<MDBIcon icon="bell" />
<MDBBadge notification color="danger" pill>1</MDBBadge>
</MDBDropdownToggle>
<MDBDropdownMenu>
<MDBDropdownItem href="#">{{ t("news1") }}</MDBDropdownItem>
<MDBDropdownItem href="#">{{ t("news2") }}</MDBDropdownItem>
</MDBDropdownMenu>
</MDBDropdown>
<MDBDropdown v-model="dropdown2" class="nav-item me-3 me-lg-0">
<MDBDropdownToggle
tag="a"
class="nav-link"
@click="dropdown2 = !dropdown2"
>
<i :class="`flag ${pickedLanguage} mx-auto`"></i>
</MDBDropdownToggle>
<MDBDropdownMenu>
<MDBDropdownItem href="#" @click="locale = 'en'">
<i class="flag-united-kingdom flag"></i>English
</MDBDropdownItem>
<MDBDropdownItem href="#" @click="locale = 'pl'">
<i class="flag flag-poland"></i>Polski
</MDBDropdownItem>
<MDBDropdownItem href="#" @click="locale = 'ja'">
<i class="flag flag-japan"></i>日本語
</MDBDropdownItem>
<MDBDropdownItem href="#" @click="locale = 'de'">
<i class="flag flag-germany"></i>Deutsch
</MDBDropdownItem>
</MDBDropdownMenu>
</MDBDropdown>
<MDBDropdown v-model="dropdown3" class="nav-item me-3 me-lg-0">
<MDBDropdownToggle
tag="a"
class="nav-link"
@click="dropdown3 = !dropdown3"
>
<img
src="https://mdbootstrap.com/img/new/avatars/2.jpg"
class="rounded-circle"
height="22"
alt=""
loading="lazy"
/>
</MDBDropdownToggle>
<MDBDropdownMenu>
<MDBDropdownItem href="#">{{ t("profile") }}</MDBDropdownItem>
<MDBDropdownItem href="#">{{ t("profileSettings") }}</MDBDropdownItem>
<MDBDropdownItem href="#">{{ t("profileLogout") }}</MDBDropdownItem>
</MDBDropdownMenu>
</MDBDropdown>
</MDBNavbarNav>
</MDBNavbar>
<MDBContainer>
<MDBRow>
<MDBCol lg="6" class="mx-auto my-5">
<MDBCarousel v-model="carousel1" :items="items1" fade />
</MDBCol>
</MDBRow>
<MDBRow class="mb-5">
<MDBCol lg="6" class="mb-4 mb-lg-0">
<section class="mx-auto d-flex align-items-center">
<div class="bg-image">
<img
src="https://mdbootstrap.com/img/new/standard/city/053.webp"
class="w-100"
alt="Sample"
/>
<div class="mask" style="background-color: rgba(0, 0, 0, 0.6)">
<div
class="d-flex justify-content-center align-items-center h-100"
>
<p class="text-white mb-0">{{ t("maskText") }}</p>
</div>
</div>
</div>
</section>
</MDBCol>
<MDBCol lg="6" class="mb-4 mb-lg-0">
<MDBAccordion v-model="activeItem">
<MDBAccordionItem
:headerTitle="t('accordion1')"
collapseId="collapseOne"
>
{{ t("accordionTxt") }}
</MDBAccordionItem>
<MDBAccordionItem
:headerTitle="t('accordion2')"
collapseId="collapseTwo"
>
{{ t("accordionTxt") }}
</MDBAccordionItem>
<MDBAccordionItem
:headerTitle="t('accordion3')"
collapseId="collapseThree"
>
{{ t("accordionTxt") }}
</MDBAccordionItem>
</MDBAccordion>
</MDBCol>
</MDBRow>
</MDBContainer>
<MDBFooter :text="['center', 'lg-start']">
<div class="text-center p-3" style="background-color: rgba(0, 0, 0, 0.2)">
© 2022 Copyright:
<a class="text-dark" href="https://mdbootstrap.com/">MDBootstrap.com</a>
</div>
</MDBFooter>
</template>
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { ref, computed } from "vue";
import {
MDBIcon,
MDBNavbar,
MDBNavbarNav,
MDBDropdown,
MDBDropdownToggle,
MDBDropdownMenu,
MDBDropdownItem,
MDBInput,
MDBBadge,
MDBAccordion,
MDBAccordionItem,
MDBCarousel,
MDBContainer,
MDBRow,
MDBCol,
MDBFooter,
} from "mdb-vue-ui-kit";
const { locale, t } = useI18n({
inheritLocale: true,
useScope: "global",
});
const dropdown1 = ref(false);
const dropdown2 = ref(false);
const dropdown3 = ref(false);
const searchInput = ref("");
const activeItem = ref("collapseOne");
const pickedLanguage = computed(() => {
switch (locale.value) {
case "en":
return "flag-united-kingdom";
case "pl":
return "flag flag-poland";
case "ja":
return "flag flag-japan";
case "de":
return "flag flag-germany";
default:
return "flag-united-kingdom";
}
});
const items1 = computed(() => [
{
src: "https://mdbootstrap.com/img/Photos/Slides/img%20(15).webp",
alt: "...",
label: t("slide1Label"),
caption: t("slide1Description"),
},
{
src: "https://mdbootstrap.com/img/Photos/Slides/img%20(22).webp",
alt: "...",
label: t("slide2Label"),
caption: t("slide2Description"),
},
{
src: "https://mdbootstrap.com/img/Photos/Slides/img%20(23).webp",
alt: "...",
label: t("slide3Label"),
caption: t("slide3Description"),
},
]);
const carousel1 = ref(0);
</script>
More about i18n
For more information, see vite plugin vue i18n github page. There you can read about other options, bundle optimizations etc.
Frontend features
MDB UI KIT:
To create the project we used our ui kit, with which we can build basic views very quickly.
Views and Layouts:
In this project we used HelloWorld.vue
file, created by vite tool in which we placed our vue
code. We have successfully integrated i18n into the MDB package and can use the appropriate translations based on provided json
files.