阿里云主机折上折
  • 微信号
Current Site:Index > Internationalization (i18n) solution implementation translates this sentence into English.

Internationalization (i18n) solution implementation translates this sentence into English.

Author:Chuan Chen 阅读数:56874人阅读 分类: 构建工具

Internationalization (i18n) Implementation Solutions

Internationalization (i18n) is an essential feature in modern frontend application development. As a next-generation build tool, Vite.js offers multiple ways to implement internationalization. From simple JSON files to complex dynamic loading, developers can choose the most suitable solution based on project requirements.

Basic JSON File Solution

The simplest way to implement internationalization is by using JSON files to store translations for different languages. Create a locales folder in a Vite project to store translation files for various languages:

// locales/en.json
{
  "welcome": "Welcome",
  "about": "About Us",
  "contact": "Contact"
}

// locales/zh.json
{
  "welcome": "欢迎",
  "about": "关于我们",
  "contact": "联系我们"
}

Then import and use the JSON files in components:

import en from './locales/en.json'
import zh from './locales/zh.json'

const messages = {
  en,
  zh
}

const currentLocale = ref('en')

function t(key) {
  return messages[currentLocale.value][key]
}

Using the vue-i18n Plugin

For Vue projects, vue-i18n is the most popular internationalization solution. First, install the dependency:

npm install vue-i18n@9

Then configure it in the Vite project:

// src/i18n.js
import { createI18n } from 'vue-i18n'
import en from './locales/en.json'
import zh from './locales/zh.json'

const messages = {
  en,
  zh
}

export default createI18n({
  legacy: false,
  locale: 'en',
  fallbackLocale: 'en',
  messages
})

Import it in main.js:

import { createApp } from 'vue'
import App from './App.vue'
import i18n from './i18n'

const app = createApp(App)
app.use(i18n)
app.mount('#app')

Usage in components:

<template>
  <p>{{ $t('welcome') }}</p>
</template>

Dynamic Language Pack Loading

For large applications, language packs can be loaded on demand to reduce initial loading size:

// src/i18n.js
export async function loadLocaleMessages(i18n, locale) {
  const messages = await import(`./locales/${locale}.json`)
  i18n.global.setLocaleMessage(locale, messages.default)
  return nextTick()
}

Call when switching languages:

async function changeLocale(locale) {
  if (!i18n.global.availableLocales.includes(locale)) {
    await loadLocaleMessages(i18n, locale)
  }
  i18n.global.locale.value = locale
}

Handling Plural Forms and Interpolation

Internationalization involves more than simple text replacement; it also requires handling plural forms and variable interpolation:

// locales/en.json
{
  "cart": {
    "items": "{count} item | {count} items"
  }
}

Usage in components:

<template>
  <p>{{ $tc('cart.items', itemCount, { count: itemCount }) }}</p>
</template>

Date and Number Formatting

Internationalization also includes localized display of dates and numbers:

const i18n = createI18n({
  // ...other configurations
  datetimeFormats: {
    en: {
      short: {
        year: 'numeric',
        month: 'short',
        day: 'numeric'
      }
    },
    zh: {
      short: {
        year: 'numeric',
        month: 'short',
        day: 'numeric'
      }
    }
  },
  numberFormats: {
    en: {
      currency: {
        style: 'currency',
        currency: 'USD'
      }
    },
    zh: {
      currency: {
        style: 'currency',
        currency: 'CNY'
      }
    }
  }
})

Usage:

<template>
  <p>{{ $d(new Date(), 'short') }}</p>
  <p>{{ $n(1000, 'currency') }}</p>
</template>

Route Internationalization

For multilingual websites, routes also need internationalization:

// router.js
const routes = [
  {
    path: '/:locale',
    component: Layout,
    children: [
      {
        path: 'about',
        component: About,
        name: 'about'
      }
    ]
  },
  {
    path: '/',
    redirect: '/en'
  }
]

Handle language switching in navigation guards:

