多语言国际化系统 (i18n)
这是一个为 LaiTool Pro 设计的完整多语言国际化解决方案,支持对象键和字符串键两种使用方式,提供完整的代码提示和类型安全。
✨ 特性
- 🌍 5种语言支持:简体中文、繁体中文、英文、日文、韩文
- 🎯 智能代码提示:使用对象键获得完整的 IntelliSense 支持
- 🛡️ 类型安全:完整的 TypeScript 支持,编译时检查
- 💰 多货币格式化:支持 CNY、USD、EUR、JPY、KRW 等
- 📅 日期时间本地化:根据语言自动格式化日期时间
- 🔄 动态语言切换:运行时无缝切换语言
- 💾 自动持久化:语言设置自动保存到本地存储
- 🔧 向下兼容:同时支持新旧两种 API 使用方式
- ⚡ Electron 优化:解决了 Electron 环境下的动态导入问题
🔧 最新修复 (2025年9月5日)
- ✅ 修复了 Electron 环境下的语言文件加载问题
- ✅ 使用静态导入替代动态导入,避免路径解析错误
- ✅ 优化了语言切换性能,现在是同步操作
- ✅ 增强了错误处理和日志记录
🏗️ 架构结构
src/i18n/
├── index.ts # 核心 I18nManager 类
├── main.ts # 统一导出入口
├── keys.ts # 翻译键对象定义(提供代码提示)
├── types.ts # TypeScript 类型定义
├── constants.ts # 常量和配置
├── locales/ # 语言包目录
│ ├── zh-cn.ts # 简体中文
│ ├── zh-tw.ts # 繁体中文
│ ├── en.ts # 英文
│ ├── ja.ts # 日文
│ └── ko.ts # 韩文
└── utils/
└── helpers.ts # 便捷工具函数
🚀 快速开始
基础用法
import { t, menu, common, video, formatPrice } from '@/i18n/main'
// 🎯 推荐方式:使用对象键(有完整代码提示)
const title = t(menu.home) // ✅ 输入 "menu." 显示所有选项
const save = t(common.save) // ✅ 类型安全,编译时检查
const generate = t(video.generate) // ✅ 自动补全,不会拼写错误
// 传统方式:使用字符串键(仍然支持)
const titleStr = t('menu.home') // ⚠️ 没有代码提示
// 价格格式化
const price = formatPrice(99.99, 'CNY') // "¥99.99"
在 Vue 组件中使用
<template>
<div>
<h1>{{ t(menu.home) }}</h1>
<button @click="save">{{ t(common.save) }}</button>
<button @click="cancel">{{ t(common.cancel) }}</button>
<p>{{ formatPrice(99.99, 'CNY') }}</p>
</div>
</template>
<script setup>
import { t, formatPrice, menu, common } from '@/i18n/main'
function save() {
console.log(t(common.loading))
}
function cancel() {
console.log(t(common.cancelled))
}
</script>
📚 可用的键对象
导入键对象后,您可以享受完整的代码提示:
import {
menu, // 菜单相关
common, // 通用操作
video, // 视频功能
settings, // 设置选项
price, // 价格相关
task, // 任务管理
file, // 文件操作
project, // 项目管理
error, // 错误信息
validation // 表单验证
} from '@/i18n/main'
// 使用示例
const homeTitle = t(menu.home) // "首页"
const saveButton = t(common.save) // "保存"
const videoGenerate = t(video.generate) // "生成视频"
const generalSettings = t(settings.general) // "通用设置"
🛠️ API 参考
核心翻译函数
t(key, params?)
支持对象键和字符串键的翻译函数
// 对象键方式(推荐)
t(menu.home) // "首页"
t(common.welcome, { name: '张三' }) // "欢迎 张三"
// 字符串键方式
t('menu.home') // "首页"
t('common.welcome', { name: '张三' }) // "欢迎 张三"
格式化函数
formatPrice(amount, currency?)
价格格式化
formatPrice(99.99, 'CNY') // "¥99.99"
formatPrice(99.99, 'USD') // "$99.99"
formatPrice(99.99, 'EUR') // "€99.99"
formatPrice(99.99, 'JPY') // "¥100"
formatPrice(99.99, 'KRW') // "₩100"
formatNumber(number, type?, locale?)
数字格式化
formatNumber(1234.56, 'decimal') // "1,234.56"
formatNumber(0.856, 'percent') // "85.6%"
formatNumber(1234, 'integer') // "1,234"
formatNumber(99.99, 'currency') // "¥99.99"
formatDate(date, type?, locale?)
日期格式化
formatDate(new Date(), 'short') // "2025/9/5"
formatDate(new Date(), 'medium') // "2025年9月5日"
formatDate(new Date(), 'long') // "2025年9月5日 星期四"
formatDate(new Date(), 'time') // "14:30:45"
formatDate(new Date(), 'dateTime') // "2025年9月5日 14:30"
语言管理
switchLocale(locale)
切换语言
await switchLocale('en') // 切换到英文
await switchLocale('zh-tw') // 切换到繁体中文
await switchLocale('ja') // 切换到日文
getCurrentLocale()
获取当前语言
const currentLang = getCurrentLocale() // "zh-cn"
getSupportedLocales()
获取支持的语言列表
const languages = getSupportedLocales()
// ['zh-cn', 'zh-tw', 'en', 'ja', 'ko']
detectAndSetLanguage()
自动检测并设置语言
const detectedLang = await detectAndSetLanguage()
🌍 支持的语言
| 语言代码 | 语言名称 | 默认货币 | 示例 |
|---|---|---|---|
| zh-cn | 简体中文 | CNY (¥) | 首页 |
| zh-tw | 繁体中文 | TWD (NT$) | 首頁 |
| en | English | USD ($) | Home |
| ja | 日本語 | JPY (¥) | ホーム |
| ko | 한국어 | KRW (₩) | 홈 |
💰 货币格式化
| 货币代码 | 符号 | 示例输出 |
|---|---|---|
| CNY | ¥ | ¥99.99 |
| USD | $ | $99.99 |
| EUR | € | €99.99 |
| JPY | ¥ | ¥100 |
| KRW | ₩ | ₩100 |
| TWD | NT$ | NT$100 |
🎯 最佳实践
✅ 推荐做法
-
使用对象键获得代码提示
import { t, menu, common } from '@/i18n/main' const title = t(menu.home) // ✅ 有完整提示 const save = t(common.save) // ✅ 类型安全 -
在组件中使用 computed
const pageTitle = computed(() => t(menu.home)) const buttonText = computed(() => t(common.save)) -
创建翻译 Hook
function usePageTranslations() { return { title: computed(() => t(menu.home)), buttons: { save: computed(() => t(common.save)), cancel: computed(() => t(common.cancel)) } } }
❌ 避免的做法
-
不要使用魔法字符串
const title = t('menu.home') // ❌ 容易出错,没有提示 -
不要在模板中直接使用字符串键
<!-- ❌ 不推荐 --> <h1>{{ t('menu.home') }}</h1> <!-- ✅ 推荐 --> <h1>{{ t(menu.home) }}</h1>
🔧 开发指南
添加新的翻译键
-
在
keys.ts中添加键定义export const newCategory = { newKey: 'newCategory.newKey' } as const -
在所有语言文件中添加翻译
// zh-cn.ts newCategory: { newKey: '新功能' } // en.ts newCategory: { newKey: 'New Feature' } -
在
main.ts中导出export { newCategory } from './keys'
测试多语言功能
import { switchLocale, t, menu } from '@/i18n/main'
// 测试所有语言
const languages = ['zh-cn', 'zh-tw', 'en', 'ja', 'ko']
for (const lang of languages) {
await switchLocale(lang)
console.log(`${lang}: ${t(menu.home)}`)
}
🐛 故障排除
常见问题
Q: 代码提示不显示?
A: 确保正确导入了键对象:import { menu, common } from '@/i18n/main'
Q: 翻译显示为键名? A: 检查语言文件中是否包含对应的键,确保所有语言文件结构一致。
Q: 语言切换后页面没更新?
A: 在 Vue 组件中使用 computed(() => t(key)) 确保响应式更新。
Q: TypeScript 报错键不存在?
A: 检查是否在 keys.ts 中定义了对应的键,并在 main.ts 中正确导出。
📖 使用示例
完整的多语言页面
<template>
<div class="page">
<header>
<h1>{{ t(menu.home) }}</h1>
<select @change="changeLanguage" v-model="currentLang">
<option value="zh-cn">简体中文</option>
<option value="zh-tw">繁体中文</option>
<option value="en">English</option>
<option value="ja">日本語</option>
<option value="ko">한국어</option>
</select>
</header>
<main>
<div class="actions">
<button @click="save">{{ t(common.save) }}</button>
<button @click="cancel">{{ t(common.cancel) }}</button>
<button @click="generateVideo">{{ t(video.generate) }}</button>
</div>
<div class="price">
<p>{{ t(price.currentPrice) }}: {{ formatPrice(99.99, 'CNY') }}</p>
</div>
<div class="status">
<p v-if="loading">{{ t(common.loading) }}</p>
<p v-if="success">{{ t(common.success) }}</p>
<p v-if="error">{{ t(common.error) }}</p>
</div>
</main>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import {
t,
formatPrice,
switchLocale,
getCurrentLocale,
menu,
common,
video,
price
} from '@/i18n/main'
const currentLang = ref(getCurrentLocale())
const loading = ref(false)
const success = ref(false)
const error = ref(false)
async function changeLanguage(event) {
const newLang = event.target.value
await switchLocale(newLang)
currentLang.value = newLang
}
function save() {
loading.value = true
setTimeout(() => {
loading.value = false
success.value = true
}, 1000)
}
function cancel() {
console.log(t(common.cancel))
}
function generateVideo() {
console.log(t(video.generate))
}
</script>
这就是您的多语言系统的完整使用指南!🎉
🔀 翻译文本合并功能
新增了翻译文本合并功能,可以根据不同语言使用相应的分隔符来合并多个翻译文本。
主要功能
1. mergeTranslations - 合并两个翻译
合并两个翻译键对应的文本,支持自定义分隔符和结尾符号。
import { mergeTranslations } from '@/i18n'
// 基本使用
const result = mergeTranslations('common.save', 'common.cancel')
// 中文: "保存,取消"
// 英文: "Save, Cancel"
// 带选项使用
const result = mergeTranslations(
'video.generate',
'video.processing',
{
separator: 'comma', // 分隔符类型
suffix: 'period', // 结尾符号
locale: 'zh-cn' // 指定语言
}
)
// 结果: "生成视频,处理中。"
2. mergeMultipleTranslations - 合并多个翻译
合并多个翻译键对应的文本。
import { mergeMultipleTranslations } from '@/i18n'
const result = mergeMultipleTranslations(
['common.save', 'common.edit', 'common.delete'],
{
separator: 'comma',
suffix: 'period'
}
)
// 中文: "保存,编辑,删除。"
// 英文: "Save, Edit, Delete."
3. getLocaleSeparators - 获取语言分隔符
获取指定语言的分隔符配置。
import { getLocaleSeparators } from '@/i18n'
const separators = getLocaleSeparators('zh-cn')
// 返回: {
// comma: ',', semicolon: ';', period: '。', colon: ':', space: ' ',
// exclamation: '!', question: '?', ellipsis: '……'
// }
配置选项
MergeTranslationOptions
interface MergeTranslationOptions {
separator?: SeparatorType | string // 分隔符
suffix?: SeparatorType | string | null // 结尾符号
locale?: string // 指定语言
}
支持的分隔符类型
comma- 逗号分隔semicolon- 分号分隔period- 句号分隔colon- 冒号分隔space- 空格分隔exclamation- 叹号分隔 🆕question- 问号分隔 🆕ellipsis- 省略号分隔 🆕- 或者直接传入自定义字符串
🎯 推荐使用 Separators 常量(智能提示)🆕
为了获得更好的开发体验,我们提供了 Separators 常量对象:
import { mergeTranslations, Separators } from '@/i18n'
// ✅ 推荐方式:使用 Separators 常量(有完整智能提示)
const result = mergeTranslations('common.save', 'common.cancel', {
separator: Separators.comma, // 输入 Separators. 显示所有选项
suffix: Separators.period // 每个选项都有详细注释说明
})
// ❌ 传统方式:使用字符串(容易拼错,没有提示)
const oldWay = mergeTranslations('common.save', 'common.cancel', {
separator: 'comma', // 没有智能提示
suffix: 'peroid' // 可能拼写错误
})
Separators 常量的优势:
- ✅ 完整的智能提示和自动补全
- ✅ 类型安全,编译时检查错误
- ✅ 每个选项都有详细注释说明效果
- ✅ 重构友好,修改时自动更新引用
- ✅ 更好的代码可读性和维护性
语言分隔符支持
目前支持以下语言的专用分隔符:
| 语言 | 逗号 | 分号 | 句号 | 冒号 | 空格 | 叹号 | 问号 | 省略号 |
|---|---|---|---|---|---|---|---|---|
| zh-cn | , | ; | 。 | : | (空格) | ! | ? | …… |
| zh-tw | , | ; | 。 | : | (空格) | ! | ? | …… |
| en | , (带空格) | ; (带空格) | . (带空格) | : (带空格) | (空格) | ! (带空格) | ? (带空格) | ... |
| ja | 、 | ; | 。 | : | (空格) | ! | ? | …… |
| ko | , (带空格) | ; (带空格) | . (带空格) | : (带空格) | (空格) | ! (带空格) | ? (带空格) | ... |
合并功能使用场景
🎯 推荐使用方式(使用 Separators 常量)
import { mergeTranslations, mergeMultipleTranslations, Separators } from '@/i18n'
// ✅ 组合操作按钮(智能提示)
const actionButtons = mergeMultipleTranslations(
['common.save', 'common.edit', 'common.delete'],
{ separator: Separators.space } // 输入 Separators. 显示所有可用选项
)
// ✅ 成功提示(叹号)
const successMessage = mergeTranslations(
'common.success',
'file.upload',
{
separator: Separators.exclamation,
suffix: Separators.exclamation
}
)
// ✅ 确认对话框(问号)
const confirmDialog = mergeTranslations(
'common.confirm',
'common.delete',
{
separator: Separators.space,
suffix: Separators.question
}
)
// ✅ 加载状态(省略号)
const loadingStatus = mergeTranslations(
'common.loading',
'video.processing',
{ separator: Separators.ellipsis }
)
传统使用方式(仍然支持)
1. 组合操作按钮
const actionButtons = mergeMultipleTranslations(
['common.save', 'common.edit', 'common.delete'],
{ separator: 'space' }
)
2. 文件信息显示
const fileInfo = mergeTranslations(
'file.size',
'file.type',
{ separator: 'comma' }
)
3. 任务状态
const taskStatus = mergeTranslations(
'task.status',
'task.progress',
{ separator: 'colon' }
)
4. 错误信息
const errorMessage = mergeTranslations(
'error.uploadFailed',
'common.error_information',
{ separator: 'period', suffix: 'period' }
)
5. 带参数的翻译合并
const validation = mergeTranslations(
'validation.minLength',
'validation.maxLength',
{ separator: 'semicolon' },
{ min: 3 }, // 第一个翻译的参数
{ max: 20 } // 第二个翻译的参数
)
6. 新增标点符号使用场景 🆕
// 成功提示(叹号)
const successMessage = mergeTranslations(
'common.success',
'file.upload',
{ separator: 'exclamation', suffix: 'exclamation' }
)
// 中文: "成功!上传文件!" 英文: "Success! Upload File!"
// 确认对话框(问号)
const confirmDialog = mergeTranslations(
'common.confirm',
'common.delete',
{ separator: 'space', suffix: 'question' }
)
// 中文: "确认 删除?" 英文: "Confirm Delete?"
// 加载状态(省略号)
const loadingStatus = mergeTranslations(
'common.loading',
'video.processing',
{ separator: 'ellipsis', suffix: null }
)
// 中文: "加载中……处理中" 英文: "Loading...Processing"
// 警告信息(组合使用)
const warningMessage = mergeMultipleTranslations(
['common.warning', 'error.network', 'common.retry'],
{ separator: 'exclamation', suffix: 'question' }
)
// 中文: "警告!网络错误!重试?" 英文: "Warning! Network Error! Retry?"
合并功能注意事项
- 如果指定的语言不存在分隔符配置,会回退到英文配置
suffix设置为null时不添加结尾符号- 自定义分隔符会直接使用传入的字符串,不会根据语言调整
- 函数会自动获取当前语言设置,也可以通过
locale参数强制指定
完整的合并功能示例
<template>
<div class="merge-demo">
<h2>{{ t(menu.home) }}</h2>
<!-- 基本合并 -->
<p>{{ mergeTranslations('common.save', 'common.cancel') }}</p>
<!-- 多个合并 -->
<p>{{ fileOperations }}</p>
<!-- 带结尾符号 -->
<p>{{ taskInfo }}</p>
<!-- 自定义分隔符 -->
<p>{{ customSeparator }}</p>
</div>
</template>
<script setup>
import { computed } from 'vue'
import {
t,
mergeTranslations,
mergeMultipleTranslations,
menu
} from '@/i18n/main'
// 文件操作组合
const fileOperations = computed(() =>
mergeMultipleTranslations(
['file.upload', 'file.download', 'file.delete'],
{ separator: 'comma', suffix: 'period' }
)
)
// 任务信息
const taskInfo = computed(() =>
mergeTranslations(
'task.status',
'task.running',
{ separator: 'colon' }
)
)
// 自定义分隔符
const customSeparator = computed(() =>
mergeTranslations(
'book.title',
'book.author',
{ separator: ' | ', suffix: null }
)
)
</script>
这个完整的多语言系统现在包含了基础翻译功能和高级的文本合并功能!🚀