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

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, the code imports VueI18n, registers it with Vue.use(), and creates a new instance defining English as both the default and fallback locale.

// 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 (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. This file imports quiz data from each language folder and exports a single messages object that maps locale codes to their respective content.

// 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 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 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.

// 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.

<!-- 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.

// 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 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 demonstrates this pattern, separating navigation logic from translation concerns.

Summary

  • Initialize vue-i18n in 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 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, 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.

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 exporting identically structured quiz objects, while the parent directory contains an 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 is imported into 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →