I18N_GUIDE.md 11 KB

国际化完整指南

📦 已完成的功能

✅ 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. 在页面中使用国际化

<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. 在组件中使用国际化

<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. 使用语言切换组件

<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 中使用(非组件环境)

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.jsen_US.js
  2. locales/index.js 中注册到 components
  3. 在组件中使用:t('components.userCard.title')

详细指南:请查看 组件国际化指南

📝 添加新的翻译模块

页面模块示例

在对应目录下创建语言文件。例如创建产品管理页面模块:

创建 locales/pages/product/zh_CN.js

export default {
  title: '产品管理',
  list: {
    title: '产品列表',
    empty: '暂无产品'
  },
  detail: {
    name: '产品名称',
    price: '价格',
    stock: '库存'
  },
  action: {
    add: '添加产品',
    edit: '编辑',
    delete: '删除'
  }
}

创建 locales/pages/product/en_US.js

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 中导入新模块:

// 导入通用模块
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:使用新模块

<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 中:

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. 命名规范

// ✅ 推荐:清晰的层级结构
{
  user: {
    profile: {
      title: '个人资料',
      field: {
        name: '姓名',
        email: '邮箱'
      }
    }
  }
}

// ❌ 不推荐:扁平结构
{
  userProfileTitle: '个人资料',
  userProfileFieldName: '姓名'
}

3. 参数化文本

// 定义
{
  welcome: '欢迎,{name}!',
  itemCount: '共 {count} 项'
}

// 使用
t('common.welcome', { name: '张三' })
t('common.itemCount', { count: 10 })

4. 保持同步

确保同一模块下所有语言文件的翻译键完全一致:

// ✅ 正确: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

const localeStore = useLocaleStore()

// 状态
localeStore.currentLocale        // 当前语言:'zh-CN' | 'en-US'
localeStore.availableLocales     // 可用语言列表

// 方法
localeStore.setLocale('en-US')   // 切换到指定语言
localeStore.toggleLocale()       // 切换到下一个语言
localeStore.getCurrentLocaleName() // 获取当前语言显示名称

useI18n

const { t, locale, te } = useI18n()

t('home.title')                  // 翻译文本
t('common.greeting', { name: 'John' }) // 带参数翻译
locale.value                     // 当前语言
te('home.title')                 // 检查键是否存在

工具函数

import { t, getLocale, setLocale, hasKey } from '@/utils/i18n'

t('home.title')                  // 翻译文本
getLocale()                      // 获取当前语言
setLocale('en-US')              // 设置语言
hasKey('home.title')            // 检查键是否存在

🐛 常见问题

问题 1:翻译不生效

原因:翻译键不存在或拼写错误

解决

  1. 检查翻译键是否正确
  2. 确认模块是否正确导入
  3. 使用浏览器开发工具查看警告信息

问题 2:语言切换后页面未更新

原因:使用了非响应式的方式获取翻译

解决

// ❌ 错误:在 setup 外部获取
const title = t('home.title')

// ✅ 正确:在模板中使用或使用 computed
{{ t('home.title') }}
// 或
const title = computed(() => t('home.title'))

问题 3:小程序环境报错

原因:i18n 配置不兼容

解决:确保使用以下配置

createI18n({
  legacy: false,          // 必须:使用 Composition API
  globalInjection: true,  // 必须:全局注入
  // ...
})

📚 相关文档

🎯 TODO

  • 添加更多语言支持(日语、韩语等)
  • 实现语言包懒加载优化
  • 添加翻译缺失检测工具
  • 集成在线翻译服务

📞 联系方式

如有问题或建议,请联系项目维护者。