# How to Build a **Vue.js Quiz Application** with **vue-i18n** Multi-Language Support

> Learn to build a Vue.js quiz application with vue-i18n multi-language support. Initialize vue-i18n, manage translations, and display localized content easily.

- Repository: [Microsoft/AI-For-Beginners](https://github.com/microsoft/AI-For-Beginners)
- Tags: tutorial
- Published: 2026-08-27

---

**You can build a multilingual Vue.js quiz application by initializing vue-i18n in your entry file, consolidating translation files by language in a centralized index, and accessing localized quiz data through the `$t` helper in components.**

The `microsoft/AI-For-Beginners` repository demonstrates a production-ready implementation of a **Vue.js quiz application with vue-i18n multi-language support** inside the `etc/quiz-app/` directory. This Vue 2 project structures quiz content as language-agnostic data objects, allowing the entire interface to switch locales at runtime without reloading.

## Initializing the vue-i18n Plugin in Vue 2

The first step wires the internationalization library into the Vue instance. In [`src/main.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/src/main.js), the code imports `VueI18n`, registers it with `Vue.use()`, and creates a new instance defining English as both the default and fallback locale.

```js
// src/main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import VueI18n from 'vue-i18n';

Vue.use(VueI18n);

const i18n = new VueI18n({
  locale: 'en',          // default language
  fallbackLocale: 'en', // fallback language
});

new Vue({ i18n, router, render: h => h(App) }).$mount('#app');

```

According to the source code at [`etc/quiz-app/src/main.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/etc/quiz-app/src/main.js) (lines 6-14), passing the `i18n` object to the root Vue constructor injects the translation functionality into every child component.

## Organizing Translation Files for Multi-Language Quizzes

### Creating the Translation Index

All language packs are aggregated in [`src/assets/translations/index.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/src/assets/translations/index.js). This file imports quiz data from each language folder and exports a single `messages` object that maps locale codes to their respective content.

```js
// src/assets/translations/index.js
import englishQuizzes from './en';
import spanishQuizzes from './es';

const messages = {
  en: englishQuizzes,
  es: spanishQuizzes,
};

export default messages;

```

This index file is imported into [`main.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/main.js) and fed directly into the `VueI18n` constructor, making the entire message catalog available application-wide.

### Defining Language-Specific Quiz Content

Inside each language folder (e.g., `src/assets/translations/en/` and `src/assets/translations/es/`), an [`index.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/index.js) exports an identical data structure containing quiz titles, questions, options, and correct answers. Because the schema is consistent across languages, switching the locale key automatically swaps the content while preserving component logic.

```js
// src/assets/translations/en/index.js
export default {
  quizTitle: 'JavaScript Basics',
  questions: [
    {
      id: 1,
      text: 'What does `===` compare?',
      options: [
        { label: 'Value only', value: 'value' },
        { label: 'Type only', value: 'type' },
        { label: 'Both value and type', value: 'both' },
      ],
      answer: 'both',
    },
    // …more questions
  ],
};

```

The Spanish translation follows the same pattern, ensuring that `this.$t('questions')` always returns an array the component can iterate over, regardless of the active language.

## Rendering Localized Content in Components

Components consume translations via the `$t()` method injected by vue-i18n. Templates reference keys directly, while computed properties can cache complex objects like the full questions array.

```vue
<!-- Quiz.vue -->
<template>
  <section>
    <h1>{{ $t('quizTitle') }}</h1>
    <div v-for="q in questions" :key="q.id" class="question">
      <p>{{ q.text }}</p>
      <ul>
        <li v-for="opt in q.options" :key="opt.value">
          <label>
            <input type="radio" :name="q.id" :value="opt.value" />
            {{ opt.label }}
          </label>
        </li>
      </ul>
    </div>
  </section>
</template>

<script>
export default {
  name: 'Quiz',
  computed: {
    title() { return this.$t('quizTitle'); },
    questions() { return this.$t('questions'); },
  },
};
</script>

```

Because the quiz data is structured as a nested object rather than flat strings, components can loop through `$t('questions')` and access properties like `q.text` and `opt.label` that automatically reflect the current locale.

## Implementing Runtime Language Switching

Users can switch languages without page reloads by mutating the `$i18n.locale` property. A language selector component calls a method that updates this value, triggering reactive updates in all components using `$t`.

```js
// LanguageSwitcher.vue
export default {
  methods: {
    setLanguage(lang) {
      this.$i18n.locale = lang;
    },
  },
};

```

As implemented in the `microsoft/AI-For-Beginners` source code, this approach works because the translation objects in `src/assets/translations/` share identical keys and data shapes, allowing Vue's reactivity system to swap content seamlessly.

## Configuring Vue Router for i18n Compatibility

The routing setup in [`src/router/index.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/src/router/index.js) uses a standard Vue-Router configuration without special internationalization handling. Since all text lookups occur through the global `$i18n` instance, routes remain agnostic to the current language. The source file at [`etc/quiz-app/src/router/index.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/etc/quiz-app/src/router/index.js) demonstrates this pattern, separating navigation logic from translation concerns.

## Summary

- **Initialize vue-i18n** in [`src/main.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/src/main.js) by registering the plugin, creating a `VueI18n` instance with `locale` and `fallbackLocale` settings, and injecting it into the root Vue constructor.
- **Structure translations** by creating language folders inside `src/assets/translations/` and aggregating them via an [`index.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/index.js) that exports a `messages` object.
- **Mirror data shapes** across all language files so that switching locales updates content without breaking component logic.
- **Access translations** in components using the `$t()` method, which reacts to locale changes automatically.
- **Switch languages** at runtime by assigning a new value to `this.$i18n.locale` in any component method.

## Frequently Asked Questions

### How does vue-i18n handle missing translations in a Vue.js quiz application?

When creating the `VueI18n` instance in [`src/main.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/src/main.js), the `fallbackLocale: 'en'` parameter ensures that if a specific key is missing in the active language, vue-i18n displays the English equivalent instead of throwing an error or displaying raw keys.

### What is the recommended file structure for storing multi-language quiz data?

The `microsoft/AI-For-Beginners` repository organizes files under `src/assets/translations/` with subdirectories for each locale (e.g., `en/`, `es/`). Each subdirectory contains an [`index.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/index.js) exporting identically structured quiz objects, while the parent directory contains an [`index.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/index.js) that aggregates these exports into the `messages` object consumed by vue-i18n.

### Can users switch quiz languages without losing their progress or reloading the page?

Yes. Because the quiz data structure is identical across all locales, changing `this.$i18n.locale` triggers Vue's reactivity system to update all `$t()` bindings instantly. The application state (such as selected answers) remains intact because the component logic persists while only the displayed text changes.

### How are translation messages loaded into the vue-i18n instance?

The `messages` object exported from [`src/assets/translations/index.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/src/assets/translations/index.js) is imported into [`src/main.js`](https://github.com/microsoft/AI-For-Beginners/blob/main/src/main.js) and passed to the `VueI18n` constructor as configuration. This wires all language packs into the application at bootstrap time, making them immediately available via the `$t` helper throughout the component tree.