前端Vue3国际化开发 :使用vue-i18n库和Element Plus 组件实现_vue3 国际化
前端Vue3国际化开发 :使用vue-i18n库和Element Plus 组件实现
目录
- 引言
- 国际化核心概念
- 实现效果展示
3.1 Element Plus组件国际化
3.2 页面内容国际化
3.3 语言本地持久化存储 - 具体实现步骤
4.1 安装vue-i18n
4.2 创建语言资源文件
4.3 配置与挂载i18n
4.4 语言持久化存储
4.5 在组件中使用国际化
4.6 配置Element Plus国际化
4.7 解决热更新问题 - 完整工作流程解析
- 注意事项
1、引言
本文将解析基于 Vue3
和 Element Plus
的国际化架构实现,从核心概念到实际应用,带您全面了解多语言支持在现代化前端应用中的实现方式。
2、国际化(i18n)核心概念
国际化(Internationalization,简称 i18n)是指设计软件应用时,使其能适应多种语言和地区需求的过程。在 Vue 生态中,主要通过 vue-i18n
库实现(Vue I18n 是 Vue.js 的国际化插件),配合 Element Plus 的国际化支持,可构建完整的国际化应用。
核心组件:
- vue-i18n:Vue.js的官方国际化插件
- Element Plus国际化:Element Plus组件库的多语言支持
- 语言资源文件:存储不同语言的翻译内容
3、实现效果
3.1 Element Plus组件的国际化
前端国际化开发效果
3.2 使用vue-i8n插件实现页面的国际化
前端国际化开发效果
3.3 国际化语言本地持久化存储
语言本地持久化存储
4、具体步骤(Vue3 + Element Plus + i18n)
4.1 vue-i18n
Vue I18n
Vue i18n插件在Vue3
中需要使用v9
版本,这一点需要注意!!
(我当时写项目的时候没有注意到这个一点,直接安装的最新版,目前为止还没发现什么问题,大家自己选择)
npm install vue-i18n@9 # Vue3 专用版本或者yarn add vue-i18n@9或者pnpm add vue-i18n@9
4.2 创建自定义语言资源文件
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: \'部门负责人\',// 实验室管理管理: \'管理\',人员信息: \'人员信息\',序号: \'序号\',姓名: \'姓名\',学工号: \'学工号\',操作: \'操作\',编辑: \'编辑\',`在这里插入代码片`}
(我一开始用的编号,后来发现代码可读性有点差,不利于后期维护,索性全用中文了!)
(可以分两个对照文档,一份中文,一份英文,我是直接放一起了,大家自行选择!)
4.3 合并 Element Plus 语言包和自定义语言包并在main.ts挂载
在main.ts中配置i18n并挂载到Vue应用:
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) : nullconst 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.value = locale // 操作ref的value属性useLocale(computed(() => (locale === \'zh-cn\' ? zhCn : en)))}// 使用 Element Plus 和 i18napp.use(ElementPlus, {locale: computed(() => (i18n.global.locale.value === \'zh-cn\' ? zhCn : en))})app.use(i18n)// 挂载语言切换方法app.config.globalProperties.$changeLocale = changeLocaleapp.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
方法挂载到全局,方便在任何组件中调用
4.4 语言持久化存储
// 在组件中使用语言状态管理<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\'
的值,并作为初始语言设置i18n
和Element 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\'}}})
4.5 vue页面中使用useI18n中的 $t
函数式组件传递值
在Vue组件中通过useI18n使用翻译函数:
代码:
<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>
效果展示:
4.6 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>
效果展示:
4.7 热更新问题
比如:表单验证规则
如果按照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\' }],}})
效果:
热更新问题
5、完整工作流程解析如下:
1、初始化阶段:
- 从sessionStorage加载上次选择的语言
- 创建i18n实例并合并语言包
- 配置Element Plus使用对应语言包
2、语言切换流程:
- 用户选择新语言
- 更新i18n的locale值
- 更新Element Plus的locale配置
- 将新语言设置保存到sessionStorage
3、组件渲染流程:
- 组件使用t()函数获取翻译文本
- 响应式系统检测语言变化自动更新界面
- Element Plus组件根据当前语言显示对应内容