当前位置: 首页 > news >正文

前端Vue3国际化开发 :使用vue-i18n库和Element Plus 组件实现

前端Vue3国际化开发 :使用vue-i18n库和Element Plus 组件实现

剖析 Vue3 + Element Plus 国际化(i18n)实现原理

本文将解析基于 Vue3Element Plus 的国际化架构实现,从核心概念到实际应用,带您全面了解多语言支持在现代化前端应用中的实现方式。

国际化(i18n)核心概念

国际化(Internationalization,简称 i18n)是指设计软件应用时,使其能适应多种语言和地区需求的过程。在 Vue 生态中,主要通过 vue-i18n 库实现(Vue I18n 是 Vue.js 的国际化插件),配合 Element Plus 的国际化支持,可构建完整的国际化应用。

国际化实现架构图

在这里插入图片描述

实现效果

效果一:Element Plus组件的国际化、使用vue-i8n插件实现页面的国际化

前端国际化开发效果

效果二:国际化语言本地持久化存储

语言本地持久化存储

具体步骤(Vue3 + Element Plus + i18n)

第一步:安装i8n

Vue I18n

Vue i18n插件在Vue3中需要使用v9版本,这一点需要注意!!
(我当时写项目的时候没有注意到这个一点,直接安装的最新版,目前为止还没发现什么问题,大家自己选择)

npm install vue-i18n@9   # Vue3 专用版本
或者
yarn add vue-i18n@9
或者
pnpm add vue-i18n@9

在这里插入图片描述
第二步:创建自定义语言资源文件
1、创建src/locales/en.js

