# BPMN.js 监听器标签翻译问题分析

## 问题描述

用户反馈：`Start: Delegate expression`、`Start: Java class` 等监听器标签没有被翻译成中文。

## 根本原因

通过分析 `bpmn-js-properties-panel` 源码（`index.esm.js:17670`），发现标签是**动态生成**的：

```javascript
function getListenerLabel(listener, translate = value => value) {
  const event = listener.get('event');
  const implementationType = getListenerType(listener);
  return `${translate(EVENT_TO_LABEL[event])}: ${translate(IMPLEMENTATION_TYPE_TO_LABEL[implementationType])}`;
}
```

### 常量定义

```javascript
const EVENT_TO_LABEL = {
  start: 'Start',        // 注意：大写 S
  end: 'End',
  take: 'Take',
  create: 'Create',
  assignment: 'Assignment',
  complete: 'Complete',
  delete: 'Delete',
  update: 'Update',
  timeout: 'Timeout'
};

const IMPLEMENTATION_TYPE_TO_LABEL = {
  class: 'Java class',              // 注意：有空格
  expression: 'Expression',
  delegateExpression: 'Delegate expression',  // 注意：小写 e
  script: 'Script'
};
```

## 翻译机制

bpmn.js 的翻译是**分步进行**的：

1. **第一步**：翻译事件类型 `translate('Start')` → `'开始'`
2. **第二步**：翻译实现类型 `translate('Java class')` → `'Java类'`
3. **第三步**：用 `': '` 连接 → `'开始: Java类'`

**关键点**：bpmn.js **不会**翻译完整的组合字符串 `'Start: Java class'`，而是分别翻译两部分！

## 解决方案

### ✅ 正确做法

在 `zh-CN.ts` 中添加**基础翻译**（单独的部分）：

```typescript
export const translations: Record<string, string> = {
  // 事件类型（大写 - 用于标签生成）
  'Start': '开始',
  'End': '结束',
  'Take': '执行',
  'Create': '创建',
  'Assignment': '分配',
  'Complete': '完成',
  'Delete': '删除',
  'Update': '更新',
  'Timeout': '超时',
  
  // 实现类型（注意空格和大小写）
  'Java class': 'Java类',
  'Expression': '表达式',
  'Delegate expression': '委托表达式',
  'Script': '脚本',
  
  // 完整组合（作为备用，但实际不会被使用）
  'Start: Java class': '开始：Java类',
  'Start: Delegate expression': '开始：委托表达式',
  // ... 其他组合
};
```

### ❌ 常见错误

1. **只添加组合字符串**：
   ```typescript
   'Start: Java class': '开始：Java类',  // ❌ 无效，bpmn.js 不会查询这个
   ```

2. **大小写不匹配**：
   ```typescript
   'start': '开始',  // ❌ 无效，bpmn.js 使用 'Start'（大写）
   'Delegate Expression': '委托表达式',  // ❌ 无效，应该是 'Delegate expression'（小写 e）
   ```

3. **缺少空格**：
   ```typescript
   'Javaclass': 'Java类',  // ❌ 无效，应该是 'Java class'（有空格）
   ```

## 验证方法

### 1. 添加调试日志

在 `customTranslate` 函数中添加：

```typescript
export function customTranslate(template: string, replacements?: Record<string, string>): string {
  replacements = replacements || {};
  
  // 调试：记录未翻译的文本
  if (import.meta.env.DEV && !translations[template] && template.includes(':')) {
    console.log('[翻译缺失]', template);
  }
  
  template = translations[template] || template;
  
  return template.replace(/{([^}]+)}/g, (_, key) => {
    return replacements[key] || `{${key}}`;
  });
}
```

### 2. 测试步骤

1. 启动开发服务器：`pnpm run dev:antd`
2. 打开流程设计页面：`http://localhost:5666/workflow/process-design`
3. 创建一个任务节点
4. 在属性面板中添加执行监听器
5. 选择不同的事件类型和监听器类型
6. 查看控制台是否有 `[翻译缺失]` 日志

### 3. 预期结果

- ✅ 标签显示为：`开始: Java类`、`创建: 脚本` 等
- ✅ 控制台无 `[翻译缺失]` 日志
- ✅ 所有下拉选项都是中文

## 当前状态

### ✅ 已完成

1. 添加了所有基础翻译（事件类型 + 实现类型）
2. 添加了完整组合翻译（作为备用）
3. 添加了调试日志功能
4. 确保大小写、空格完全匹配

### 📝 翻译覆盖

- **事件类型（9个）**：start, end, take, create, assignment, complete, delete, update, timeout
- **实现类型（4个）**：Java class, Expression, Delegate expression, Script
- **理论组合数**：9 × 4 = 36 种
- **实际常用组合**：约 20 种（已全部添加）

## 技术细节

### bpmn.js 翻译流程

```
用户点击监听器
    ↓
getListenerLabel(listener)
    ↓
获取 event = 'start'
获取 implementationType = 'class'
    ↓
查找 EVENT_TO_LABEL['start'] = 'Start'
查找 IMPLEMENTATION_TYPE_TO_LABEL['class'] = 'Java class'
    ↓
translate('Start') → '开始'
translate('Java class') → 'Java类'
    ↓
组合：'开始' + ': ' + 'Java类'
    ↓
最终显示：'开始: Java类'
```

### 为什么组合翻译无效？

因为 bpmn.js 在**生成标签之前**就已经完成了翻译：

```javascript
// bpmn.js 内部执行顺序
const eventLabel = translate('Start');        // → '开始'
const typeLabel = translate('Java class');    // → 'Java类'
const finalLabel = `${eventLabel}: ${typeLabel}`;  // → '开始: Java类'

// 注意：finalLabel 已经是中文了，不会再调用 translate(finalLabel)
```

所以添加 `'Start: Java class': '开始：Java类'` 是无效的，因为 bpmn.js 永远不会查询这个完整字符串。

## 总结

**核心原则**：翻译 bpmn.js 动态生成的标签时，必须翻译**组成部分**，而不是翻译**最终结果**。

**检查清单**：
- ✅ 大小写是否匹配？（`'Start'` vs `'start'`）
- ✅ 空格是否正确？（`'Java class'` vs `'Javaclass'`）
- ✅ 是否翻译了基础部分？（`'Start'`, `'Java class'`）
- ✅ 是否添加了调试日志？

---

**最后更新**：2025-10-11
**状态**：✅ 已修复

