多语言资源的添加流程及实现原理.md 9.9 KB

多语言资源的添加流程及实现原理

概述

本项目采用 React-Intl 库实现国际化(i18n)支持,通过 Redux 状态管理维护多语言状态。本文档详细介绍多语言资源的添加流程、技术实现原理以及相关开发规范。

技术架构

核心技术栈

  • React-Intl v7.1.11: React 国际化库
  • Redux Toolkit: 状态管理
  • Ant Design: UI 组件库(内置国际化支持)
  • Taro: 跨平台开发框架

核心组件

  1. IntlProvider: React-Intl 上下文提供者
  2. i18nSlice: Redux 状态管理切片
  3. 语言切换组件: LanguageSettingModal
  4. 转换脚本: extract-i18n-json.js

语言资源文件结构

src/assets/i18n/messages/
├── zh.js    # 中文语言资源
└── en.js    # 英文语言资源

文件格式

每个语言文件都是标准的 ES6 模块:

export default {
  "greeting": "你好,世界!",
  "login.username": "用户名",
  "login.username.placeholder": "请输入用户名",
  // ... 更多翻译项
};

添加多语言资源的完整流程

步骤1:代码开发阶段

在组件中定义翻译键,并提供默认消息:

import { FormattedMessage, useIntl } from 'react-intl';

// 方法1:使用 FormattedMessage 组件
<FormattedMessage
  id="newFeature.title"
  defaultMessage="新功能标题"
/>

// 方法2:使用 useIntl hook
const intl = useIntl();
const title = intl.formatMessage({
  id: 'newFeature.title',
  defaultMessage: '新功能标题'
});

步骤2:添加翻译资源

2.1 在中文文件中添加翻译

// src/assets/i18n/messages/zh.js
export default {
  // ... 现有翻译
  "newFeature.title": "新功能标题",
  "newFeature.description": "这是新功能的详细描述",
};

2.2 在英文文件中添加对应翻译

// src/assets/i18n/messages/en.js
export default {
  // ... 现有翻译
  "newFeature.title": "New Feature Title",
  "newFeature.description": "This is the detailed description of the new feature",
};

步骤3:转换并部署

3.1 执行转换脚本

node scripts/extract-i18n-json.js

脚本执行流程:

  1. 读取所有语言文件 (zh.js, en.js)
  2. 移除 export default 语法和结尾分号
  3. 转换为纯 JSON 格式
  4. 输出到 scripts/output/i18n/ 目录

转换后的文件格式:

{
  "greeting": "你好,世界!",
  "login.username": "用户名",
  "newFeature.title": "新功能标题"
}

3.2 上传到服务器

脚本执行后会自动询问服务器配置:

📤 SCP配置 (按Enter使用默认值):
IP地址 (默认: 192.168.110.245):
用户名 (默认: root):
中文文件路径 (默认: /root/gydr/trans/zh_CN/zh.js):
英文文件路径 (默认: /root/gydr/trans/en_US/en.js):

确认配置后自动通过 SCP 上传:

scp zh.js root@192.168.110.245:/root/gydr/trans/zh_CN/zh.js
scp en.js root@192.168.110.245:/root/gydr/trans/en_US/en.js

实现原理

1. React-Intl 集成原理

1.1 应用入口配置

// src/app.tsx
import { IntlProvider } from 'react-intl';

<IntlProvider
  locale={currentLocale ? currentLocale.split('_')[0] : 'en'}
  messages={messages || {}}
>
  {/* 应用内容 */}
</IntlProvider>

1.2 状态管理架构

// src/states/i18nSlice.ts
interface I18nState {
  messages: I18nMessages;           // 当前语言的翻译字典
  currentLocale: string;            // 当前语言代码 (en_US/zh_CN)
  supportedLocales: string[];       // 支持的语言列表
  availableLanguages: LanguageItem[]; // 后端返回的语言选项
  loading: boolean;                 // 加载状态
  error: string | null;            // 错误信息
}

2. 语言切换流程

2.1 用户操作流程

  1. 点击 SystemZone 中的"语言管理"按钮
  2. 弹出 LanguageSettingModal 对话框
  3. 自动加载可用语言列表
  4. 用户选择目标语言
  5. 调用后端 API 更新系统语言
  6. Redux store 更新当前语言
  7. 应用重新渲染显示新语言

2.2 API 接口

// 获取语言列表
GET /dr/api/v1/pub/language

// 更新系统语言
POST /api/v1/auth/manage/language
{
  "lang": "zh_CN.UTF-8"  // 或 "en_US.UTF-8"
}

3. 转换脚本实现原理

3.1 核心转换逻辑

function extractJsonFromJs(filePath) {
  const content = fs.readFileSync(filePath, 'utf-8');

  // 移除 export default 语句
  let jsonString = content
    .replace(/export\s+default\s+/g, '')
    .trim();

  // 移除末尾分号
  if (jsonString.endsWith(';')) {
    jsonString = jsonString.slice(0, -1);
  }

  // 安全解析 JSON
  const jsonObj = eval('(' + jsonString + ')');
  return jsonObj;
}

3.2 自动化部署流程

