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.

Live preview

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.