前端开发攻略---在 Vue 3 项目中使用 vue-i18n 实现国际化多语言

实现思路

1. 项目初始化与依赖安装

javascript 复制代码
npm install vue-i18n@9
# 如果使用 axios
npm install axios

2. 创建 i18n 实例并配置基础结构

在项目中创建一个 i18n.js(或 i18n.ts)文件,初始化 i18n 实例。通常我们会:

  • 设置默认语言(如 zh-CN

  • 设置后备语言(fallback locale)

  • 可以预先加载默认语言包(也可以全部动态加载)

javascript 复制代码
// i18n.js
import { createI18n } from 'vue-i18n'

// 默认语言
const defaultLocale = 'zh-CN'

// 可以预先导入本地默认语言包(可选)
import zhCN from './locales/zh-CN.json'

const i18n = createI18n({
  legacy: false, // 使用 Composition API 模式
  locale: defaultLocale,
  fallbackLocale: 'en-US', // 后备语言
  messages: {
    'zh-CN': zhCN
  }
})

export default i18n

然后在 main.js 中挂载:

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import i18n from './i18n'

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

3. 定义语言包结构

语言包为标准的 JSON 格式,例如:

javascript 复制代码
// zh-CN.json
{
  "home": {
    "title": "首页",
    "welcome": "欢迎使用"
  },
  "common": {
    "save": "保存",
    "cancel": "取消"
  }
}
javascript 复制代码
// en-US.json
{
  "home": {
    "title": "Home",
    "welcome": "Welcome"
  },
  "common": {
    "save": "Save",
    "cancel": "Cancel"
  }
}

4. 从后端 API 动态加载语言包

我们需要一个函数,根据语言代码从后端获取对应的 JSON 文件,然后通过 i18n.global.setLocaleMessage() 将语言包添加到 i18n 实例中,最后切换 locale

同时,为了避免重复请求,可以缓存已加载的语言包(i18n 内部本身会存储,但我们可以额外用一个变量记录已加载状态)。

javascript 复制代码
// utils/localeLoader.js
import i18n from '@/i18n'
import axios from 'axios'

// 记录正在加载中的语言,防止并发重复请求
const loadingLocales = new Set()

/**
 * 加载指定语言包
 * @param {string} locale - 语言代码,如 'en-US'
 * @returns {Promise}
 */
export async function loadLocaleMessages(locale) {
  // 如果已经加载过,直接返回(i18n.global.getLocaleMessage(locale) 可检查是否存在)
  if (i18n.global.availableLocales.includes(locale)) {
    return Promise.resolve()
  }

  // 避免重复请求同一个语言包
  if (loadingLocales.has(locale)) {
    // 可以返回一个 pending 的 promise,或者简单等待
    return new Promise((resolve) => {
      const check = setInterval(() => {
        if (i18n.global.availableLocales.includes(locale)) {
          clearInterval(check)
          resolve()
        }
      }, 50)
    })
  }

  loadingLocales.add(locale)

  try {
    // 假设后端 API 路由为 /api/locales/{locale}.json
    const response = await axios.get(`/api/locales/${locale}.json`)
    const messages = response.data

    // 将语言包设置到 i18n 实例中
    i18n.global.setLocaleMessage(locale, messages)
    
    // 可选:同时将语言包存入 localStorage 或 IndexedDB 做离线缓存
    // localStorage.setItem(`locale_${locale}`, JSON.stringify(messages))
  } catch (error) {
    console.error(`Failed to load locale messages for ${locale}:`, error)
    throw error
  } finally {
    loadingLocales.delete(locale)
  }
}

5. 切换语言功能

切换语言时,先调用 loadLocaleMessages 确保语言包已加载,然后修改 i18n 的 locale 值。由于 locale 是响应式 ref,所有使用了 $tt 函数的地方会自动更新。

为了持久化用户偏好,可以将当前语言保存到 localStorage

在组件中实现语言切换器:

javascript 复制代码
<!-- components/LanguageSwitcher.vue -->
<template>
  <select v-model="currentLocale" @change="changeLanguage">
    <option value="zh-CN">中文</option>
    <option value="en-US">English</option>
    <option value="ja-JP">日本語</option>
    <!-- 动态语言选项可以从后端获取支持的语言列表 -->
  </select>
</template>

<script setup>
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { loadLocaleMessages } from '@/utils/localeLoader'

const { locale } = useI18n()
const currentLocale = ref(locale.value)

// 切换语言
const changeLanguage = async () => {
  const newLocale = currentLocale.value
  // 加载语言包
  await loadLocaleMessages(newLocale)
  // 更新 locale
  locale.value = newLocale
  // 保存到 localStorage
  localStorage.setItem('user-locale', newLocale)
}

// 初始化时从 localStorage 读取上次语言并加载
const initLocale = async () => {
  const savedLocale = localStorage.getItem('user-locale')
  if (savedLocale && savedLocale !== locale.value) {
    currentLocale.value = savedLocale
    await loadLocaleMessages(savedLocale)
    locale.value = savedLocale
  }
}
initLocale()
</script>

6. 页面实时响应

vue-i18nlocale 是一个 ref,当它的值改变时,所有依赖它的 t 函数或组件内的翻译都会自动重新计算。只要切换语言后执行了 locale.value = newLocale,页面所有文本会立即更新,无需额外操作。

7. 动态新增自定义语言

支持动态新增语言意味着我们可以通过管理界面让用户定义新语言(例如添加一个语言代码和上传对应的 JSON 文件),然后将其保存到后端,前端再获取并应用。

步骤

  1. 提供一个管理界面,允许用户输入语言代码(如 fr-FR)和上传 JSON 文件或在线编辑键值对。

  2. 将新的语言包发送到后端 API 进行保存(例如存到数据库或文件系统)。

  3. 后端提供一个接口返回所有支持的语言列表(如 GET /api/locales),前端在初始化时可以请求该列表,用于构建语言切换器的选项。

  4. 当用户选择新语言时,通过上述 loadLocaleMessages 从后端获取并加载。

动态语言列表示例

javascript 复制代码
// 在 LanguageSwitcher 中增加动态选项
import { ref, onMounted } from 'vue'
import axios from 'axios'

const supportedLocales = ref([])

onMounted(async () => {
  const res = await axios.get('/api/locales')
  supportedLocales.value = res.data // 例如 [{ code: 'fr-FR', name: 'Français' }]
})

模板中:

html 复制代码
<select v-model="currentLocale" @change="changeLanguage">
  <option v-for="loc in supportedLocales" :key="loc.code" :value="loc.code">
    {{ loc.name }}
  </option>
</select>

8. 进阶优化

  • 预加载常用语言:在应用初始化时,可以预先加载几种常用语言(如当前语言和后备语言),减少切换时的等待。

  • 加载状态处理:切换语言时如果网络慢,可以显示 loading 状态,避免界面卡顿。

  • 错误处理:加载语言包失败时,可降级使用后备语言或显示错误提示。

  • 离线缓存:将已加载的语言包存入 localStorage 或 IndexedDB,下次打开应用时可直接使用,减少请求。

9. 完整的 i18n 配置文件示例

javascript 复制代码
// i18n.js
import { createI18n } from 'vue-i18n'

const defaultLocale = localStorage.getItem('user-locale') || 'zh-CN'

const i18n = createI18n({
  legacy: false,
  locale: defaultLocale,
  fallbackLocale: 'en-US',
  messages: {
    // 可以只放一个空对象,完全动态加载
    'zh-CN': {}, // 启动后立刻加载
    'en-US': {}
  }
})

export default i18n

然后在 App.vue 或根组件中,异步加载默认语言包:

javascript 复制代码
import { onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { loadLocaleMessages } from '@/utils/localeLoader'

export default {
  setup() {
    const { locale } = useI18n()
    onMounted(async () => {
      await loadLocaleMessages(locale.value)
    })
  }
}
相关推荐
qq_437100661 小时前
ElasticSearch相关记录
大数据·前端·javascript·elasticsearch·全文检索
CHU7290351 小时前
剧本杀组车约玩小程序前端功能版块设计及玩法介绍
前端·小程序
清空mega2 小时前
《Vue3 模板进阶:class/style 绑定、事件对象、修饰符、表单处理与高频易错点》
前端·javascript·vue.js
还是大剑师兰特2 小时前
Vue3 插槽完整实战(具名插槽 + 动态插槽)
前端·javascript·vue.js
fei_sun2 小时前
Vue+SpingBoot+MyBaits框架
前端·javascript·vue.js
爱吃鱼的锅包肉2 小时前
利用css+js实现一个图片随鼠标滑动裁剪的功能
前端·javascript·css·计算机外设
儒雅的烤地瓜2 小时前
小程序 | Vue小程序开发框架:MPvue与UniApp深度解析
前端·vue.js·uni-app·nodejs·cli·mpvue
小鸡脚来咯2 小时前
正则表达式考点
java·开发语言·前端
ujainu2 小时前
Electron 主进程与渲染进程通信详解:HarmonyOS PC基于 `ipcRenderer.send` 与 `ipcMain.on` 的双向数据传输
javascript·electron·harmonyos