Internationalization (i18n) Implementation

TsFile Viewer supports multiple languages with Vue I18n.

Supported Languages

  • Chinese (zh-CN) - Default language
  • English (en-US)

Features

  • Automatic language detection from browser settings
  • Language preference saved in localStorage
  • Language switcher in the top-right corner
  • All UI text translated
  • Documentation available in both languages

File Structure

frontend/src/i18n/
├── index.ts              # i18n configuration
└── locales/
    ├── zh-CN.json        # Chinese translations
    └── en-US.json        # English translations

Usage in Components

Composition API

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

const { t, locale } = useI18n();

// Use translation
const title = t("app.title");

// Switch language
locale.value = "en-US";
</script>

<template>
  <h1>{{ $t("app.title") }}</h1>
  <p>{{ $t("app.description") }}</p>
</template>

Options API

<script>
export default {
  computed: {
    title() {
      return this.$t("app.title");
    },
  },
  methods: {
    switchLanguage(lang) {
      this.$i18n.locale = lang;
    },
  },
};
</script>

<template>
  <h1>{{ $t("app.title") }}</h1>
</template>

Translation Keys

Common Keys

{
  "common": {
    "loading": "Loading...",
    "error": "Error",
    "success": "Success",
    "cancel": "Cancel",
    "confirm": "Confirm"
  }
}

Feature-specific Keys

{
  "file": {
    "title": "File Management",
    "uploadFile": "Upload File",
    "selectFile": "Select File"
  },
  "metadata": {
    "title": "Metadata",
    "version": "Version",
    "timeRange": "Time Range"
  },
  "data": {
    "title": "Data Preview",
    "filters": "Filters",
    "exportCsv": "Export CSV"
  },
  "chart": {
    "title": "Chart Visualization",
    "exportPng": "Export PNG"
  }
}

Adding a New Language

  1. Create a new locale file:

    touch frontend/src/i18n/locales/ja-JP.json
    
  2. Add translations:

    {
      "app": {
        "title": "TsFileビューア",
        "description": "Apache TsFile形式データの表示と分析ツール"
      }
    }
    
  3. Import in i18n/index.ts:

    import jaJP from "./locales/ja-JP.json";
    
    const i18n = createI18n({
      messages: {
        "zh-CN": zhCN,
        "en-US": enUS,
        "ja-JP": jaJP, // Add new language
      },
    });
    
  4. Update LanguageSwitcher component:

    const languageItems = computed(() => [ [ { label: '中文', click: () =>
    switchLanguage('zh-CN') }, { label: 'English', click: () =>
    switchLanguage('en-US') }, { label: '日本語', click: () =>
    switchLanguage('ja-JP') }, ], ])
    

Documentation

Available Documentation

Adding Documentation in a New Language

  1. Copy existing documentation:

    cp README.md README.ja-JP.md
    cp USER_GUIDE.md USER_GUIDE.ja-JP.md
    cp DEPLOYMENT.md DEPLOYMENT.ja-JP.md
    
  2. Translate the content

  3. Add links in main README:

    [中文文档](../README.zh-CN.md) | [English](../README.md) | [日本語](README.ja-JP.md)
    

Best Practices

  1. Use Namespaces: Organize translations by feature

    {
      "file": { ... },
      "metadata": { ... },
      "data": { ... }
    }
    
  2. Consistent Keys: Use the same key structure across languages

    // zh-CN.json
    { "common": { "save": "保存" } }
    
    // en-US.json
    { "common": { "save": "Save" } }
    
  3. Pluralization: Use Vue I18n pluralization

    {
      "items": "no items | one item | {count} items"
    }
    
    {{ $t("items", 0) }} // "no items" {{ $t("items", 1) }} // "one item"
    {{ $t("items", 5) }} // "5 items"
    
  4. Interpolation: Use variables in translations

    {
      "welcome": "Welcome, {name}!"
    }
    
    {{ $t("welcome", { name: "John" }) }} // "Welcome, John!"
    
  5. Date/Time Formatting: Use locale-aware formatting

    const date = new Date();
    const formatted = date.toLocaleString(locale.value);
    

Testing

Test translations in different languages:

import { createI18n } from "vue-i18n";
import zhCN from "@/i18n/locales/zh-CN.json";
import enUS from "@/i18n/locales/en-US.json";

describe("i18n", () => {
  it("should have all keys in both languages", () => {
    const zhKeys = Object.keys(zhCN);
    const enKeys = Object.keys(enUS);
    expect(zhKeys).toEqual(enKeys);
  });
});

Configuration

Vite Configuration

import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";

export default defineConfig({
  plugins: [
    VueI18nPlugin({
      include: resolve(__dirname, "./src/i18n/locales/**"),
    }),
  ],
});

TypeScript Support

import type { MessageSchema } from '@/i18n'

// Type-safe translations
const i18n = createI18n<[MessageSchema], 'zh-CN' | 'en-US'>({
  legacy: false,
  locale: 'zh-CN',
  messages: { ... },
})

Browser Support

  • Modern browsers with ES6+ support
  • localStorage for language preference
  • Automatic fallback to English if translation missing

Performance

  • Translations are pre-compiled at build time
  • Lazy loading for large translation files (if needed)
  • Minimal runtime overhead

Troubleshooting

Missing Translations

If a translation key is missing:

  1. Check the console for warnings
  2. Verify the key exists in both language files
  3. Ensure the key path is correct

Language Not Switching

  1. Check localStorage for saved preference
  2. Verify locale value is being set correctly
  3. Clear browser cache and reload

Build Errors

If you encounter build errors:

  1. Ensure all JSON files are valid
  2. Check that all imports are correct
  3. Verify VueI18nPlugin configuration

Resources