脚本集成了完整的部署流程:

  1. 文件转换 (JS → JSON)
  2. 配置询问 (服务器信息)
  3. SCP 上传 (自动传输)
  4. 结果反馈 (成功/失败状态)

翻译键命名规范

命名规则

采用点号分隔的多级命名结构,产品相关命名放在第一级:

[产品.]模块.子模块.元素[.状态]

产品层级命名

根据产品类型在第一级添加产品标识符:

宠物产品 (VETDROS)

  • 第一级使用 animal. 前缀
  • 适用于宠物诊疗相关功能

人医产品 (DROS)

  • 无产品前缀,直接从模块开始
  • 适用于人类医疗相关功能

实际示例

宠物产品示例

  • animal.login.username - 宠物产品登录模块用户名
  • animal.register.patientId - 宠物注册模块宠物编号
  • animal.register.patientName.placeholder - 宠物注册模块宠物昵称占位符
  • animal.exam.action.resetParams - 宠物检查模块重置参数动作

人医产品示例

  • login.username - 登录模块用户名
  • register.patientId - 注册模块患者编号
  • register.patientName.placeholder - 注册模块患者姓名占位符
  • exam.action.resetParams - 检查模块重置参数动作

语义化分类

通用模块

  • login.* - 登录相关
  • register.* - 注册相关
  • exam.* - 检查相关
  • worklist.* - 工作清单相关
  • output.* - 输出相关
  • actionPanel.* - 操作面板相关

宠物专用模块

  • animal.* - 宠物相关功能
  • animal.register.* - 宠物注册
  • animal.worklist.* - 宠物工作清单
  • animal.actionPanel.* - 宠物操作面板

功能状态后缀

  • .placeholder - 输入框占位符
  • .required - 必填验证消息
  • .success - 成功提示
  • .failed - 失败提示
  • .loading - 加载状态
  • .empty - 空状态
  • .error - 错误状态

命名原则

  1. 产品优先: 宠物产品必须使用 animal. 前缀,人医产品直接从模块开始
  2. 模块清晰: 使用具有语义的英文单词作为模块名
  3. 层次分明: 通过点号建立清晰的层次结构
  4. 状态明确: 对于不同状态的相同元素,使用状态后缀区分
  5. 一致性: 相同功能在不同产品中保持相似的命名结构

高级功能

1. 参数化翻译

// 消息文件
"welcome.user": "欢迎,{name}!"

// 使用方式
<FormattedMessage
  id="welcome.user"
  values={{ name: userName }}
/>

2. 复数处理

// 消息文件
"item.count": "有 {count, plural, =0 {没有项目} one {1 个项目} other {# 个项目}}"

// 使用方式
<FormattedMessage
  id="item.count"
  values={{ count: itemCount }}
/>

3. 日期和数字格式化

const intl = useIntl();

// 日期格式化
const formattedDate = intl.formatDate(date, {
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

// 数字格式化
const formattedNumber = intl.formatNumber(value, {
  style: 'currency',
  currency: 'CNY'
});

最佳实践

开发规范

  1. 默认消息: 始终提供 defaultMessage 作为降级
  2. 键唯一性: 确保翻译键在所有语言文件中唯一
  3. 一致性: 中英文翻译键必须完全一致
  4. 模块化: 按功能模块组织翻译键

部署规范

  1. 环境隔离: 不同环境使用不同服务器配置
  2. 备份策略: 上传前备份现有翻译文件
  3. 回滚计划: 准备翻译文件回滚方案
  4. 测试验证: 部署后验证多语言切换功能

常见问题及解决方案

1. 翻译不显示

现象: 界面显示翻译键而非翻译文本 原因: 翻译键不存在或语言文件未正确加载 解决:

  • 检查翻译键拼写是否正确
  • 验证所有语言文件是否包含该键
  • 确认语言切换是否生效

2. IntlProvider 错误

现象: "Could not find required intl object" 原因: 组件渲染时 IntlProvider 还未挂载 解决: 确保 IntlProvider 始终存在,提供默认值

3. 转换脚本失败

现象: 脚本执行报错 原因: Node.js 环境问题或文件权限问题 解决:

  • 检查 Node.js 版本
  • 验证文件路径和权限
  • 查看控制台错误信息

4. 上传失败

现象: SCP 上传失败 原因: 网络连接或服务器配置问题 解决:

  • 检查网络连接
  • 验证服务器地址和端口
  • 确认 SSH 密钥或密码正确

扩展方向

1. 自动化改进

  • 集成 CI/CD 流水线自动转换和上传
  • 添加翻译键重复检查
  • 实现翻译完成度统计

2. 开发体验优化

  • VS Code 插件支持翻译键提示
  • 翻译键提取工具自动化生成
  • 实时翻译预览功能

3. 翻译管理平台

  • 集成专业翻译管理工具
  • 支持翻译记忆库
  • 多版本翻译管理

总结

本项目的多语言实现方案提供了完整的开发到部署流程:

  1. 开发阶段: 定义翻译键并添加默认消息
  2. 翻译阶段: 在语言文件中添加对应翻译
  3. 部署阶段: 执行转换脚本并上传到服务器

通过标准化的流程和自动化工具,确保了多语言功能的开发效率和维护质量。开发者可以专注于业务功能开发,而翻译部署工作可以通过规范化的脚本完成。