How the Vue.js Quiz App in Microsoft's AI-For-Beginners Handles Translations with vue-i18n

The quiz application uses vue-i18n to initialize a global i18n instance with locale fallback settings, loads language-specific JSON bundles through a centralized translations module, and lets components access the active locale via this.$root.$i18n.locale to render multilingual quiz content.

The Microsoft AI-For-Beginners repository includes a Vue.js-based quiz application that demonstrates practical internationalization patterns. This guide examines how the app leverages vue-i18n to support multiple languages through a clean, maintainable architecture.

vue-i18n Initialization in src/main.js

The translation system boots in src/main.js, where the plugin is registered and configured.

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

Vue.use(VueI18n);

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

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

The VueI18n instance is created with locale: 'en' and fallbackLocale: 'en' to ensure graceful degradation. Passing this instance to the root Vue constructor makes $i18n available throughout the component tree.

Translation Bundle Organization

Centralized Message Loading

All translations are aggregated in src/assets/translations/index.js. This file imports language-specific modules and exports a messages object mapping locale codes to their data.

// src/assets/translations/index.js – bundle aggregation
import englishQuizzes from './en';
import spanishQuizzes from './es';

export default {
  en: englishQuizzes,
  es: spanishQuizzes,
};

Per-Language Module Structure

Each locale folder contains an index.js that imports per-lesson JSON files. The English module at src/assets/translations/en/index.js demonstrates this pattern:

// Imports all lesson JSON files and builds a flat quiz object
import lesson1 from './lesson-1.json';
import lesson2 from './lesson-2.json';
// ... additional lesson imports

export default {
  quiz: {
    1: lesson1,
    2: lesson2,
    // ...
  }
};

The JSON files (lesson-1.json, lesson-2.json, etc.) store quiz titles, questions, and answer options. This structure separates content data from UI translations, a common pattern in educational applications.

Component-Level Locale Access in Quiz.vue

The Quiz.vue component consumes these bundles through computed properties tied to vue-i18n's reactive locale state.

// src/components/Quiz.vue – consuming translations
import messages from '@/assets/translations';

export default {
  computed: {
    // Expose the full message map to the template
    questions() {
      return messages;
    },
    // Read the active locale from the root i18n instance
    currLocale() {
      return this.$root.$i18n.locale;
    },
  },
  // Template accesses questions[currLocale] to retrieve correct language data
};

The component reads this.$root.$i18n.locale rather than this.$i18n.locale, ensuring it tracks the global locale state regardless of nested component depth.

Dynamic Locale Selection

The Quiz.vue component handles runtime language switching through the created() lifecycle hook:

// From src/components/Quiz.vue lines 81-86
created() {
  if (this.$route.query.loc) {
    this.locale = this.$route.query.loc;
  } else {
    this.locale = 'en';
  }
}

The loc query parameter (e.g., /quiz/1?loc=es) allows URL-driven language selection. While this.locale is assigned here, the reactive system ultimately responds to changes in this.$root.$i18n.locale, enabling external language switchers to update the UI.

Key Implementation Patterns

  • Global instance injection: vue-i18n is installed once and passed to the root Vue instance, avoiding prop drilling
  • Static bundle imports: Translations are bundled at build time rather than fetched dynamically, suitable for a fixed-content quiz app
  • Computed property reactivity: currLocale re-evaluates when $i18n.locale changes, triggering template updates
  • Query parameter initialization: Routes accept ?loc= to preselect language on direct navigation

Summary

  • vue-i18n initialization happens in src/main.js with default and fallback locales set to 'en'
  • Translation bundles are centralized in src/assets/translations/index.js, aggregating per-language modules
  • JSON content files for each lesson are imported and exposed through locale-specific index files
  • Quiz.vue accesses translations via computed properties tied to this.$root.$i18n.locale
  • URL parameters allow initial locale selection through the loc query string

Frequently Asked Questions

How does the quiz app switch languages without page reload?

The app relies on vue-i18n's reactive integration. When this.$root.$i18n.locale changes, computed properties like currLocale re-evaluate automatically. The template then indexes into questions[currLocale], causing Vue's reactivity system to update the rendered quiz content without navigation.

Why does Quiz.vue use this.$root.$i18n.locale instead of this.$i18n.locale?

This ensures the component reads the global locale state from the root instance. In nested component trees, $i18n might reference a localized scope; $root.$i18n guarantees access to the singleton instance created in src/main.js.

Can new languages be added without modifying component code?

Yes. Adding a new language requires: (1) creating a new folder under src/assets/translations/ with lesson JSON files and an index.js exporter, (2) importing it in src/assets/translations/index.js, and (3) ensuring the locale code matches what vue-i18n expects. No changes to Quiz.vue or other components are necessary.

Does the app support runtime translation loading?

No. The current implementation uses static ES6 imports, bundling all translations at build time. This keeps the application simple and offline-capable but increases initial bundle size. For larger applications, vue-i18n's lazy loading with dynamic imports would be recommended.

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 →