Globalize Your Vue App: A Practical Guide to Vue 3 Internationalization

Shah Moksha
Simform Engineering
8 min readJan 10, 2024

A step-by-step guide to creating an international website with Vue 3 and Vite.

Building web experiences that can cater to a diverse audience is important, and so is internationalization to create applications adapted to different languages and cultures.

Internationalization is also known as i18n, which means “I — eighteen letters — N”. It helps improve user experience through features such as language switching, date and time formatting, and number formatting.

Why Internationalization Matters

In today’s digital world, overlooking internationalization in your projects could mean leaving out a significant number of users who speak different languages or have diverse cultural preferences.

When you embrace internationalization, you’re not just making your websites or apps accessible, you’re also making them attractive and relatable to people from various backgrounds.

Key Concepts in Internationalization

  • Localization (L10n): Adapting an application for a specific language or region by translating text and adjusting date formats without altering the core functionality.
  • 0Translation: Converting UI labels, messages, and other user-facing text from one language to another while preserving the original meaning.
  • Globalization (G11n): Designing software to be easily adapted to different languages and regions, encompassing both internationalization and localization efforts.

So, let’s start exploring internationalization with the Vue internationalization example.

Vue I18n Plugin

Vue I18n is a powerful internationalization plugin for Vue.js applications that makes the process of handling multilingual content seamless. Before delving into the practical implementation, let’s grasp the key concepts of Vue I18n.

Core Concepts of Vue I18n

  • Locale
    A locale represents a specific language and region combination (e.g., ‘en-US’ for English in the United States). Vue I18n allows your application to switch between different locales dynamically.
  • Messages
    Messages are key-value pairs that hold the translations for your application. Each key corresponds to a specific phrase or sentence in your application, and its value is the translation in a particular language.
  • Translation
    The process of providing content in multiple languages. Vue I18n facilitates the storage and retrieval of translations based on the current locale.

Setting Up a Vue 3 Project

Step 1: Create a new Vue 3 project

Now, let’s use the command to create a new Vue 3 project. Navigate to the desired directory and run:

npm create vue@latest

Step 2: Install vue-i18n

  • To start with Vue 3 Internationalization, install the vue-i18n package. This can be done using npm or yarn.
  • Here are the respective commands to install the library:
npm install vue-i18n@9

or

yarn add vue-i18n@9

Step 3: VueI18n set up and configuration

  • After installation, create a new file src/i18n.js for configuration.
  • In this file, we will place all of the i18n’s configuration.

src/i18n.js

// src/i18n.js

import { createI18n } from "vue-i18n";
import en from "./locales/en.json";
import ar from "./locales/ar.json";

function loadLocaleMessages() {
const locales = [{ en: en }, { ar: ar }];
const messages = {};
locales.forEach((lang) => {
const key = Object.keys(lang);
messages[key] = lang[key];
});
return messages;
}
export default createI18n({
locale: "en",
fallbackLocale: "en",
legacy: false,
messages: loadLocaleMessages(),
});
  • The default locale that I want to configure is English:locale:'en'
  • Set legacy to false. By this, legacy API will be removed and only be left with the vue-i18n’s composition API
  • fallbackLocale:’en’:- Fallbacks come into play when a translation is missing for a specific locale. This ensures that even if a translation is unavailable for a specific locale, the user will still see content in a language they understand. In this case, we set it to en
  • Set message object to message property in the function, which returns value according to language (For message object, refer to next point as we need to add locale files for this step)
  • Once the configuration is done, import this file into our main.js

src/main.js

// src/main.js

import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import i18n from './i18n'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(router)
app.use(i18n).mount('#app')

Step 4: Create files for translating locales

  • First, create a folder named locales in the src folder
  • In this folder, create a file for all locales that you want to include for internationalization
  • For now, we will create two files: locales/en.js & locales/ar.js
  • As mentioned above, we import these two files in i18n.js for messages. Directory structure for different languages in the locales folder looks like:
Locales folder- Directory Structure
Locales Folder -Directory Structure

Locale Switching

  • As we build internationalized Vue.js applications, providing users with the ability to switch between different locales (languages) is a key feature.
  • Switching the locale is quite simple: Just assign the new locale to the locale property.

Let’s create a file and save it as components/LocaleSwitcher.vue

  • In it, create a dropdown button with the two languages we have in the locales folder.
  • Ensure that your language-sensitive content is properly set up in your Vue I18n messages.
// LocaleSwitcher.vue

<script setup></script>

<template>
<div class="locale-switcher">
<div class="locale-changer">
<select v-model="$i18n.locale" style="padding: 5px 15px;font-size: 16px;">
<option
v-for="locale in $i18n.availableLocales"
:key="`locale-${locale}`"
:value="locale"
>
{{ locale }}
</option>
</select>
</div>
</div>
</template>
  • Add this component to the navbar so we can change language easily
// Navbar.vue

<div class="nav__end">
<p class="user-greeting">{{ $t("user_greeting", { name: "Sam" }) }}</p>
<LocaleSwitcher />
</div>

Translations in Vue Component Files

How to use Vue I18n inside the Vue 3 components?

  • Once you have set up the global I18n instance, you can use it in your components. You can access the $t(translate) method to retrieve translations.
  • Another option is to import the useI18n composable function. This function returns the global composer instance.
  • Here’s an example:

$t (translate) method

<ul>
<li>{{ $t("about-sh") }}</li>
<br />
<li>{{ $t("about-para1") }}</li>
<li>{{ $t("about-para2") }}</li>
<li>{{ $t("about-para3") }}</li>
</ul>

Import useI18n composable function

<script>
import { useI18n } from "vue-i18n";
const { t } = useI18n();
</script>

<template>
<div class="nav">
<div class="nav__start">
<RouterLink to="/">{{ t("Home") }} </RouterLink>
<RouterLink to="/about">{{ t("About") }} </RouterLink>
<RouterLink to="/pluralization">{{ t("pluralization") }} </RouterLink>
<RouterLink to="/dateTime">{{ t("dateTime") }} </RouterLink>
<RouterLink to="/numbers"> {{t("numbers")}}</RouterLink>
</div>
</template>

Use VueI18n to Translate Your templates

Interpolations:- Vue I18n supports interpolation using placeholders {} like “Mustache”

  • Named interpolation:-
    The Named interpolation can be interpolated in the placeholder using variable names defined in JavaScript.
  • List interpolation:-
    The List interpolation can be interpolated in the placeholder using an array defined in JavaScript.
  • Literal interpolation:-
    The Literal interpolation can be interpolated in the placeholder using a literal string.
<li>
<span class="text-details">Named interpolation:</span>
{{ $t("home.popularItem", { item: "123456" }) }}
</li>
<li>
<span class="text-details">List interpolation:</span>
{{ $t("home.hey", ["hey","Good noon"]) }}
</li>
<li>
<span class="text-details">Literal interpolation(email):</span>
{{ $t("home.address", { account: "foo", domain: "domain.com" }) }}
</li>
   "home": {
"header": "vue i18n all examples",
"$tfunction": "hello text in function without import",
"iUseI18n": "ABCD text translation with import function",
"popularItem": "The most popular item on the website is the {item}, but not for long!",
"address": "{account}{'@'}{domain}",
"list": "{0} Sam, {1}"
},
  • Simple text:-
    To use a translation, use the $t() function with a translation id as a parameter, as already seen above.
<div>
<ul>
<li>{{ $t("about-para1") }}</li>
<li>{{ $t("about-para2") }}</li>
<li>{{ $t("about-para3") }}</li>
</ul>
</div>
  • Translating attribute values:-
    You can pass translated attribute values to sub-components this way.
<template>
<header-component :title="$t('main.hello')"></header-component>
</template>

Number and Date Formatting

Vue I18n provides built-in support for formatting numbers and dates according to the user’s locale.

Before diving into usage, let’s configure Vue I18n to handle number and date formatting. Update your Vue I18n instance in src/i18n.js:

const numberFormats = {
en: {
currency: {
style: "currency",
currency: "USD",
currencyDisplay: "symbol",
},
percent: {
style: "percent",
},
decimal: {
style: "decimal",
},
},
ar: {
currency: {
style: "currency",
currency: "AED",
currencyDisplay: "symbol",
},
percent: {
style: "percent",
},
decimal: {
style: "decimal",
},
},
};

