国际化提供者
国际化提供者是 DVHA 的核心概念之一,它是一个抽象层,负责处理应用程序的多语言和国际化功能。通过国际化提供者,您可以轻松地为应用添加多语言支持,提供翻译、语言切换等功能。
什么是国际化提供者?
国际化提供者是一个实现了特定接口的对象,它定义了如何处理应用的国际化需求。DVHA 通过国际化提供者来执行所有的国际化操作,包括:
- 文本翻译 (t)
- 语言切换 (changeLocale)
- 语言包加载 (loadLocale)
- 语言包合并 (mergeLocale)
- 获取当前语言 (getLocale)
- 获取支持的语言列表 (getLocales)
内置国际化提供者
DVHA 内置了 i18nProvider
,基于 vue-i18n
实现:
typescript
import { i18nProvider } from '@duxweb/dvha-core'
const provider = i18nProvider({
locale: 'zh-CN',
fallbackLocale: 'en-US',
messages: {
'zh-CN': {
welcome: '欢迎',
hello: '你好 {name}'
},
'en-US': {
welcome: 'Welcome',
hello: 'Hello {name}'
}
}
})
const config: IConfig = {
i18nProvider: provider,
// ... 其他配置
}
TIP
内置的 i18nProvider
基于成熟的 vue-i18n
库,提供完整的国际化功能,包括插值、复数、日期时间格式化等特性。它使用 Composition API 模式,支持 TypeScript 类型推导。
国际化提供者接口
typescript
interface I18nProvider {
// 翻译文本
t: (key: string, options?: any, defaultMessage?: string) => string
// 切换语言
changeLocale: (lang: string, options?: any) => Promise<any>
// 加载语言包
loadLocale: (lang: string, files: Record<string, unknown>) => Promise<any>
// 合并语言包
mergeLocale: (lang: string, messages: Record<string, unknown>) => void
// 获取当前语言
getLocale: () => string
// 获取支持的语言列表
getLocales: () => string[]
}
配置选项
I18nOptions
基于 vue-i18n
的配置选项:
typescript
interface I18nOptions {
locale?: string // 默认语言
fallbackLocale?: string | string[] // 回退语言
messages?: Record<string, any> // 语言包
legacy?: boolean // 是否使用 legacy API(默认 false)
missingWarn?: boolean // 缺失翻译警告(默认 false)
fallbackWarn?: boolean // 回退警告(默认 false)
[key: string]: any // 其他 vue-i18n 选项
}
配置说明
内置的 i18nProvider
自动设置了以下默认值:
legacy: false
- 使用 Composition API 模式missingWarn: false
- 关闭缺失翻译警告fallbackWarn: false
- 关闭回退警告
使用示例
基本配置
typescript
import { i18nProvider } from '@duxweb/dvha-core'
import enUS from './locales/en-US.json'
import zhCN from './locales/zh-CN.json'
const config: IConfig = {
i18nProvider: i18nProvider({
locale: 'zh-CN',
fallbackLocale: 'en-US',
messages: {
'zh-CN': zhCN,
'en-US': enUS
}
}),
// ... 其他配置
}
语言包结构
推荐的语言包结构:
json
// locales/zh-CN.json
{
"common": {
"save": "保存",
"cancel": "取消",
"confirm": "确认",
"delete": "删除"
},
"user": {
"profile": "用户资料",
"name": "姓名",
"email": "邮箱"
},
"message": {
"saveSuccess": "保存成功",
"deleteConfirm": "确定要删除 {name} 吗?"
}
}
json
// locales/en-US.json
{
"common": {
"save": "Save",
"cancel": "Cancel",
"confirm": "Confirm",
"delete": "Delete"
},
"user": {
"profile": "User Profile",
"name": "Name",
"email": "Email"
},
"message": {
"saveSuccess": "Save successfully",
"deleteConfirm": "Are you sure to delete {name}?"
}
}
高级配置
typescript
import { i18nProvider } from '@duxweb/dvha-core'
const provider = i18nProvider({
locale: 'zh-CN',
fallbackLocale: ['en-US', 'zh-CN'],
messages: {
'zh-CN': {
// 支持插值
greeting: '你好,{name}!',
// 支持复数
item: '没有项目 | 1 个项目 | {count} 个项目',
// 支持嵌套
nav: {
home: '首页',
about: '关于'
}
},
'en-US': {
greeting: 'Hello, {name}!',
item: 'no items | 1 item | {count} items',
nav: {
home: 'Home',
about: 'About'
}
}
}
})
动态语言包加载
typescript
import { i18nProvider } from '@duxweb/dvha-core'
const provider = i18nProvider({
locale: 'zh-CN',
fallbackLocale: 'en-US',
messages: {
'zh-CN': {},
'en-US': {}
}
})
// 动态加载语言包
async function loadLanguagePack(lang: string) {
try {
const messages = await import(`./locales/${lang}.json`)
await provider.loadLocale(lang, messages.default)
await provider.changeLocale(lang)
console.log(`Language pack loaded: ${lang}`)
} catch (error) {
console.error(`Failed to load language pack: ${lang}`, error)
}
}
// 动态合并语言包(用于插件或模块的额外翻译)
function mergeModuleTranslations(lang: string, moduleMessages: Record<string, unknown>) {
provider.mergeLocale(lang, moduleMessages)
}
// 使用示例
loadLanguagePack('ja-JP')
// 合并额外的翻译
mergeModuleTranslations('zh-CN', {
plugin: {
name: '插件名称',
settings: '插件设置'
}
})
获取语言信息
typescript
// 获取当前语言
const currentLang = provider.getLocale() // 'zh-CN'
// 获取所有支持的语言
const availableLanguages = provider.getLocales() // ['zh-CN', 'en-US']
// 检查语言是否支持
function isLanguageSupported(lang: string): boolean {
return provider.getLocales().includes(lang)
}
自定义国际化提供者
您也可以创建自定义的国际化提供者来适配特定的需求:
typescript
import type { I18nProvider } from '@duxweb/dvha-core'
// 基于其他 i18n 库的提供者
function customI18nProvider(options: any): I18nProvider {
// 初始化您的 i18n 实例
const i18n = createYourI18nInstance(options)
return {
t: (key: string, options?: any, defaultMessage?: string): string => {
const result = i18n.translate(key, options)
return result || defaultMessage || key
},
changeLocale: async (lang: string, options?: any): Promise<any> => {
await i18n.setLocale(lang)
return lang
},
loadLocale: async (lang: string, files: Record<string, unknown>): Promise<any> => {
i18n.addResourceBundle(lang, 'translation', files)
return lang
},
mergeLocale: (lang: string, messages: Record<string, unknown>): void => {
i18n.mergeResourceBundle(lang, 'translation', messages)
},
getLocale: (): string => {
return i18n.language
},
getLocales: (): string[] => {
return i18n.languages || []
}
}
}
与管理端集成
国际化提供者可以在全局配置,也可以在特定管理端中配置:
typescript
const config: IConfig = {
// 全局国际化提供者
i18nProvider: i18nProvider({
locale: 'zh-CN',
fallbackLocale: 'en-US',
messages: globalMessages
}),
manages: [
{
name: 'admin',
title: '管理后台',
// 管理端专用的国际化提供者
i18nProvider: i18nProvider({
locale: 'en-US',
fallbackLocale: 'zh-CN',
messages: adminMessages
})
},
{
name: 'merchant',
title: '商户后台',
// 商户端专用的国际化提供者
i18nProvider: i18nProvider({
locale: 'zh-CN',
fallbackLocale: 'en-US',
messages: merchantMessages
})
}
]
}
与 useI18n Hook 集成
国际化提供者通过 useI18n
Hook 在组件中使用:
typescript
import { useI18n } from '@duxweb/dvha-core'
export default {
setup() {
const { t, changeLocale, getLocale, loadLocale, mergeLocale, getLocales } = useI18n()
// 基本翻译
const title = t('page.title', null, '默认标题')
// 带参数的翻译
const greeting = t('welcome.message', { name: 'John' })
// 切换语言
const switchLanguage = async (lang: string) => {
await changeLocale(lang)
}
// 动态加载语言包
const loadNewLanguage = async (lang: string) => {
const messages = await import(`./locales/${lang}.json`)
await loadLocale(lang, messages.default)
await changeLocale(lang)
}
return {
title,
greeting,
switchLanguage,
loadNewLanguage,
currentLang: getLocale(),
availableLanguages: getLocales()
}
}
}
最佳实践
1. 语言包组织
locales/
├── zh-CN/
│ ├── common.json # 通用翻译
│ ├── user.json # 用户相关
│ └── admin.json # 管理端
├── en-US/
│ ├── common.json
│ ├── user.json
│ └── admin.json
└── index.ts # 语言包入口
2. 语言包合并
typescript
// locales/index.ts
import enUSAdmin from './en-US/admin.json'
import enUSCommon from './en-US/common.json'
import enUSUser from './en-US/user.json'
import zhCNAdmin from './zh-CN/admin.json'
import zhCNCommon from './zh-CN/common.json'
import zhCNUser from './zh-CN/user.json'
export const messages = {
'zh-CN': {
...zhCNCommon,
...zhCNUser,
...zhCNAdmin
},
'en-US': {
...enUSCommon,
...enUSUser,
...enUSAdmin
}
}
3. 类型安全
typescript
// types/i18n.ts
export interface LocaleMessages {
common: {
save: string
cancel: string
confirm: string
}
user: {
profile: string
name: string
email: string
}
}
declare module '@duxweb/dvha-core' {
interface I18nProvider {
t: <T extends keyof LocaleMessages>(
key: T,
options?: any,
defaultMessage?: string
) => string
}
}
4. 语言包模块化
typescript
// 模块化加载语言包
const loadModuleMessages = async (moduleName: string, lang: string) => {
try {
const module = await import(`./modules/${moduleName}/locales/${lang}.json`)
provider.mergeLocale(lang, {
[moduleName]: module.default
})
} catch (error) {
console.warn(`Failed to load ${moduleName} messages for ${lang}`)
}
}
// 批量加载模块
const loadAllModuleMessages = async (lang: string) => {
const modules = ['user', 'product', 'order']
await Promise.all(
modules.map(module => loadModuleMessages(module, lang))
)
}
5. 默认值策略
typescript
// 智能默认值函数
const smartTranslate = (key: string, options?: any, fallback?: string) => {
// 尝试翻译
const result = provider.t(key, options)
// 如果翻译失败,使用策略生成默认值
if (result === key) {
if (fallback) return fallback
// 从键值生成默认值
const parts = key.split('.')
const lastPart = parts[parts.length - 1]
return lastPart.charAt(0).toUpperCase() + lastPart.slice(1)
}
return result
}
性能优化
1. 按需加载语言包
typescript
const lazyLoadLanguagePack = async (lang: string) => {
// 检查是否已经加载
if (provider.getLocales().includes(lang)) {
return provider.changeLocale(lang)
}
// 动态导入语言包
const [common, specific] = await Promise.all([
import(`./locales/common/${lang}.json`),
import(`./locales/specific/${lang}.json`)
])
// 合并并加载
const merged = { ...common.default, ...specific.default }
await provider.loadLocale(lang, merged)
return provider.changeLocale(lang)
}
2. 翻译缓存
typescript
// 创建翻译缓存
const translationCache = new Map<string, string>()
const cachedTranslate = (key: string, options?: any, defaultMessage?: string) => {
const cacheKey = `${key}:${JSON.stringify(options)}`
if (translationCache.has(cacheKey)) {
return translationCache.get(cacheKey)!
}
const result = provider.t(key, options, defaultMessage)
translationCache.set(cacheKey, result)
return result
}
// 清理缓存(语言切换时)
const clearTranslationCache = () => {
translationCache.clear()
}
小提示
- 使用命名空间来组织翻译键值,避免冲突
- 为常用的翻译文本提供默认值
- 定期检查和清理未使用的翻译键值
- 考虑使用工具来自动化翻译流程
- 利用
mergeLocale
方法实现插件化的翻译扩展 - 使用
getLocales
方法动态构建语言切换器
下一步
了解如何在组件中使用国际化功能:
- 🌍 国际化 Hook (useI18n) - 在组件中使用国际化功能