--- name: dy-skill-i18n description: 处理前端国际化翻译工作。当用户提到需要做国际化、i18n、翻译、多语言支持时使用此 skill。主要功能:1) 识别代码中的硬编码静态文字;2) 判断是否应使用现有公共翻译或需要新增;3) 将翻译添加到对应的语言文件中;4) 将硬编码替换为国际化调用;5) 检查翻译完整性和正确性。 --- # 国际化翻译 Skill ## 目录 - [核心原则](#核心原则) - [工作流程](#工作流程) - [常见问题处理](#常见问题处理) - [翻译准确性要求](#翻译准确性要求) - [注意事项](#注意事项) - [验证与错误处理](#验证与错误处理) --- ## 概述 此 skill 用于处理前端项目的国际化翻译工作。当你需要将代码中的硬编码中文(或英文)文字转换为国际化支持时使用。 **前提**:以实际项目结构为准,不破坏现有项目规则。 --- ## 核心原则 1. **以实际项目结构为准** - 不假设固定目录结构,根据项目现有配置灵活调整 2. **配置放对应位置** - 公共翻译放公共目录,模块翻译放模块目录,不混淆 3. **优先复用现有翻译** - 已有相同含义的翻译时直接使用,不要重复添加 4. **只翻译静态文字** - 不翻译后端接口返回的数据、字典/枚举中的内容 5. **不破坏现有规则** - 所有修改基于项目现有规则,不改变现有结构 --- ## 工作流程 ### Step 1: 了解项目结构 首先探索项目的国际化配置: 1. 查找语言文件目录(常见名称:lang, locales, i18n, language, messages) 2. 确认目录结构模式: - **有模块区分**:是否存在 common/, module/, 或按模块名划分的子目录 - **无模块区分**:所有翻译是否都在一个或少数几个文件中 3. 确认文件命名规范(如 zh_CN.ts, zh-CN.ts, en.ts, en_US.ts 等) 4. 确认国际化调用方式(如 $t(), t(), useI18n() 等) 5. 确认支持的语言种类(是否只有中英文,还是支持更多语言) 6. 确认是否使用了 vue-i18n 的特殊功能(复数、插值等) ### Step 2: 识别需要翻译的内容 **✅ 需要翻译**: - 静态显示的中文/英文字符串 - 按钮文字、提示信息、表单标签 - 表格列标题、对话框标题 - 占位符文字、选项文字 **❌ 不需要翻译**: - 从后端 API 返回的数据 - 字典/枚举中获取的内容 - 变量和动态计算的值 - 数字、日期格式(需要使用专门的格式化方法) - 技术性错误信息(后端返回的 error message) ### Step 3: 判断翻译放哪里 根据项目实际结构判断翻译应该添加到哪里: #### 情况A: 项目有模块区分 ``` lang/ ├── common/ # 公共翻译 │ ├── zh.ts │ └── en.ts ├── module/ # 模块翻译 │ ├── product/ │ ├── order/ │ └── ... └── index.ts ``` **决策规则**: - 如果是**通用性质**的翻译(如:新增、编辑、删除、搜索、重置、确定、取消、请输入、请选择等)→ 放 `common/` - 如果是**特定业务模块**的翻译(如:产品名称、订单状态,品牌分类等)→ 放对应模块目录 #### 情况B: 项目无模块区分 ``` lang/ ├── zh_CN.ts ├── en_US.ts └── index.ts ``` **决策规则**: - 所有翻译都直接添加到对应的语言文件中 - 使用有前缀的 key 区分不同模块,如 `product.*`, `order.*`, `common.*` #### 情况C: 其他结构 根据项目实际结构灵活处理: - 可能存在多个语言文件(按语言分、按模块分、混合分) - 可能使用 JSON 格式或 TS 格式 - 总之**遵循项目现有模式,不打破现有结构** ### Step 4: 添加翻译 1. **检查现有翻译** - 先搜索是否已有相同含义的翻译,有则复用 2. **新增翻译 key** - 如果没有,添加新的翻译 3. **确保所有支持的语言一致** - 添加时同步添加所有支持的语言,保持 key 路径一致 **添加位置判断**: ``` IF 项目有 common/ 或类似的公共目录 THEN IF 翻译是通用性质的 THEN 添加到公共目录 ELSE 添加到对应模块目录 ELSE 添加到主语言文件中,使用模块前缀区分 ``` ### Step 5: 替换硬编码 根据项目实际的调用方式替换。常见使用方式如下: ```vue {{ $t("key.path") }} ``` ### Step 6: 检查验证 1. **完整性检查**: - 所有支持的语言翻译都已添加 - key 路径在所有语言文件中一致 2. **正确性检查**: - 翻译 key 正确 - 页面显示正常 3. **遗漏检查**: - 扫描文件确认没有遗漏的硬编码 - 检查相似场景是否需要同样处理 --- ## 常见问题处理 ### Q1: 如何判断是公共翻译还是模块翻译? ``` 通用性质 = 任何模块都可能用到 - 操作类:新增、编辑、删除、查看、导入、导出、提交、审核 - 提示类:确定、取消、关闭,保存、成功、失败 - 占位符类:请输入、请选择、开始日期、结束日期 - 表格类:序号、操作、状态 模块特有 = 只有特定模块使用 - 产品名称、产品编码、产品分类 - 订单号、订单状态 - 客户名称、客户电话 ``` ### Q2: 项目没有模块目录怎么办 直接添加到主语言文件中,使用模块前缀区分: ```typescript // zh_CN.ts export default { common: { action: { add: "新增", edit: "编辑" }, }, product: { name: "产品名称", code: "产品编码", }, order: { no: "订单号", status: "订单状态", }, }; ``` ### Q3: 已有公共翻译但想保持模块独立性 如果业务确实需要独立管理(如不同模块由不同人维护),可以在模块目录中重复定义,但建议优先复用公共翻译。 ### Q4: 如何处理动态参数/插值 如果翻译中需要动态参数(如用户名、数量、时间等): 1. **在 key 中使用占位符**: ```typescript // zh_CN.ts export default { deleteSuccess: "删除成功,共 {count} 条记录", welcome: "欢迎 {username} 登录系统", selectedCount: "已选择 {n} 项", }; ``` 2. **在组件中传递参数**: ```vue {{ $t("deleteSuccess", { count: deletedCount }) }} ``` 3. **注意事项**: - 遵循项目现有的插值语法(占位符格式可能不同,如 `{count}` 或 `%{count}`) - 占位符命名应简洁明了 - 确保所有语言中占位符名称一致 ### Q5: 如何处理复数形式 如果项目使用 vue-i18n 的复数功能: ```typescript // zh_CN.ts(中文通常不需要复数变化,使用相同形式) export default { itemCount: "{n} 个项目 | {n} 个项目", }; // en_US.ts export default { itemCount: "{n} item | {n} items", }; ``` 使用方式: ```vue {{ $t("itemCount", { n: count }, count) }} ``` vue-i18n 会根据 count 的值自动选择单数或复数形式。 **注意**:如果项目没有使用复数功能,将复数和单数分别定义为不同的 key,如 `itemCount` 和 `itemCount_plural`。 ### Q6: 如何处理日期/数字/货币格式化 日期、数字、货币通常需要专门的格式化方法,**不要**使用简单的翻译: 1. **使用项目现有的格式化方法**: - 查找项目中是否有现成的格式化工具 - 如使用 `dayjs`, `Intl.NumberFormat` 等 2. **如果确实需要翻译日期格式**: ```typescript // 仅翻译格式说明文字,不翻译实际日期 dateFormat: { year: '年', month: '月', day: '日' } ``` 3. **数字和货币**: ```typescript // 建议使用专门的格式化,不走翻译 // 如:Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }) ``` ### Q7: 如何处理 UI 框架组件的国际化 对于 Element Plus、Ant Design 等 UI 框架的组件: 1. **遵循项目配置** - 查看项目是否已经全局配置了框架的 i18n 2. **组件自带属性** - 很多组件有内置的 i18n 属性(如 `empty-text`, `confirm-btn-text` 等) 3. **使用项目配置** - 如果项目有全局的组件文案配置,优先使用 ```vue ``` ### Q8: 如何处理后端返回的错误信息 1. **如果后端返回的是国际化 key** - 直接使用,无需翻译 2. **如果后端返回原始错误信息** - 建议: - 在前端建立错误码映射表 - 或让后端支持国际化 key 返回 3. **如果是业务性质的提示** - 可以翻译: ```typescript // 错误码映射 error: { 1001: '用户名不存在', 1002: '密码错误', 1003: '账号已被锁定' } ``` ### Q9: 项目需要支持多种语言怎么办 1. **确认支持的语言种类** - 查看项目现有语言文件 2. **所有语言同步添加** - 新增翻译时,必须同时添加所有支持的语言 3. **遵循语言代码规范** - 使用项目现有的语言代码格式(如 zh-CN vs zh_CN) ### Q10: 翻译 key 冲突怎么办 1. **检查现有 key** - 确认是否真的冲突 2. **使用更具体的路径** - 添加模块前缀区分 3. **与项目成员协商** - 如果是公共 key 的修改,需沟通 ### Q11: 如何处理部分国际化的遗留代码 项目中可能存在部分已国际化但风格不一致的代码: 1. **保持现有风格** - 不强制统一,避免大规模改动 2. **新添加的遵循规范** - 新翻译使用规范写法 3. **必要时可重构** - 如果发现明显问题,可提出建议 ### Q12: 旧翻译 key 废弃怎么办 1. **保留旧翻译** - 暂时保留,避免线上报错 2. **标记废弃** - 添加注释说明已废弃 3. **后续清理** - 定期清理未使用的废弃翻译 ### Q13: 如何处理 slot 中的文字 对于 scoped slot 中的静态文字: ```vue ``` ### Q14: script 中如何使用翻译 ```vue ``` ### Q15: v-html 和 $t 结合使用需要注意什么 **谨慎使用** `v-html`: ```vue {{ $t('message.prefix') }}{{ $t('message.link') }} ``` 如果必须使用 `v-html`,确保内容来自可信来源。 ### Q16: 函数式组件中如何使用翻译 对于使用 render 函数或 JSX 的组件: ```typescript // 使用 this.$t(需要确保组件可访问到 i18n 实例) export default { render() { return h("span", this.$t("key.path")); }, }; // 或者通过 provide/inject 传递翻译函数 // 父组件 const { t } = useI18n(); provide("i18n", { t }); // 子组件 const { t } = inject("i18n"); return h("span", t("key.path")); ``` ### Q17: keep-alive 缓存组件翻译切换问题 使用 keep-alive 缓存的组件在切换语言后可能不会重新渲染: 1. **监听语言变化** - 在 activated 生命周期中强制刷新 ```vue ``` 2. **使用 key 变化** - 为 keep-alive 组件添加 key ```vue ``` ### Q18: 异步组件的翻译加载 异步组件的翻译需要在主应用或单独加载: 1. **如果项目使用全局翻译** - 异步组件会自动继承 2. **如果需要单独加载** - 使用 vue-i18n 的懒加载功能 ```typescript // 懒加载翻译 const messages = { en: () => import("./locales/en.json"), zh: () => import("./locales/zh.json"), }; ``` --- ## 翻译准确性要求 作为经验丰富的翻译专家,你需要遵循以下严格要求: ### 1. 理解上下文语境 翻译前必须理解文字的使用场景: | 场景 | 示例 | 翻译注意事项 | | ---------- | ---------------------------- | -------------------- | | 按钮文字 | "提交"、"确认"、"取消" | 简洁有力,通常用动词 | | 表单标签 | "产品名称"、"创建时间" | 名词短语,明确指示 | | 占位符 | "请输入名称"、"请选择日期" | 引导性语句 | | 提示信息 | "操作成功"、"保存失败" | 结果导向,说明状态 | | 对话框标题 | "新增产品"、"编辑品牌" | 动作 + 对象 | | 表格列 | "状态"、"创建人"、"更新时间" | 简洁名词 | ### 2. 根据场景选择准确翻译 同一个中文词在不同场景可能有不同译法: ``` 示例:中文 "状态" ├── 表格列标题 → "Status" ├── 业务流程中 → "State" 或 "Process Status" ├── 设备状态 → "Device Status" └── 订单状态 → "Order Status" 示例:中文 "确认" ├── 按钮文字 → "Confirm" 或 "Submit" ├── 二次确认提示 → "Are you sure?" └── 确认框标题 → "Confirmation" 示例:中文 "查看" ├── 表格操作列 → "View" ├── 查看详情 → "Details" ├── 查看记录 → "View Record" └── 查看图片 → "Preview" ``` ### 3. 保持翻译一致性 - **相同含义 → 相同翻译**:整个项目中,相同含义的文字必须使用相同的翻译 - **相同场景 → 相同模式**:类似场景使用类似的翻译结构和用词 - **建立术语表**:对于专业术语,建立统一的翻译标准 ``` ✅ 正确:所有"产品名称"都翻译为 "Product Name" ❌ 错误:有时翻译为 "Product Name",有时翻译为 "Name" ``` ### 4. 专业术语处理 - **行业标准术语**:使用公认的英文术语 - **产品特定术语**:保持与产品文档一致 - **缩写和缩写词**:如需使用缩写,应在首次出现时提供全称 ``` 示例: - SKU → Stock Keeping Unit(库存单位) - MDM → Master Data Management(主数据管理) - CRM → Customer Relationship Management(客户关系管理) ``` ### 5. key 命名规范 遵循项目的命名规范,项目没有特殊规定时参考以下原则: ``` 命名原则: - 使用小写字母 - 使用点分隔层级 - 保持简洁但有意义 - 避免缩写(除非是公认的缩写) 层级结构建议: - 动作相关:{模块}.action.{具体动作} product.action.add, product.action.edit, product.action.delete - 字段相关:{模块}.{实体}.{字段名} product.product.name, product.product.code - 提示相关:{模块}.message.{类型} product.message.success, product.message.error - 占位符:common.placeholder.{类型} common.placeholder.input, common.placeholder.select 公共部分:common.{类型}.{具体项} common.action.add, common.action.edit common.table.index, common.table.action common.message.success, common.message.error ``` ### 6. 长度和空间考虑 - 英文翻译通常比中文短,但也要考虑UI空间 - 避免过长的翻译导致布局问题 - 必要时可以使用更简洁的表达 ### 7. 复数和单数 - 注意英文的单复数形式 - 根据实际场景选择单复数形式 - 如果项目使用 vue-i18n 复数功能,按规范使用 ### 8. 大小写规范 - 按钮文字:首字母大写(Save, Cancel, Confirm) - 表格列标题:首字母大写(Product Name, Status) - 占位符文字:首字母小写(please enter, please select) - 标题和标签:首字母大写 - **遵循项目现有规范** ### 9. 标点符号 - 英文使用英文标点(, . 而不是 ,) - 但按钮文字、标签等通常不加句号 - 提示信息根据语气决定是否加句号 --- ## 翻译决策流程 当遇到翻译时,按以下流程决策: ``` 1. 理解文字含义和用途 ↓ 2. 查看项目现有翻译库 ├── 已有相同翻译?→ 直接复用 └── 没有?→ 继续 ↓ 3. 分析使用场景 ├── 什么类型的UI元素? ├── 在什么上下文中使用? └── 用户期望什么语气? ↓ 4. 选择最准确的翻译 ↓ 5. 判断翻译放哪里 ├── 通用性质?→ 公共目录 └── 模块特有?→ 模块目录 ↓ 6. 检查一致性 ├── 是否与现有术语冲突? └── 是否需要更新术语表? ``` --- ## 注意事项 1. **不修改项目结构** - 只在现有结构中添加内容,不创建新目录(除非项目本身就需要) 2. **保持风格一致** - 使用项目现有的命名风格(camelCase, kebab-case, SCREAMING_SNAKE_CASE 等) 3. **验证替换结果** - 修改后测试页面显示,确保没有破坏现有功能 4. **公共翻译不放模块** - 通用性质的翻译不要放到模块目录中 5. **模块翻译不放公共** - 特定业务模块的翻译不要放到公共目录中 6. **所有语言同步** - 项目支持的所有语言都要同步更新 7. **不破坏现有** - 所有修改基于现有规则,不改变现有结构 --- ## 验证与错误处理 ### 验证翻译质量 修改完成后,必须验证: 1. **语义准确性**:翻译是否准确表达原意? 2. **场景合适性**:在当前场景下是否自然? 3. **一致性检查**:类似文字是否使用类似翻译? 4. **拼写和语法**:英文翻译是否有拼写错误或语法问题? 5. **UI适配性**:翻译后是否超出UI空间? ### 验证方法 1. **运行时检查**: - 切换语言测试页面显示 - 检查控制台是否有 missing translation 警告 2. **代码检查**: - 搜索是否还有遗漏的硬编码 - 确认所有 key 都已正确添加 3. **如果项目有 lint 工具**:按项目规范执行 ### 错误处理 1. **翻译错误**: - 立即修正错误翻译 - 检查是否影响其他使用该翻译的地方 2. **遗漏翻译**: - 补充遗漏的翻译 - 检查是否还有其他遗漏 3. **格式问题**: - 保持与项目现有格式一致 - 使用项目的格式化工具(如果有) 4. **如果出现问题**: - 使用 git 回滚到修改前 - 检查问题原因后重新修改