router.beforeEach((to) => {
  const locale = to.params.locale || 'en'
  if (!supportedLocales.includes(locale)) {
    return '/en' + to.fullPath
  }
  i18n.global.locale.value = locale
})

SEO Optimization

Multilingual websites require hreflang tags for SEO:

<template>
  <head>
    <link 
      v-for="locale in availableLocales"
      :key="locale"
      rel="alternate"
      :hreflang="locale"
      :href="`https://example.com/${locale}${$route.path}`"
    >
  </head>
</template>

Testing Internationalized Applications

When writing tests, consider multilingual scenarios:

import { mount } from '@vue/test-utils'
import Component from './Component.vue'
import { createI18n } from 'vue-i18n'

const i18n = createI18n({
  locale: 'en',
  messages: {
    en: {
      welcome: 'Welcome'
    }
  }
})

const wrapper = mount(Component, {
  global: {
    plugins: [i18n]
  }
})

expect(wrapper.text()).toContain('Welcome')

Performance Optimization Tips

  1. Load language packs on demand
  2. Use CDN to host language files
  3. Implement language caching
  4. Preload languages the user is likely to use
// Preload adjacent languages
function preloadAdjacentLocales(locale) {
  const localesToPreload = getAdjacentLocales(locale)
  localesToPreload.forEach(l => {
    import(`./locales/${l}.json`)
  })
}

Common Problem Solutions

Problem 1: Dynamic key translation

// Use computed properties
const translatedKey = computed(() => $t(`page.${currentPage}.title`))

Problem 2: Mixed content translation

// Use arrays and v-for
const mixedContent = computed(() => [
  { text: $t('part1'), isHtml: false },
  { html: '<strong>HTML content</strong>', isHtml: true }
])

Problem 3: Handling missing translations

// Custom missing handler
const i18n = createI18n({
  // ...other configurations
  missing: (locale, key) => {
    console.warn(`Missing translation for ${key} in ${locale}`)
    return key
  }
})

Advanced Custom Requirements

For projects requiring high customization, extend i18n functionality:

// Custom directive
app.directive('t', {
  mounted(el, binding) {
    el.textContent = i18n.global.t(binding.value)
  },
  updated(el, binding) {
    el.textContent = i18n.global.t(binding.value)
  }
})

// Usage
<p v-t="'welcome'"></p>

Integration with Other Tools

Integration with Pinia state management:

// stores/i18n.js
export const useI18nStore = defineStore('i18n', {
  state: () => ({
    locale: 'en'
  }),
  actions: {
    setLocale(locale) {
      this.locale = locale
      i18n.global.locale.value = locale
    }
  }
})

Integration with TailwindCSS for RTL support:

// Switch HTML direction based on language
watch(() => i18n.global.locale.value, (locale) => {
  document.documentElement.dir = locale === 'ar' ? 'rtl' : 'ltr'
})

Build Optimization

Optimize internationalization resources in Vite configuration:

// vite.config.js
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('locales')) {
            return 'locales'
          }
        }
      }
    }
  }
})

Practical Application Scenarios

Multilingual product display for e-commerce websites:

<template>
  <div v-for="product in products" :key="product.id">
    <h3>{{ $t(`products.${product.id}.name`) }}</h3>
    <p>{{ $t(`products.${product.id}.description`) }}</p>
    <p>{{ $n(product.price, 'currency') }}</p>
  </div>
</template>

Multilingual form validation:

// Validation rules
const rules = {
  required: value => !!value || i18n.global.t('validation.required'),
  email: value => /.+@.+\..+/.test(value) || i18n.global.t('validation.email')
}

Continuous Maintenance Strategy

  1. Establish translation key naming conventions
  2. Automate extraction of untranslated text
  3. Integrate translation management systems
  4. Regularly review translation quality
# Example script to extract untranslated text
grep -r "\$t(" src/ | awk -F"\$t\\('" '{print $2}' | awk -F"'" '{print $1}' | sort | uniq > keys.txt

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.