# Dy Skill I18N

> 处理前端国际化翻译工作。当用户提到需要做国际化、i18n、翻译、多语言支持时使用此 skill。主要功能：1) 识别代码中的硬编码静态文字；2) 判断是否应使用现有公共翻译或需要新增；3) 将翻译添加到对应的语言文件中；4) 将硬编码替换为国际化调用；5) 检查翻译完整性和正确性。

- Skill: `leoyeai-openclaw-master-skills/dy-skill-i18n` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add leoyeai-openclaw-master-skills/dy-skill-i18n`
- Raw SKILL.md: https://api.skillmd.com/api/skills/leoyeai-openclaw-master-skills/dy-skill-i18n/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: LeoYeAI (https://skillmd.com/u/leoyeai-openclaw-master-skills)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/leoyeai-openclaw-master-skills/dy-skill-i18n

---


# 国际化翻译 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
<!-- Template 中使用 $t -->
{{ $t("key.path") }}

<!-- 在 script 中使用 -->
<script setup>
const { t } = useI18n();
const text = t("key.path");
</script>

<!-- 属性绑定 -->
<el-input :placeholder="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 }) }}

   <!-- 在 script 中 -->
   <script setup>
   const { t } = useI18n();
   const message = t("deleteSuccess", { count: deletedCount });
   </script>
   ```

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
<!-- Element Plus 示例 -->
<el-table :data="list" :empty-text="$t('common.table.empty')">
</el-table>
```

### 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
<!-- 转换前 -->
<template #default="{ row }">
  <span>产品名称：{{ row.name }}</span>
</template>

<!-- 转换后 -->
<template #default="{ row }">
  <span>{{ $t("product.name") }}：{{ row.name }}</span>
</template>
```

### Q14: script 中如何使用翻译

```vue
<script setup>
// useI18n 通常由项目自动导入，无需手动 import
// 如项目无自动导入，则需要：import { useI18n } from 'vue-i18n'

const { t } = useI18n();

// 在方法中使用
function handleClick() {
  const message = t("common.message.success");
  ElMessage.success(message);
}

// 在计算属性中使用
const statusText = computed(() => {
  return t(`product.status.${status.value}`);
});
</script>
```

### Q15: v-html 和 $t 结合使用需要注意什么

**谨慎使用** `v-html`：

```vue
<!-- 不推荐：可能有 XSS 风险 -->
<span v-html="$t('message.withHtml')"></span>

<!-- 推荐：分开处理 -->
<span>{{ $t('message.prefix') }}<a :href="url">{{ $t('message.link') }}</a></span>
```

如果必须使用 `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
<script setup>
import { watch } from "vue";
import { useI18n } from "vue-i18n";

const { locale } = useI18n();

// 监听语言变化，强制刷新
watch(locale, () => {
  // 强制组件重新渲染
  refreshData();
});
</script>
```

2. **使用 key 变化** - 为 keep-alive 组件添加 key

```vue
<keep-alive>
  <component :is="component" :key="locale" />
</keep-alive>
```

### 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 回滚到修改前
   - 检查问题原因后重新修改

