|
|
@@ -0,0 +1,485 @@
|
|
|
+# 国际化完整指南
|
|
|
+
|
|
|
+## 📦 已完成的功能
|
|
|
+
|
|
|
+✅ vue-i18n 集成
|
|
|
+✅ 模块化语言包管理
|
|
|
+✅ 中英文双语支持
|
|
|
+✅ 语言切换功能
|
|
|
+✅ 持久化存储
|
|
|
+✅ Pinia 状态管理
|
|
|
+✅ 可复用组件
|
|
|
+✅ 完整文档
|
|
|
+
|
|
|
+## 📁 项目结构
|
|
|
+
|
|
|
+```
|
|
|
+intelligent-etmf-system-applet/
|
|
|
+├── i18n/ # i18n 配置
|
|
|
+│ ├── index.js # i18n 初始化
|
|
|
+│ └── README.md # 使用文档
|
|
|
+├── locales/ # 语言包(按模块分组)
|
|
|
+│ ├── common/ # 通用模块
|
|
|
+│ │ ├── zh_CN.js # 中文翻译
|
|
|
+│ │ └── en_US.js # 英文翻译
|
|
|
+│ ├── pages/ # 页面模块
|
|
|
+│ │ └── home/ # 首页
|
|
|
+│ │ ├── zh_CN.js # 中文翻译
|
|
|
+│ │ └── en_US.js # 英文翻译
|
|
|
+│ ├── components/ # 组件模块
|
|
|
+│ │ └── languageSwitcher/ # 语言切换组件
|
|
|
+│ │ ├── zh_CN.js # 中文翻译
|
|
|
+│ │ └── en_US.js # 英文翻译
|
|
|
+│ ├── index.js # 语言包总导出
|
|
|
+│ ├── README.md # 语言包管理文档
|
|
|
+│ ├── STRUCTURE.md # 目录结构说明
|
|
|
+│ └── COMPONENT_I18N.md # 组件国际化指南
|
|
|
+├── store/ # 状态管理
|
|
|
+│ └── locale.js # 语言切换 store
|
|
|
+├── utils/ # 工具函数
|
|
|
+│ └── i18n.js # i18n 工具函数
|
|
|
+├── components/ # 组件
|
|
|
+│ └── LanguageSwitcher/ # 语言切换组件
|
|
|
+│ └── index.vue
|
|
|
+└── main.js # 已集成 i18n
|
|
|
+```
|
|
|
+
|
|
|
+## 🚀 快速开始
|
|
|
+
|
|
|
+### 1. 在页面中使用国际化
|
|
|
+
|
|
|
+```vue
|
|
|
+<template>
|
|
|
+ <view>
|
|
|
+ <!-- 基础用法 -->
|
|
|
+ <text>{{ t('home.title') }}</text>
|
|
|
+
|
|
|
+ <!-- 嵌套键 -->
|
|
|
+ <text>{{ t('common.button.submit') }}</text>
|
|
|
+
|
|
|
+ <!-- 带参数 -->
|
|
|
+ <text>{{ t('common.greeting', { name: userName }) }}</text>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { useI18n } from 'vue-i18n'
|
|
|
+
|
|
|
+const { t } = useI18n()
|
|
|
+const userName = '张三'
|
|
|
+</script>
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 在组件中使用国际化
|
|
|
+
|
|
|
+```vue
|
|
|
+<template>
|
|
|
+ <view class="user-card">
|
|
|
+ <!-- 使用组件专属翻译 -->
|
|
|
+ <text>{{ t('components.userCard.title') }}</text>
|
|
|
+
|
|
|
+ <!-- 使用通用翻译 -->
|
|
|
+ <button>{{ t('common.button.confirm') }}</button>
|
|
|
+
|
|
|
+ <!-- 动态键 -->
|
|
|
+ <text>{{ t(`components.userCard.status.${user.status}`) }}</text>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { useI18n } from 'vue-i18n'
|
|
|
+
|
|
|
+const { t } = useI18n()
|
|
|
+const props = defineProps({
|
|
|
+ user: Object
|
|
|
+})
|
|
|
+</script>
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 使用语言切换组件
|
|
|
+
|
|
|
+```vue
|
|
|
+<template>
|
|
|
+ <view class="header">
|
|
|
+ <!-- 方式1:使用封装的组件 -->
|
|
|
+ <LanguageSwitcher />
|
|
|
+
|
|
|
+ <!-- 方式2:自定义切换逻辑 -->
|
|
|
+ <button @click="changeLanguage">切换语言</button>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { useLocaleStore } from '@/store/locale'
|
|
|
+import LanguageSwitcher from '@/components/LanguageSwitcher/index.vue'
|
|
|
+
|
|
|
+const localeStore = useLocaleStore()
|
|
|
+
|
|
|
+const changeLanguage = () => {
|
|
|
+ // 切换到下一个语言
|
|
|
+ localeStore.toggleLocale()
|
|
|
+
|
|
|
+ // 或切换到指定语言
|
|
|
+ // localeStore.setLocale('en-US')
|
|
|
+}
|
|
|
+</script>
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 在 JS 中使用(非组件环境)
|
|
|
+
|
|
|
+```javascript
|
|
|
+import { t } from '@/utils/i18n'
|
|
|
+
|
|
|
+// 在 API 请求中使用
|
|
|
+const showError = () => {
|
|
|
+ uni.showToast({
|
|
|
+ title: t('common.message.error'),
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 在工具函数中使用
|
|
|
+const formatStatus = (status) => {
|
|
|
+ return t(`order.status.${status}`)
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 🎨 为组件添加国际化
|
|
|
+
|
|
|
+### 为什么要为组件创建专门的翻译?
|
|
|
+
|
|
|
+- 组件有特定的业务术语
|
|
|
+- 组件需要在多处复用
|
|
|
+- 便于独立维护和版本管理
|
|
|
+
|
|
|
+### 快速示例
|
|
|
+
|
|
|
+创建 UserCard 组件的翻译:
|
|
|
+
|
|
|
+1. 创建翻译文件:`locales/components/userCard/zh_CN.js` 和 `en_US.js`
|
|
|
+2. 在 `locales/index.js` 中注册到 `components` 下
|
|
|
+3. 在组件中使用:`t('components.userCard.title')`
|
|
|
+
|
|
|
+**详细指南**:请查看 [组件国际化指南](./locales/COMPONENT_I18N.md)
|
|
|
+
|
|
|
+## 📝 添加新的翻译模块
|
|
|
+
|
|
|
+### 页面模块示例
|
|
|
+
|
|
|
+在对应目录下创建语言文件。例如创建产品管理页面模块:
|
|
|
+
|
|
|
+创建 `locales/pages/product/zh_CN.js`:
|
|
|
+```javascript
|
|
|
+export default {
|
|
|
+ title: '产品管理',
|
|
|
+ list: {
|
|
|
+ title: '产品列表',
|
|
|
+ empty: '暂无产品'
|
|
|
+ },
|
|
|
+ detail: {
|
|
|
+ name: '产品名称',
|
|
|
+ price: '价格',
|
|
|
+ stock: '库存'
|
|
|
+ },
|
|
|
+ action: {
|
|
|
+ add: '添加产品',
|
|
|
+ edit: '编辑',
|
|
|
+ delete: '删除'
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+创建 `locales/pages/product/en_US.js`:
|
|
|
+```javascript
|
|
|
+export default {
|
|
|
+ title: 'Product Management',
|
|
|
+ list: {
|
|
|
+ title: 'Product List',
|
|
|
+ empty: 'No products'
|
|
|
+ },
|
|
|
+ detail: {
|
|
|
+ name: 'Product Name',
|
|
|
+ price: 'Price',
|
|
|
+ stock: 'Stock'
|
|
|
+ },
|
|
|
+ action: {
|
|
|
+ add: 'Add Product',
|
|
|
+ edit: 'Edit',
|
|
|
+ delete: 'Delete'
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 步骤 2:注册模块
|
|
|
+
|
|
|
+在 `locales/index.js` 中导入新模块:
|
|
|
+```javascript
|
|
|
+// 导入通用模块
|
|
|
+import commonZhCN from './common/zh_CN'
|
|
|
+import commonEnUS from './common/en_US'
|
|
|
+
|
|
|
+// 导入页面模块
|
|
|
+import homeZhCN from './pages/home/zh_CN'
|
|
|
+import homeEnUS from './pages/home/en_US'
|
|
|
+import productZhCN from './pages/product/zh_CN' // 新增
|
|
|
+import productEnUS from './pages/product/en_US' // 新增
|
|
|
+
|
|
|
+// 导入组件模块
|
|
|
+import languageSwitcherZhCN from './components/languageSwitcher/zh_CN'
|
|
|
+import languageSwitcherEnUS from './components/languageSwitcher/en_US'
|
|
|
+
|
|
|
+export const messages = {
|
|
|
+ 'zh-CN': {
|
|
|
+ common: commonZhCN,
|
|
|
+ home: homeZhCN,
|
|
|
+ product: productZhCN, // 新增
|
|
|
+ components: {
|
|
|
+ languageSwitcher: languageSwitcherZhCN
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 'en-US': {
|
|
|
+ common: commonEnUS,
|
|
|
+ home: homeEnUS,
|
|
|
+ product: productEnUS, // 新增
|
|
|
+ components: {
|
|
|
+ languageSwitcher: languageSwitcherEnUS
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**注意**:
|
|
|
+- 页面模块直接注册在第一层
|
|
|
+- 组件模块注册在 `components` 对象下
|
|
|
+
|
|
|
+### 步骤 3:使用新模块
|
|
|
+
|
|
|
+```vue
|
|
|
+<template>
|
|
|
+ <view>
|
|
|
+ <text>{{ t('product.title') }}</text>
|
|
|
+ <text>{{ t('product.detail.name') }}</text>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+```
|
|
|
+
|
|
|
+## 🌍 添加新语言
|
|
|
+
|
|
|
+### 步骤 1:创建语言文件
|
|
|
+
|
|
|
+为每个现有模块创建新语言的翻译文件:
|
|
|
+
|
|
|
+```
|
|
|
+locales/
|
|
|
+ ├── common/
|
|
|
+ │ ├── zh_CN.js
|
|
|
+ │ ├── en_US.js
|
|
|
+ │ └── ja_JP.js # 新增日文
|
|
|
+ └── pages/
|
|
|
+ └── home/
|
|
|
+ ├── zh_CN.js
|
|
|
+ ├── en_US.js
|
|
|
+ └── ja_JP.js # 新增日文
|
|
|
+```
|
|
|
+
|
|
|
+### 步骤 2:更新配置
|
|
|
+
|
|
|
+在 `locales/index.js` 中:
|
|
|
+```javascript
|
|
|
+import commonZhCN from './common/zh_CN'
|
|
|
+import commonEnUS from './common/en_US'
|
|
|
+import commonJaJP from './common/ja_JP' // 新增
|
|
|
+
|
|
|
+import homeZhCN from './pages/home/zh_CN'
|
|
|
+import homeEnUS from './pages/home/en_US'
|
|
|
+import homeJaJP from './pages/home/ja_JP' // 新增
|
|
|
+
|
|
|
+export const messages = {
|
|
|
+ 'zh-CN': {
|
|
|
+ common: commonZhCN,
|
|
|
+ home: homeZhCN
|
|
|
+ },
|
|
|
+ 'en-US': {
|
|
|
+ common: commonEnUS,
|
|
|
+ home: homeEnUS
|
|
|
+ },
|
|
|
+ 'ja-JP': { // 新增
|
|
|
+ common: commonJaJP,
|
|
|
+ home: homeJaJP
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export const localeList = [
|
|
|
+ { label: '简体中文', value: 'zh-CN' },
|
|
|
+ { label: 'English', value: 'en-US' },
|
|
|
+ { label: '日本語', value: 'ja-JP' } // 新增
|
|
|
+]
|
|
|
+```
|
|
|
+
|
|
|
+## 💡 最佳实践
|
|
|
+
|
|
|
+### 1. 模块划分原则
|
|
|
+
|
|
|
+- **common/**:通用文本(按钮、消息、错误提示等),所有语言文件都在 `locales/common/` 下
|
|
|
+- **pages/**:页面模块,每个页面一个子目录(如 `pages/home/`、`pages/user/`),每个子目录下包含各语言版本
|
|
|
+- **其他业务模块**:可根据需要创建其他模块目录(如 `api/`、`components/` 等)
|
|
|
+
|
|
|
+**优势**:
|
|
|
+- 同一功能的不同语言翻译在同一目录下,便于对比和维护
|
|
|
+- 添加新语言只需在每个模块目录下添加新的语言文件
|
|
|
+- 模块划分清晰,职责明确
|
|
|
+
|
|
|
+### 2. 命名规范
|
|
|
+
|
|
|
+```javascript
|
|
|
+// ✅ 推荐:清晰的层级结构
|
|
|
+{
|
|
|
+ user: {
|
|
|
+ profile: {
|
|
|
+ title: '个人资料',
|
|
|
+ field: {
|
|
|
+ name: '姓名',
|
|
|
+ email: '邮箱'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ❌ 不推荐:扁平结构
|
|
|
+{
|
|
|
+ userProfileTitle: '个人资料',
|
|
|
+ userProfileFieldName: '姓名'
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 参数化文本
|
|
|
+
|
|
|
+```javascript
|
|
|
+// 定义
|
|
|
+{
|
|
|
+ welcome: '欢迎,{name}!',
|
|
|
+ itemCount: '共 {count} 项'
|
|
|
+}
|
|
|
+
|
|
|
+// 使用
|
|
|
+t('common.welcome', { name: '张三' })
|
|
|
+t('common.itemCount', { count: 10 })
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 保持同步
|
|
|
+
|
|
|
+确保同一模块下所有语言文件的翻译键完全一致:
|
|
|
+```javascript
|
|
|
+// ✅ 正确:locales/pages/user/zh_CN.js 和 locales/pages/user/en_US.js 键名相同
|
|
|
+// zh_CN.js
|
|
|
+{ user: { name: '姓名' } }
|
|
|
+
|
|
|
+// en_US.js
|
|
|
+{ user: { name: 'Name' } }
|
|
|
+
|
|
|
+// ❌ 错误:键名不一致
|
|
|
+// zh_CN.js
|
|
|
+{ user: { name: '姓名' } }
|
|
|
+
|
|
|
+// en_US.js
|
|
|
+{ user: { userName: 'Name' } } // 键名不同!
|
|
|
+```
|
|
|
+
|
|
|
+**提示**:建议同时打开同一模块的不同语言文件进行对比编辑
|
|
|
+
|
|
|
+## 🔧 API 参考
|
|
|
+
|
|
|
+### useLocaleStore
|
|
|
+
|
|
|
+```javascript
|
|
|
+const localeStore = useLocaleStore()
|
|
|
+
|
|
|
+// 状态
|
|
|
+localeStore.currentLocale // 当前语言:'zh-CN' | 'en-US'
|
|
|
+localeStore.availableLocales // 可用语言列表
|
|
|
+
|
|
|
+// 方法
|
|
|
+localeStore.setLocale('en-US') // 切换到指定语言
|
|
|
+localeStore.toggleLocale() // 切换到下一个语言
|
|
|
+localeStore.getCurrentLocaleName() // 获取当前语言显示名称
|
|
|
+```
|
|
|
+
|
|
|
+### useI18n
|
|
|
+
|
|
|
+```javascript
|
|
|
+const { t, locale, te } = useI18n()
|
|
|
+
|
|
|
+t('home.title') // 翻译文本
|
|
|
+t('common.greeting', { name: 'John' }) // 带参数翻译
|
|
|
+locale.value // 当前语言
|
|
|
+te('home.title') // 检查键是否存在
|
|
|
+```
|
|
|
+
|
|
|
+### 工具函数
|
|
|
+
|
|
|
+```javascript
|
|
|
+import { t, getLocale, setLocale, hasKey } from '@/utils/i18n'
|
|
|
+
|
|
|
+t('home.title') // 翻译文本
|
|
|
+getLocale() // 获取当前语言
|
|
|
+setLocale('en-US') // 设置语言
|
|
|
+hasKey('home.title') // 检查键是否存在
|
|
|
+```
|
|
|
+
|
|
|
+## 🐛 常见问题
|
|
|
+
|
|
|
+### 问题 1:翻译不生效
|
|
|
+
|
|
|
+**原因**:翻译键不存在或拼写错误
|
|
|
+
|
|
|
+**解决**:
|
|
|
+1. 检查翻译键是否正确
|
|
|
+2. 确认模块是否正确导入
|
|
|
+3. 使用浏览器开发工具查看警告信息
|
|
|
+
|
|
|
+### 问题 2:语言切换后页面未更新
|
|
|
+
|
|
|
+**原因**:使用了非响应式的方式获取翻译
|
|
|
+
|
|
|
+**解决**:
|
|
|
+```javascript
|
|
|
+// ❌ 错误:在 setup 外部获取
|
|
|
+const title = t('home.title')
|
|
|
+
|
|
|
+// ✅ 正确:在模板中使用或使用 computed
|
|
|
+{{ t('home.title') }}
|
|
|
+// 或
|
|
|
+const title = computed(() => t('home.title'))
|
|
|
+```
|
|
|
+
|
|
|
+### 问题 3:小程序环境报错
|
|
|
+
|
|
|
+**原因**:i18n 配置不兼容
|
|
|
+
|
|
|
+**解决**:确保使用以下配置
|
|
|
+```javascript
|
|
|
+createI18n({
|
|
|
+ legacy: false, // 必须:使用 Composition API
|
|
|
+ globalInjection: true, // 必须:全局注入
|
|
|
+ // ...
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## 📚 相关文档
|
|
|
+
|
|
|
+- [i18n 使用指南](./i18n/README.md)
|
|
|
+- [语言包管理](./locales/README.md)
|
|
|
+- [目录结构说明](./locales/STRUCTURE.md)
|
|
|
+- [组件国际化指南](./locales/COMPONENT_I18N.md)
|
|
|
+- [Vue I18n 官方文档](https://vue-i18n.intlify.dev/)
|
|
|
+
|
|
|
+## 🎯 TODO
|
|
|
+
|
|
|
+- [ ] 添加更多语言支持(日语、韩语等)
|
|
|
+- [ ] 实现语言包懒加载优化
|
|
|
+- [ ] 添加翻译缺失检测工具
|
|
|
+- [ ] 集成在线翻译服务
|
|
|
+
|
|
|
+## 📞 联系方式
|
|
|
+
|
|
|
+如有问题或建议,请联系项目维护者。
|