一. 概述
该文章主要基于vue3+elementPlus+vue-i18n完成国际化配置,首先,确保已经安装了vue-i18n和element-plus,
该项目国际化配置主要分elementPlus组件配置和自定义国际化组件配置两个方面,配置的入口文件分别在布局组件ElConfigProvider和main.js文件中
会先以一个简易版本为示例让大家上手,之后再封装配置用于实际的项目中。
二. 配置基本流程(简易示例)
main.js
css
import { createI18n } from 'vue-i18n';
const i18n = createI18n({
legacy: false,
locale: 'zh', // 应用默认语言
messages: {
en: {
greeting: 'Hello',
// ...其他应用翻译
},
zh: {
greeting: '你好',
// ...其他应用翻译
},
th: {
greeting: '泰语你好',
}
}
})
const router = createRouter({
history: createWebHistory(),
routes
})
createApp(App)
.use(router) // 注册路由
.use(ElementPlus) //配置elementui组件翻译
.use(i18n) // 注册i18n实例
.mount('#app')
该代码片段完成了以下国际化(i18n)的核心配置
- i18n实例创建
- 语言挂载到Vue应用
- 已实现的基础功能
支持中/英/泰三语言
动态语言切换基础架构
全局翻译占位符(通过 $t('greeting') 使用)
全局语言上下文传递
布局组件
css
<template>
<ElConfigProvider :locale="currentElementLocale">
<div>主页面</div>
<el-dropdown @command="handleLanguageChange" style="margin-left:400px;">
<span class="el-dropdown-link">
语言设置<el-icon><arrow-down /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="zh">
中文
</el-dropdown-item>
<el-dropdown-item command="en">
English
<el-dropdown-item command="th" >
泰语
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<RouterView />
</ElConfigProvider>
</template>
<script setup>
import { computed } from 'vue'
import { ElConfigProvider } from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/es/locale/lang/en'
import th from 'element-plus/es/locale/lang/th'
import { useI18n } from 'vue-i18n'
const { locale, t } = useI18n()
const handleLanguageChange = (command) => {
locale.value = command;
localStorage.setItem('lang', command);
}
const currentElementLocale = computed(() => {
return locale.value === 'zh' ? zhCn :locale.value === 'en'?en:th
})
</script>
完成以下功能
-
语言切换UI实现
1.1 通过el-dropdown组件构建语言选择下拉菜单,支持"中文/English/泰语"3种语言切换
1.2 选择时触发handleLanguageChange方法,参数为语言标识符(zh/en/th)
-
语言状态管理
2.1 使用vue-i18n的locale响应式变量保存当前语言
2.2 通过localStorage持久化存储用户语言选择,实现跨会话保持
-
Element Plus组件国际化
3.1 通过ElConfigProvider组件的locale属性,将Element UI组件语言绑定到计算属性currentElementLocale
3.2 动态返回对应语言包(zhCn/en/th),实现按钮/提示等组件文本的本地化
测试组件
css
<template>
<div>
首页
<div>{{ $t("greeting") }}</div>
<!-- 使用vue-i18n -->
<el-button type="primary">确定</el-button> <!-- 中文显示"确定",英文显示"Confirm" -->
<el-button>提示</el-button>
<el-date-picker v-model="value2" type="month" placeholder="选择月">
</el-date-picker>
<!-- Element的按钮文本由内置i18n处理 -->
</div>
</template>
<script setup>
import {ref} from 'vue'
const value2 = ref('')
</script>
<style lang="scss" scoped></style>
注: el-date-picker组件测试的elementPlus组件的国际化
三. 项目实战
实际项目中,由于语言的多样性,国际化文件可能比较庞大,需要在一个目录下进行管理,其主要优化方向有如下几点
- 动态加载语言文件
css
// setup18n
export async function setupI18n(app: App) {
const options = await createI18nOptions();
i18n = createI18n(options) as I18n;
app.use(i18n);
}
// options
async function createI18nOptions(): Promise<I18nOptions> {
const localeStore = useLocaleStoreWithOut();
const locale = localeStore.getLocale;
const defaultLocal = await import(`./lang/${locale}.ts`);
const message = defaultLocal.default?.message ?? {};
setHtmlPageLang(locale);
setLoadLocalePool((loadLocalePool) => {
loadLocalePool.push(locale);
});
return {
legacy: false,
locale,
fallbackLocale: fallback,
messages: {
[locale]: message,
},
availableLocales: availableLocales,
sync: true, //If you don't want to inherit locale from global scope, you need to set sync of i18n component option to false.
silentTranslationWarn: true, // true - warning off
missingWarn: false,
silentFallbackWarn: true,
globalInjection: true,
};
}
// 使用`await`等待`i18n`初始化完成
await setupI18n(app);
}
比如en.ts文件,批量加载目标语言的国际化文件
css
import { genMessage } from '../helper';
import elLocale from 'element-plus/es/locale/lang/en';
const modules = import.meta.glob('./en/**/*.ts', { eager: true, import: 'default' });
export default {
message: {
...genMessage(modules, 'en'),
elLocale,
},
dateLocale: null,
dateLocaleName: 'en',
};
- 切换语言关联i18n.glob属性
css
export function setHtmlPageLang(locale: LocaleType) {
document.querySelector('html')?.setAttribute('lang', locale);
}
css
function setI18nLanguage(locale: LocaleType) {
const localeStore = useLocaleStoreWithOut();
if (i18n.mode === 'legacy') {
i18n.global.locale = locale;
} else {
(i18n.global.locale as any).value = locale;
}
localeStore.setLocaleInfo({ locale });
setHtmlPageLang(locale);
}
css
async function changeLocale(locale: LocaleType) {
const globalI18n = i18n.global;
const currentLocale = unref(globalI18n.locale);
if (currentLocale === locale) return locale;
if (loadLocalePool.includes(locale)) {
setI18nLanguage(locale);
return locale;
}
const langModule = ((await import(`./lang/${locale}.ts`)) as any).default as LangModule;
if (!langModule) return;
const { message } = langModule;
globalI18n.setLocaleMessage(locale, message);
loadLocalePool.push(locale);
setI18nLanguage(locale);
return locale;
}
globalI18n.setLocaleMessage(locale, message)完成对语言的切换
注:i18n = createI18n(options) as I18n;
3.利用pinia,对数据进行统一管理
更多优化可阅读往期文章:Vue3国际化实战:动态加载语言包与Element Plus组件集成分步指南