How to Add and Configure Internationalization (i18n) with vue-i18n in Celeris Web

Celeris Web provides a modular i18n system built on vue-i18n that uses LocalesEngine and LocalesConfiguration to load JSON translation files from apps/admin/locales, persist the selected locale in local storage, and expose translation helpers via useI18n() in components.

Celeris Web implements a thin, modular wrapper around vue-i18n that simplifies adding multilingual support to your Vue applications. The system lives in the @celeris/locale package under packages/web/locale and provides a persistent store, asynchronous message loading, and a clean API for runtime locale switching.

Core Architecture and File Structure

The internationalization layer is organized into distinct modules that separate storage, configuration, and Vue plugin initialization:

File Responsibility
packages/web/locale/src/store.ts Persists the selected locale in localStorage using LOCALES_STORE_KEY. Exports setLocale and getLocale.
packages/web/locale/src/config.ts Defines LocalesConfiguration for mutable settings and LocalesEngine as the static API façade.
packages/web/locale/src/index.ts Creates the vue-i18n instance via createI18n and registers it on the Vue app through setupI18n.
apps/admin/src/AppConfiguration.ts Loads JSON files from apps/admin/locales/*.json using Vite’s import.meta.glob and feeds them to LocalesEngine.
apps/admin/src/main.ts Bootstraps the application and invokes setupI18n(app) after configuration initialization.
Component files (e.g., Menu.vue) Consume translations using useI18n() from vue-i18n.

Configuration Flow and Initialization

The system initializes in five distinct phases to ensure translations are available before components render:

  1. Locale Persistence — store.ts creates a reactive getLocale computed property and a setLocale helper that writes to localStorage at packages/web/locale/src/store.ts.

  2. Configuration State — LocalesConfiguration holds the current locale, fallback language, message handler function, and additional vue-i18n options at packages/web/locale/src/config.ts.

  3. Static API — LocalesEngine exposes static methods like initLocales and setLocale that delegate to the configuration object at packages/web/locale/src/config.ts.

  4. Instance Creation — setupI18n(app) in packages/web/locale/src/index.ts calls createI18nOptions(), which merges defaults (legacy: false, locale from configuration) with user options, creates the i18n instance, and installs it on the Vue app.

  5. Application Bootstrap — initializeI18n() in apps/admin/src/AppConfiguration.ts pre-loads all translation files, then main.ts awaits this initialization before mounting the app at apps/admin/src/main.ts.

Practical Implementation Examples

Loading Translation Messages

In your application configuration file, load JSON files from the locales directory and initialize the engine:

// apps/admin/src/AppConfiguration.ts
import { LocalesEngine } from "@celeris/locale";

function initializeI18n() {
  const { getLocale } = useAppSetting();

  // Load all JSON files from apps/admin/locales/*.json
  const messages = Object.fromEntries(
    Object.entries(
      import.meta.glob<{ default: any }>("./locales/*.json", { eager: true })
    ).map(([key, value]) => [key.slice(10, -5), value.default])
  );

  // Feed the data to the engine
  LocalesEngine.initLocales(() => ({
    locale: getLocale.value,
    fallbackLocale: "en",
    messagesHandler: () => messages,
    otherOptions: {
      sync: true,
      availableLocales: Object.keys(messages),
      silentTranslationWarn: true,
      missingWarn: false,
      silentFallbackWarn: true,
    },
  }));
}

Initializing the i18n Instance

The setupI18n function creates the vue-i18n instance with merged options:

// packages/web/locale/src/index.ts
import { createI18n } from "vue-i18n";
import { deepMerge } from "@celeris/utils";
import { LocalesConfiguration } from "./config";

export let i18n: ReturnType<typeof createI18n>;

async function createI18nOptions() {
  return deepMerge(
    {
      legacy: false,
      locale: LocalesConfiguration.locale,
      fallbackLocale: LocalesConfiguration.fallbackLocale,
      messages: await LocalesConfiguration.messagesHandler(),
    },
    LocalesConfiguration.otherOptions
  );
}

export async function setupI18n(app) {
  const options = await createI18nOptions();
  i18n = createI18n(options);
  app.use(i18n);
}

Consuming Translations in Components

Any Vue component can access translations using the useI18n composable:

<script setup lang="ts">
import { useI18n } from "vue-i18n";

const { te, t } = useI18n();

function i18nRender(key: string) {
  // Return the translated string if it exists, otherwise the key itself
  return te(key) ? t(key) : key;
}
</script>

<template>
  <span>{{ i18nRender('menu.dashboard') }}</span>
</template>

Runtime Locale Switching

Change the active language and persist the selection using the engine API:

import { LocalesEngine } from "@celeris/locale";

// Switch to Chinese
LocalesEngine.setLocale("zh-CN");

// Updates localStorage and reconfigures the i18n instance automatically

Summary

  • Persistence: The locale store in store.ts maintains the user's language preference in localStorage using LOCALES_STORE_KEY.
  • Configuration: LocalesConfiguration and LocalesEngine provide a type-safe, centralized API for managing i18n settings and switching languages at runtime.
  • Loading: Translation files are loaded via import.meta.glob in AppConfiguration.ts, making them available synchronously during app bootstrap.
  • Integration: The setupI18n function registers the vue-i18n instance on the Vue app only after messages are fully loaded, preventing translation flashes.
  • Usage: Components consume translations through standard useI18n() from vue-i18n, with helper patterns like i18nRender for fallback handling.

Frequently Asked Questions

How do I add a new language to a Celeris Web application?

Create a new JSON file in apps/admin/locales (e.g., fr.json for French), add your translation key-value pairs, and restart the development server. The import.meta.glob pattern in AppConfiguration.ts automatically picks up new files and adds them to availableLocales.

Where does Celeris Web store the user's selected language?

The selected locale is persisted in the browser's localStorage under the key defined by LOCALES_STORE_KEY in packages/web/locale/src/store.ts. The setLocale function updates this value and the reactive getLocale computed property.

How can I change the fallback locale from English to another language?

Modify the fallbackLocale property passed to LocalesEngine.initLocales in apps/admin/src/AppConfiguration.ts. Change the string "en" to your preferred fallback language code (e.g., "zh-CN").

What is the purpose of the LocalesEngine class?

LocalesEngine acts as a static façade that exposes high-level methods like initLocales and setLocale. It delegates to the mutable LocalesConfiguration object, allowing the application to configure and control the i18n system without directly manipulating vue-i18n internals.

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 →