const datetimeFormats = {
en: {
shortFormat: {
dateStyle: "short",
},
long: {
year: 'numeric', month: 'short', day: 'numeric',
weekday: 'short', hour: 'numeric', minute: 'numeric'
},
longDate:{
year: 'numeric', month: 'short', day: 'numeric',
},
longMonth:{
year: 'numeric', month: 'long', day: 'numeric',
}
},
ar: {
shortFormat: {
dateStyle: "short",
},
long: {
year: 'numeric', month: 'short', day: 'numeric',
weekday: 'short', hour: 'numeric', minute: 'numeric'
},
longDate:{
year: 'numeric', month: 'short', day: 'numeric',
},
longMonth:{
year: 'numeric', month: 'long', day: 'numeric',
}
},
};
  • We add this format to createI18n functions in i18n configurations:
export default createI18n({
locale: "en",
fallbackLocale: "en",
legacy: false,
messages: loadLocaleMessages(),
numberFormats,
datetimeFormats,
});
  • Number formatting:- The $nmethod is used for formatting numbers, and the second parameter corresponds to the defined formatting style.
<li>
<span class="text-details">Number Formatting:</span>
{ $n(7854, "currency") }}
</li>
<li>
<span class="text-details">currency with Name:</span>
{{ $n(7854, "currency", { currencyDisplay: "name" }) }}
</li>
  • Date formatting:- $d is the method for formatting dates, and ‘shortFormat’ is the defined date and time formatting style.
<li>
<span class="text-details"> Date Formatting short:</span>
{{ $d(new Date(), "shortFormat") }}
</li>
<li>
<span class="text-details"> Date Formatting long:</span>
{{ $d(new Date(), "longDate") }}
</li>

Pluralization

Pluralization is about changing the text depending on the values. e.g., in English, you want to say 1 flower but 2 flowers.

Pluralization is a crucial aspect of internationalization that addresses the challenge of adapting content based on numeric values.

  • Usage: Define the locale messages that have a pipe | separator and define plurals in the pipe separator.
  • Plural messages are selected by the logic of the choice rule in the translation API according to the numeric value you specify at the translation API.
  • Passing a number to the translation method will return appropriate translations.
"pl":{
"car": "car | cars",
"apple": "no apples | one apple | {count} apples"
},
<li>[value:0] {{ $t("pl.apple", 0) }}</li>
<li>[value: 1] {{ $t("pl.apple", 1) }}</li>
<li>[value: 10] {{ $t("pl.apple", 10, { count: 10 }) }}</li>

Create a Good Structure for Your Translation IDs

  • To enhance the organization and maintainability of your Vue I18n translations, consider structuring your translation messages in a well-defined JSON format.
  • This approach not only streamlines the management of multilingual content but also ensures consistency and clarity across your application.
  • JSON structure: Organize translations into logical sections or screens, each represented by an object.
"home": {
"header": "vue i18n all examples",
"$tfunction": "hello text in function without import",
"iUseI18n": "ABCD text translation with import function",
"popularItem": "The most popular item on the website is the {item}, but not for long!",
"address": "{account}{'@'}{domain}",
"hey": "{0} Sam, {1}"
},
  • Using JSON structure in Vue I18n:
    In your components, access translations by referencing the appropriate keys in your JSON file. For example:
<li>
<span class="text-details">Translation with import useI18n function:</span>
{{ t("home.iUseI18n") }}
</li>
<li>
<span class="text-details">when text is not found in locale:</span>
{{ $t("home.fallbackText") }}
</li>

Create References to Other Translations

  • Vue I18n allows you to create references to other translations within your JSON files.
  • This feature enables you to reuse common phrases or terms across different contexts, promoting consistency and simplifying the management of your multilingual content.
  • In this example, we use @:about-title
  • Built-in Modifiers:-
    Upper, Lower, Capitalize​

Syntax: @.modifier:key

  • upper: Uppercase all characters in the linked message
  • lower: Lowercase all characters in the linked message
  • capitalize: Capitalize the first character in the linked message
  • In this example, we use @.lower:about-title​ which will return a word in lowercase like “about us”.
"about-title": "About Us",
"about-subtitle": "hello to @:about-title​"
"about-sh": "Learn more @.lower:about-title",

GitHub Repository:

Vue Internationalization example: Practical-guide-Vue3-i18n

Live Demo Link:

Vue Internationalization Live Demo

Conclusion:

Vue 3 Internationalization is an important feature for building multilingual applications. With its powerful features, it allows developers to create and manage translations easily.

By following these guidelines, you can create high-quality multilingual applications using Vue 3 Internationalization.

For more updates on the latest tools and technologies, follow the Simform Engineering blog.

Follow us: Twitter | LinkedIn

--

--