export const language = {en: {// 部门sys_dept_list00001: 'Department Name',sys_dept_list00002: 'Person in Charge Name',sys_dept_list00003: 'Department Head',// 实验室管理: 'Manage',人员信息: 'Personnel Information',序号: 'NO.',姓名: 'Name',学工号: 'Student ID',账号: 'Account',操作: 'Action',编辑: 'Edit',}}

2、创建src/locales/zh-cn.js

	'zh-cn': {// 部门sys_dept_list00001: '部门名称',sys_dept_list00002: '负责人名称',sys_dept_list00003: '部门负责人',// 实验室管理管理: '管理',人员信息: '人员信息',序号: '序号',姓名: '姓名',学工号: '学工号',操作: '操作',编辑: '编辑',`在这里插入代码片`}

(我一开始用的编号,后来发现代码可读性有点差,不利于后期维护,索性全用中文了!)
在这里插入图片描述
(可以分两个对照文档,一份中文,一份英文,我是直接放一起了,大家自行选择!)
第三步:合并 Element Plus 语言包和自定义语言包并在main.ts挂载

import { icons as epIcons } from '@iconify-json/ep'
import { icons as nfIcons } from '@iconify-json/nf'
import { addCollection } from '@iconify/vue'
import { createApp } from 'vue'import '!/public/style/index.css'
import '@unocss/reset/tailwind-compat.css'
import 'virtual:uno.css'
import '@nofar-core/shared/integrations/element'
import 'animate.css'import { setupDirectives } from '@nofar-core/directives'
import { setupModules } from '@nofar-core/shared/plugins'
import App from '@nofar-core/shared/views/App.vue'import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css'import ElementPlus, { ElConfigProvider, useLocale } from 'element-plus'
import en from 'element-plus/es/locale/lang/en' // 英文语言包
import zhCn from 'element-plus/es/locale/lang/zh-cn' // 中文语言包import { createPinia } from 'pinia'
import { createI18n } from 'vue-i18n'
import Vue3DraggableResizable from 'vue3-draggable-resizable'import { language } from '@nofar-core/shared/locales' // 引入语言包const pinia = createPinia()const app = createApp(App)
app.use(pinia)
const appLangStr = sessionStorage.getItem('app-lang')
const appLang = appLangStr ? JSON.parse(appLangStr) : null
const savedLocale = appLang?.currentLang || 'zh-cn'  // 默认值const initialLocale = ref(savedLocale)
// 创建 i18n 实例
const i18n = createI18n({legacy: false,// locale: 'en', // 默认语言locale: initialLocale.value || 'zh-cn', // 初始语言messages: {en: {// welcome: 'Welcome',...language.en, // 英文语言包...en // Element Plus 的英文语言包},'zh-cn': {// welcome: '欢迎',...language['zh-cn'], // 中文语言包...zhCn // Element Plus 的中文语言包}}
})
// 添加语言切换方法
const changeLocale = (locale: 'zh-cn' | 'en') => {// i18n.global.locale = locale// // ElConfigProvider.config({// // 	locale: locale === 'zh-cn' ? zhCn : en// // })// useLocale(ref(locale === 'zh-cn' ? zhCn : en))i18n.global.locale.value = locale // 操作ref的value属性useLocale(computed(() => (locale === 'zh-cn' ? zhCn : en)))
}// 使用 Element Plus 和 i18n
app.use(ElementPlus, {// locale: i18n.global.locale === 'zh-cn' ? zhCn : enlocale: computed(() => (i18n.global.locale.value === 'zh-cn' ? zhCn : en))// locale: en
})
app.use(i18n)// 挂载语言切换方法
app.config.globalProperties.$changeLocale = changeLocale
app.use(Vue3DraggableResizable)
setupModules(app)
setupDirectives(app)addCollection(epIcons)
addCollection(nfIcons)app.config.errorHandler = (err) => {console.error(err)
}app.mount('#app')

上述代码实现详解
1、语言包导入与管理

// 引入 Element Plus 语言包
import en from 'element-plus/es/locale/lang/en' // 英文语言包
import zhCn from 'element-plus/es/locale/lang/zh-cn' // 中文语言包//从 vue-i18n中导入用于创建 i18n 实例的方法
import { createI18n } from 'vue-i18n'// 引入自定义语言包
import { language } from '@nofar-core/shared/locales'// 创建 i18n 实例
const i18n = createI18n({legacy: false, // 使用 Vue3 的 Composition API 风格locale: initialLocale.value || 'zh-cn', // 初始语言messages: {en: {...language.en, // 自定义英文语言包...en // Element Plus 的英文语言包},'zh-cn': {...language['zh-cn'], // 自定义中文语言包...zhCn // Element Plus 的中文语言包}}
})

关键点解析:

  • legacy: false 表示使用 Vue3 的 Composition API 风格
  • 通过对象展开符 合并自定义语言包和 Element Plus 语言包
  • 语言包结构为键值对形式,例如:{ welcome: '欢迎', login: '登录' }

2、 语言状态初始化

// 从 sessionStorage 获取保存的语言设置
const appLangStr = sessionStorage.getItem('app-lang')
const appLang = appLangStr ? JSON.parse(appLangStr) : null// 设置初始语言,默认为中文
const savedLocale = appLang?.currentLang || 'zh-cn'  
const initialLocale = ref(savedLocale)

关键点解析:

  • 使用 sessionStorage 持久化用户的语言选择
  • 初始语言默认为中文(‘zh-cn’)
  • 使用 Vue 的 ref 创建响应式语言状态

3、Element Plus 国际化集成

// 使用 Element Plus 并配置国际化
app.use(ElementPlus, {locale: computed(() => i18n.global.locale.value === 'zh-cn' ? zhCn : en)
})

关键点解析:

  • 使用 computed 创建响应式语言配置
  • 根据当前选择的语言动态返回对应的 Element Plus 语言包
  • 确保 Element Plus 组件(如日期选择器、表单等)显示正确的语言

4、语言切换功能实现

// 添加语言切换方法
const changeLocale = (locale: 'zh-cn' | 'en') => {// 更新 vue-i18n 的语言设置i18n.global.locale.value = locale// 更新 Element Plus 的语言设置useLocale(computed(() => (locale === 'zh-cn' ? zhCn : en)))
}// 挂载语言切换方法到全局app.config.globalProperties.$changeLocale = changeLocale

关键点解析:

  • i18n.global.locale.value 是响应式属性,更新后会触发界面重新渲染
  • useLocale 是 Element Plus 提供的用于更新组件语言的函数
  • changeLocale 方法挂载到全局,方便在任何组件中调用

第四步:语言持久化存储

// 在组件中使用语言状态管理
<script setup lang="ts">
import { ElDropdown, ElDropdownItem, ElDropdownMenu, ElMessage } from 'element-plus'
import { getCurrentInstance } from 'vue'
import { useLanguageStore } from '@nofar-core/shared/stores/language'const {locale } = useI18n()
// 获取Pinia语言状态存储库
const languageStore = useLanguageStore()// 获取当前Vue实例的代理对象
const { proxy } = getCurrentInstance() as any// 处理语言切换
const handleCommand = async (command: string) => {locale.value = command // 更新本地响应式变量languageStore.setLanguage(command) // 保存到Pinia状态管理if (command === 'zh-cn') {proxy.$changeLocale('zh-cn') // 调用全局方法切换中文ElMessage.success('已切换为中文')} else if (command === 'en') {proxy.$changeLocale('en') // 调用全局方法切换英文ElMessage.success('Switched to English')}
}
</script>

注意:代码中使用了proxy.$changeLocale,这是在之前代码中挂载到app.config.globalProperties上的全局方法。

关键点解析:

  • 通过调用了proxy.$changeLocale,更新i18n的locale(这样使用i18n的地方会重新渲染),更新Element Plus的locale(这样Element Plus组件会显示对应语言)
  • 将当前语言保存到sessionStorage(键为’app-lang’),实现持久化。
  • 当应用重新加载(刷新或重新进入)时,main.ts会从sessionStorage中读取'app-lang'的值,并作为初始语言设置i18nElement Plus

Pinia状态管理(语言状态存储库定义 (stores/language.ts))

import { defineStore } from 'pinia';
export const useLanguageStore = defineStore('language', {persist: {key: 'app-lang',storage: sessionStorage,pick: ['currentLang']},state: () => ({currentLang: 'zh-cn' // 默认中文}),actions: {setLanguage(lang: string) {this.currentLang = lang},getApiLangParam() {return this.currentLang === 'zh-cn' ? 'Ch' : 'En'}}
})

第五步:vue页面中使用useI18n中的 $t函数式组件传递值
代码:

<script setup lang="ts">import { useI18n } from 'vue-i18n' // 引入 useI18nconst { t } = useI18n()const querys = reactive([{prop: 'personName',labelKey: '人员名称',label: ''},{prop: ['startTime', 'endTime'],labelKey: '出入时间',label: '',type: 'date' as const,datePicker: {type: 'datetimerange' as const,valueFormat: 'YYYY-MM-DD HH:mm:ss',rangeSeparator: '-',startPlaceholder: t('开始日期'),endPlaceholder: t('结束日期')}},])const queryParams = reactive({userName: undefined,regionId: undefined,startTime: undefined,endTime: undefined})const pageParams = reactive({pageIndex: 1,pageSize: 10})const columns = computed(() => [{type: 'selection'},{prop: 'personName',label: t('人员名称')},{prop: 'cardNo',label: t('卡号')},])
</script>
<template><div class="h-full flex flex-col gap-pageGap"><NfPageHeader v-model="queryParams" :querys @query="resetAndQuery()" @reset="resetAndQuery()" /><div class="flex flex-1 flex-col gap-pageGap rounded-module bg-white p-4"><NfTable class="flex-1" height="auto" :columns :data row-key="id"><template #action="{ row }"><el-button type="primary" link @click="handleEdit(row)">{{t('查看详情')}}</el-button></template></NfTable><NfPagination v-model="pageParams" :total="total" @change="getList()" /></div></div><EditDialog v-model="open" :form :region-list @submit="getList()" />
</template>

我这边用的是封装的组件,正常用form表单可以参考下面的:

<template><div class="app-container h-full w-full flex flex-col"><el-form ref="queryRef" :model="queryParams" :inline="true" class="bg-#fff px-4 pt-6 rounded-lg mb-4"><el-form-item :label="t('设施名称')" prop="deviceName" label-width="auto"><el-input v-model="queryParams.deviceName" :placeholder="t('请输入设施名称')" clearable maxlength="30" @keyup.enter="handleQuery" /></el-form-item><el-form-item :label="t('负责人')" prop="userName" label-width="auto"><el-input v-model="queryParams.userName" :placeholder="t('请输入负责人名称')" clearable maxlength="30" @keyup.enter="handleQuery" /></el-form-item></div>
</template>
<script setup lang="ts">import { useI18n } from 'vue-i18n' // 引入 useI18nconst { t } = useI18n()const rules = computed(() => {return {deviceName: [{ required: true, trigger: 'blur', message: t('设施名称不能为空') }],userName: [{ required: true, trigger: 'blur', message: t('负责人不能为空') }]}})</script>

效果展示:

第六步:Element Plus的国际化操作
Element Plus 提供了一个 Vue 组件 ConfigProvider 用于全局配置国际化的设置。官方地址https://element-plus.org/zh-CN/guide/i18n.html
只需要在 App.vue 中包一层配置组件即可!
代码:

App.vue
<script setup lang="ts">import { ElConfigProvider } from 'element-plus'import en from 'element-plus/es/locale/lang/en' // 英文语言包import zhCn from 'element-plus/es/locale/lang/zh-cn'import { useI18n } from 'vue-i18n' // 引入 useI18nimport { RouterView } from 'vue-router'const { locale } = useI18n() // 获取当前语言
</script><template><n-config-provider :theme-overrides="themeOverrides" class="h-full"><el-config-provider  :locale="locale === 'zh-cn' ? zhCn : en"><router-view></router-view></el-config-provider></n-config-provider>
</template>

效果展示:

第七步:热更新问题
比如:表单验证规则
如果按照reactive正常写代码,在进行语言切换时会发现表单的验证规则更新不及时!
如下:

	const rules = reactive({name: [{ required: true, message: t('请输入门禁名称'), trigger: 'blur' }],regionId: [{ required: true, message: t('请选择区域'), trigger: 'change' }],})

效果:
在这里插入图片描述

解决方案:使用computed

	const rules = computed(() => {return {name: [{ required: true, message: t('请输入门禁名称'), trigger: 'blur' }],regionId: [{ required: true, message: t('请选择区域'), trigger: 'change' }],}})

效果:
在这里插入图片描述

完整工作流程解析如下:

在这里插入图片描述

注意事项

http://www.xdnf.cn/news/1004941.html

相关文章:

  • Tensorflow 基础知识:变量、常量、占位符、Session 详解
  • strncpy_s与_TRUNCATE
  • 汉化langfuse踩坑记录--docker卷挂载未生效问题修复及langfuse启动
  • 基于 SpringBoot + Vue 在线点餐系统(前后端分离)
  • javascript入门
  • LangGraph--搭建官方机器人聊天(带工具的)教程
  • vue 导航 + router-view 局部刷新
  • AI技术专题:电商AI专题
  • java使用aspose读取word里的图片
  • YOLOv8 模块添加与修改讲解:从源码修改到配置文件配置
  • Nacos服务注册失败解决方案
  • pysnmp 操作流程和模块交互关系的可视化总结
  • JVM深度解析:执行引擎、性能调优与故障诊断完全指南
  • 【Python从入门到精通】--pycharm虚拟环境详解
  • 深度解析关键词价值,实现精准流量匹配
  • SpringBoot解决下载接口文件名中文乱码问题的3种方法
  • Bash (Bourne Again SHell)
  • Ftrace 调试 Rockchip MIPI D-PHY 驱动步骤
  • 明远智睿SD2351核心板:边缘计算时代的工业级核心引擎深度解析
  • 深度学习之模型压缩三驾马车:基于ResNet18的模型剪枝实战(3)
  • DEVICENET转MODBUS TCP网关连接DeviceNet数字远程IO模块配置案例
  • 解决新版RN 热更新报错:recreateReactContextInBackground
  • Unity Mecanim C# 动画切换实践:实现随机播放待机动画
  • 网络安全:OWASP防护守则
  • Tomcat调优
  • Ntfs!NtfsAllocateRestartTableIndex函数分析和Ntfs!DIRTY_PAGE_ENTRY_V0结构的关系
  • CSS 基础选择器 文字控制属性 综合案例
  • python3.12安装记录
  • 分割任意组织:用于医学图像分割的单样本参考引导免训练自动点提示方法|文献速递-深度学习医疗AI最新文献
  • MCU、MPU、GPU、Soc、DSP、FPGA、CPLD……它们到底是什么?