1 业务结构:
src/lang/
├── index.js # 主入口文件(重构)
├── languageMap.js # 保持不变
├── element-plus.i18n.js # 保持不变
├── modules/ # 新增模块目录
│ ├── index.js # 模块聚合
│ ├── common.js # 公共词汇
│ ├── auth.js # 认证相关
│ ├── product.js # 商品管理
│ ├── order.js # 订单管理
│ ├── finance.js # 财务管理
│ ├── customer.js # 客户管理
│ └── report.js # 报表统计
└── tenant/ # 租户自定义(可选)
├── tenant-001.js
└── tenant-002.js
2 创建模块化语言文件
export default {
'zh-CN': {
common: {
save: '保存',
cancel: '取消',
delete: '删除',
edit: '编辑',
confirm: '确认',
loading: '加载中...',
search: '搜索',
reset: '重置',
operation: '操作',
status: '状态',
createTime: '创建时间',
updateTime: '更新时间'
},
message: {
success: '操作成功',
error: '操作失败',
confirmDelete: '确认删除吗?',
noData: '暂无数据'
}
},
'en-US': {
common: {
save: 'Save',
cancel: 'Cancel',
delete: 'Delete',
edit: 'Edit',
confirm: 'Confirm',
loading: 'Loading...',
search: 'Search',
reset: 'Reset',
operation: 'Operation',
status: 'Status',
createTime: 'Create Time',
updateTime: 'Update Time'
},
message: {
success: 'Operation successful',
error: 'Operation failed',
confirmDelete: 'Confirm deletion?',
noData: 'No data'
}
},
'es-ES': {
common: {
save: 'Guardar',
cancel: 'Cancelar',
delete: 'Eliminar',
edit: 'Editar',
confirm: 'Confirmar',
loading: 'Cargando...',
search: 'Buscar',
reset: 'Restablecer',
operation: 'Operación',
status: 'Estado',
createTime: 'Tiempo de creación',
updateTime: 'Tiempo de actualización'
},
message: {
success: 'Operación exitosa',
error: 'Operación fallida',
confirmDelete: '¿Confirmar eliminación?',
noData: 'Sin datos'
}
}
}
3 模块聚合文件
import common from './common.js'
import auth from './auth.js'
import product from './product.js'
import order from './order.js'
import finance from './finance.js'
import customer from './customer.js'
import report from './report.js'
function mergeModules(modules) {
const languages = ['zh-CN', 'en-US', 'es-ES']
const result = {}
languages.forEach(lang => {
result[lang] = {}
modules.forEach(module => {
if (module[lang]) {
Object.keys(module[lang]).forEach(key => {
result[lang][key] = {
...result[lang][key],
...module[lang][key]
}
})
}
})
})
return result
}
const allModules = [common, auth, product, order, finance, customer, report]
const messages = mergeModules(allModules)
export default messages
4 重构主入口文件
import { createI18n } from "vue-i18n"
import messages from './modules/index.js'
import { createPinia } from "pinia";
import useUserStore from "@/store/modules/user";
const pinia = createPinia()
const userStore = useUserStore(pinia)
const loadTenantMessages = async (tenantType) => {
try {
const tenantMsg = await import(`./tenant/tenant-${tenantType}.js`)
return tenantMsg.default || {}
} catch (error) {
console.log(`租户 ${tenantType} 无自定义配置`)
return {}
}
}
export const createI18nInstance = async (locale = 'zh-CN') => {
const tenantType = userStore.userType || '00'
const tenantMessages = await loadTenantMessages(tenantType, locale)
const finalMessages = {}
const languages = ['zh-CN', 'en-US', 'es-ES']
languages.forEach(lang => {
finalMessages[lang] = {
...messages[lang],
...(tenantMessages[lang] || {})
}
})
const i18n = createI18n({
legacy: false,
locale: locale,
fallbackLocale: 'zh-CN',
messages: finalMessages,
silentTranslationWarn: true,
missingWarn: false
})
return i18n
}
export const i18n = createI18n({
legacy: false,
locale: 'zh-CN',
fallbackLocale: 'zh-CN',
messages: messages,
})
export default i18n
5 更新语言映射配置
export function getLocaleConfig(locale) {
const localeMap = {
'en': 'en-US',
'es': 'es-ES',
'zh': 'zh-CN',
'en-US': 'en-US',
'es-ES': 'es-ES',
'zh-CN': 'zh-CN'
}
return localeMap[locale] || 'es-ES'
}
export function getCurrencyConfig(locale) {
const currencyMap = {
'en': { locale: 'en-US', symbol: '$', currency: 'USD' },
'es': { locale: 'es-ES', symbol: '€', currency: 'EUR' },
'zh': { locale: 'zh-CN', symbol: '¥', currency: 'CNY' },
'en-US': { locale: 'en-US', symbol: '$', currency: 'USD' },
'es-ES': { locale: 'es-ES', symbol: '€', currency: 'EUR' },
'zh-CN': { locale: 'zh-CN', symbol: '¥', currency: 'CNY' }
}
return currencyMap[locale] || { locale: 'es-ES', symbol: '€', currency: 'EUR' }
}
export const SUPPORTED_LANGUAGES = [
{ value: 'zh-CN', label: '中文' },
{ value: 'en-US', label: 'English' },
{ value: 'es-ES', label: 'Español' }
]
6 更新主组件
// APP.vue
<template>
<el-config-provider :locale="elementLocales[effectiveLang]">
<router-view></router-view>
</el-config-provider>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue'
import { useLanguageStore } from '@/store/modules/language'
import { elementLocales } from '@/lang/element-plus.i18n'
import { useI18n } from 'vue-i18n'
import { getLocaleConfig } from '@/lang/languageMap'
const languageStore = useLanguageStore()
const { locale } = useI18n()
// 计算有效的语言代码
const effectiveLang = computed(() => {
const storeLang = languageStore.language
return getLocaleConfig(storeLang)
})
// 监听语言变化
watch(effectiveLang, (newLang) => {
locale.value = newLang
// 可以在这里添加语言切换的其它逻辑,如更新页面标题等
})
// 初始化语言
onMounted(() => {
locale.value = effectiveLang.value
})
</script>
7 封装工具函数 - 按需加载
import { i18n } from '@/lang'
export const loadLanguageModule = async (moduleName) => {
try {
const module = await import(`@/lang/modules/${moduleName}.js`)
const { locale } = i18n.global
const currentMessages = i18n.global.getLocaleMessage(locale)
i18n.global.mergeLocaleMessage(locale, {
...currentMessages,
...module.default[locale]
})
} catch (error) {
console.warn(`Failed to load module: ${moduleName}`, error)
}
}
export const t = (key, defaultValue = '') => {
const value = i18n.global.t(key)
return value === key ? defaultValue : value
}
export const translateBatch = (keys, namespace = '') => {
const result = {}
keys.forEach(key => {
const fullKey = namespace ? `${namespace}.${key}` : key
result[key] = t(fullKey, key)
})
return result
}
8 使用示例
<template>
<div>
<h1>{{ $t('order.title') }}</h1>
<el-button type="primary">
{{ $t('order.create') }}
</el-button>
<span>{{ $t('order.status.pending') }}</span>
<span>{{ $t('common.message.success') }}</span>
</div>
</template>
<script setup>
import { useI18n } from 'vue-i18n'
import { loadLanguageModule } from '@/utils/i18n-utils'
const { t } = useI18n()
// 如果需要动态加载模块
onMounted(async () => {
await loadLanguageModule('report') // 按需加载报表模块
})
</script>