尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

BPMN.js汉化实战:配置文档驱动中文翻译

BPMN.js汉化实战:配置文档驱动中文翻译 简介这是一份面向 Web 开发者的 bpmnjs 汉化资源包用于解决 BPMN 编辑器默认英文界面给中文用户带来的使用门槛。资源包以材料齐全、可直接参照为特点除完整汉化资源与配置文件外还内置了配置文档开发者能按说明快速完成属性面板及核心模块的中文本地化。包内共 6119 个文件以 js、json、ts、css 等前端代码与配置类型为主辅以 md 说明文档和 license 声明压缩包总大小约 15.17MB目录组织清晰便于定位需要替换的汉化文件和构建脚本。目前已有 458 人学习下载适用对象为需要在项目中集成 bpmnjs、并以中文界面进行业务流程建模的前端工程师以及流程设计工具二次开发者。利用这套方案可免去自行整理翻译资源和排查配置的重复劳动直接对照文档完成汉化改造有效提升团队协作与建模效率。1. BPMN.js 汉化操作一张配置文档让画布、菜单和属性面板全部变成中文不少开发者拿到“bpmnjs汉化-内有配置文档放心下载”这类资源包第一反应是把界面上的几个单词替换掉就算完事。真正接进项目才发现流程设计器里的英文至少来自三块互不相同的界面左侧 palette 的“Create StartEvent”点选节点后弹出来的 contextPad 上的“Append Task”以及右侧属性面板里的“General”“Documentation”。这三块文案由 bpmn-js 不同模块生成虽然展示时机各不一样最后都会走到同一个translate()翻译函数里等待替换。因此汉化操作的核心不是去 npm 包里改源码而是准备一份配置文档中英术语映射把它注入到 bpmn-js 的翻译管线。下面按机制、配置、集成、验证四条主线把这份映射表从读到写到生效的过程完整梳理一遍适合正在做流程设计器、审批流前端或工作台组件的开发者参考。2. BPMN.js 翻译机制配置文档中的 key 是如何被界面消费的2.1 所有汉化操作最终都要注入同一个 translate 函数bpmn-js 是构建在 diagram-js 之上的从创建流程节点到弹出菜单界面文案的生成路径可以简化成三步Provider 提供英文模板字符串调用translate(template, replacements)再交给渲染层输出。默认情况下 bpmn-js 内置的 translate 实现只是占位符替换器把{name}这种变量替换成实际值后原样返回英文。这就是为什么你不装任何汉化模块时界面同样是英文的和有没有引入中文语言包无关。汉化操作真正改变的是第二步额外注册一个 customTranslate让它先查配置文档对应的字典查得到就返回中文查不到就回退到原始英文。这个动作在 bpmn-js 里通常以 additionalModules 的形式在new BpmnModeler时注入。一个最简翻译器如下const zhDictionary { Create StartEvent: 创建开始事件, Create Task: 创建任务, Append Task: 追加任务 }; const customTranslate { translate: function (template, replacements) { replacements replacements || {}; template template.replace(/\{([^}])\}/g, function (match, key) { return replacements[key] || { key }; }); return zhDictionary[template] || template; } }; const modeler new BpmnModeler({ container: #canvas, additionalModules: [ { translate: [value, customTranslate] } ] });这段代码里有几个参数值得说明。translate函数签名中template是 Provider 传入的原始字符串形如Create StartEventreplacements是字符串里需要替换的变量对象。先用正则把{变量}占位符替换掉是在模仿 bpmn-js 默认 translate 的行为否则带变量的模板会暴露原始花括号。最后一行zhDictionary[template] || template是整条汉化操作的命门字典是“英文原文 - 中文”如果这条 key 不在字典里就原样返回避免界面出现空白。提示additionalModules里的注入格式是{ translate: [value, customTranslate] }。数组第一个元素固定写value表示按值注入第二个元素是翻译器对象。如果漏掉数组包装直接写{ translate: customTranslate }bpmn-js 会把它当成模块定义而不是实例页面通常不报错但所有中文都不会出现。2.2 配置文档要覆盖五类 keypalette、contextPad、属性面板最常漏下载包里那份配置文档作者通常会以 key-value 列表或 JSON 形式给出我见过比较规范的会把条目按界面区域分表。按渲染位置划分至少要覆盖以下五类界面区域典型配置 key渲染位置说明是否依赖上下文左侧 paletteCreate StartEvent、Create Task、Create EndEvent工具栏图标下方标签依赖元素创建类型节点 contextPadAppend Task、Replace、Delete点选节点后弹出的操作按钮依赖当前节点类型与连接规则弹出菜单Append、Replace、Connect点开更多操作后的菜单项和 contextPad 共用 Provider属性面板General、Name、Documentation、Implementation右侧表单的条目标题由 properties panel 的 entry 提供校验提示Element must be connected、Flow must be a Sequence Flow保存或规则校验时报错只在错误场景出现palette 与 contextPad 的 key 大多可以通过点击界面反查比较直觉属性面板里的General、Documentation属于公共词它们在代码里不带有bpmn:前缀需要单独记录。校验提示则最隐蔽不触发对应错误根本看不见。汉化操作如果只做到前两类用户截图时还是会被英文报错文案穿帮。惯用做法是把配置文档拆成两层一层是术语词典负责StartEvent - 开始事件、Task - 任务这类元素类型另一层是界面片语负责Create StartEvent - 创建开始事件这类完整句子。术语层可以在多处复用片语层直接配给具体界面。下载包里如果只提供了其中一层我会在实际打开界面后把另一层补全。2.3 配置文档与 bpmn-js 版本不同步用 rg 反向定位过期 key我遇到不止一次的情况下载包注明适用于 bpmn-js但项目里版本较新部分 key 已经变了。比如某些重构版本把 palette 的 key 从create.task改成更可读的Create Task配置文档不跟随更新映射就全部失效。不要凭肉眼在界面里猜直接用 grep 工具定位模板字符串的真实面目rg Create Task|Append Task|General|Documentation \ node_modules/bpmn-js/lib \ node_modules/bpmn-js-properties-panel/lib这条命令把 bpmn-js 核心包和属性面板包里出现这些英文模板的文件脉络列出来你会看到类似PaletteProvider.js、ContextPadProvider.js、ReplaceMenuProvider.js的路径模板字符串就写在 provider 里。把它们逐条和配置文档比对就能知道哪个 key 过时、哪个 key 缺失。node_modules 里的文件不建议直接改npm install重新执行后改动会消失正确姿势是把定位结果回写到自己的配置文档再走注入流程。如果你项目里用的是压缩后的打包文件没有 node_modules 可查可以在customTranslate里临时加上调试分支把每一次未命中的 template 输出到控制台这个开关会在后面的章节给出。3. 把配置文档变成中文语言包字典编写与翻译器注入3.1 从下载包的配置文档生成模块化 zh 字典拿到配置文档后先把它转换成一个可按需导入的 JavaScript 模块。结构上保持“英文 key - 中文 value”的单层映射同时保留配置文档里的分组注释方便日后对照。一个典型的字典文件长这样// 术语词典负责 bpmn 元素类型与公共属性 export default { StartEvent: 开始事件, EndEvent: 结束事件, Task: 任务, User Task: 用户任务, Service Task: 服务任务, Exclusive Gateway: 排他网关, Parallel Gateway: 并行网关, General: 常规, Name: 名称, Documentation: 文档, Implementation: 实现, // 界面片语负责 palette / contextPad / 菜单 Create StartEvent: 创建开始事件, Create Task: 创建任务, Append Task: 追加任务, Append EndEvent: 追加结束事件, Delete: 删除, Connect: 连接 };转换过程中最容易丢的信息是“同一个英文在不同界面是否对应不同中文”。比如Name在属性面板里通常是“名称”如果某份配置文档在别处把Name定义为“流程名”就需要按界面优先级拆成两个场景在注释里标明优先级。我不建议做智能化解析直接按配置文档的行号逐条搬运然后跑一遍界面截图对比差异最省时间。字典文件同时要控制格式统一 UTF-8 无 BOMVS Code 里右下角编码如果显示 UTF-8 with BOM先另存一次。带 BOM 的 JS 文件在某些构建链里会报错带 BOM 的 JSON 文件则会直接把第一个 key 解析坏。配置文档里的 key 如果出现同名不同义可以用一个小表格管理英文 key出现界面推荐中文备注Name属性面板名称元素 name 字段Name弹窗标题命名多实例循环配置弹窗General属性面板 Tab常规首个 Tab 页这个表可以放在配置文件头部注释里也可以在代码仓库里单独建一份 Markdown和实际字典同步维护。汉化操作完成后这张表是后续版本升级时最值得依赖的记录。3.2 注册 customTranslate 的完整顺序先插值再查字典字典文件做好后需要一个把翻译实现放进 bpmn-js 依赖注入容器的模块。推荐结构是“一个模块 一个字典”模块内部暴露translate方法方法里先处理插值变量再依次查术语层和片语层。带容错版本的实现如下import zhDictionary from ./zh; const customTranslate { translate: function (template, replacements) { replacements replacements || {}; // 先处理插值变量避免字典匹配变形 const interpolated template.replace(/\{([^}])\}/g, function (match, key) { return replacements[key] ! undefined ? replacements[key] : {${key}}; }); // 依次查术语层和片语层两层都没有就返回原始值 if (zhDictionary[interpolated]) { return zhDictionary[interpolated]; } const trimmed interpolated.trim(); if (zhDictionary[trimmed]) { return zhDictionary[trimmed]; } return interpolated; } }; export default customTranslate;这段代码的关键点有两个先做插值再做字典查询是为了兼容模板里带变量的情况先查原样再 trim 一次是为了覆盖某些 Provider 在拼接模板时残留的首尾空格。靠近末尾加一个调试分支开发阶段可以打开发布前再注释掉if (!zhDictionary[interpolated] !zhDictionary[trimmed]) { console.warn([bpmn-zh] 未汉化 key:, JSON.stringify(template)); }把所有未命中的 key 打印出来比对着界面逐一截图快得多。得到一份完整的 key 清单后直接回填到配置文档汉化包的覆盖率就会随每次迭代逐步收敛。随后在创建 BpmnModeler 时引入import BpmnModeler from bpmn-js/lib/Modeler; import customTranslate from ./i18n/customTranslate; const modeler new BpmnModeler({ container: #canvas, additionalModules: [ { translate: [value, customTranslate] } ] });{ translate: [value, customTranslate] }是整个汉化操作能否生效的分水岭。当属性面板或画布组件初始化时它们会通过依赖注入获取translate拿到的版本如果不带[value, ...]包装bpmn-js 会把它当作模块定义而非实例果界面毫无变化而且控制台不抛错排查一圈才发现是注入格式的问题。3.3 属性面板的汉化边界公共词进字典业务字段别动属性面板的情况略微特殊。bpmn-js-properties-panel 新旧版本的 API 差异较大汉化操作有两条路线可走。第一种是在 customTranslate 里直接补公共词把General、Name、Documentation、Implementation配进字典改动量最小适用于配置文档已经把这些公共词列全的情况。第二种是自定义属性面板的 entry把标签和显示逻辑整体替换成中文模板import entryFactory from bpmn-js-properties-panel/lib/factory/EntryFactory; const nameEntry entryFactory.textField({ id: name, label: 流程名称, modelProperty: name });上面这段是旧版属性面板的写法如果你的项目用新版bpmn-io/properties-panel类名与工厂函数都变了不能直接照搬。碰到版本差异时我优先选择“公共词进字典”的路线因为它绕过了属性面板底层 API 的变迁汉化文件写一次可以稳定生效。同时要守住一条边界汉化只做显示层映射不能改element.businessObject.name这类真实属性值。配置文档里如果出现“把节点的 name 改成中文”的建议那是误解了汉化职责。流程数据仍然要保存英文或业务系统定义的原始值界面展示中文即可否则导出 BPMN XML 后数据就脏了。4. Vue 3 与 React 项目集成汉化配置文档实际落地4.1 Vue 3 组合式DOM 挂载完成后再创建 modelerVue 工程中最常见的坑不是翻译器注册而是容器。new BpmnModeler({ container: #canvas })要求#canvas已经存在于 DOM 中在 Vue 里意味着 ref 要指向真实元素并且 mounted 之后再创建。把前面准备好的customTranslate与字典直接导入完整写法如下template div refcanvasRef classbpmn-canvas/div /template script setup import { ref, onMounted } from vue; import BpmnModeler from bpmn-js/lib/Modeler; import customTranslate from /i18n/customTranslate; const canvasRef ref(null); let modeler null; onMounted(() { modeler new BpmnModeler({ container: canvasRef.value, additionalModules: [ { translate: [value, customTranslate] } ] }); modeler.createDiagram(); }); /script这里把container直接传canvasRef.value而不是字符串#canvas能避开 Vue 模板 ref 与 bpmn-js 内部 id 查询之间的时序问题。onMounted里初始化组件卸载时也要记得清理onBeforeUnmount(() { if (modeler) { modeler.destroy(); } });另外建议把modeler放在模块级变量或markRaw包一层不要直接塞进 Vue 的reactive响应式状态。bpmn-js 内部对象数量多、引用关系复杂被 Proxy 包裹后事件循环里不断触发响应式更新排查起来非常痛苦。汉化配置文档字典是纯静态数据放在模块引用里即可不需要参与响应式。4.2 React 函数组件清理函数里的 destroy 必须写React 中的约束在 StrictMode 下尤其明显。开发环境 StrictMode 会执行两次 effect第一次创建 modeler 后如果没有清理函数第二次会在同一个 DOM 上叠加新实例出现重复 canvas 或事件堆积。配合汉化配置文档最小可运行版本如下import { useEffect, useRef } from react; import BpmnModeler from bpmn-js/lib/Modeler; import customTranslate from ./i18n/customTranslate; export default function BpmnEditor() { const containerRef useRef(null); useEffect(() { const modeler new BpmnModeler({ container: containerRef.current, additionalModules: [ { translate: [value, customTranslate] } ] }); modeler.createDiagram(); return () { modeler.destroy(); }; }, []); return div ref{containerRef} classNamebpmn-canvas /; }useEffect的清理函数里执行modeler.destroy()是 React 18 以后必须养成的习惯。destroy()会把 bpmn-js 内部的事件总线、canvas 上的 SVG 节点一并卸载否则再次进入页面时旧实例仍监听键盘与鼠标事件界面会出现双份节点。汉化字典在这个组件里只负责给翻译器提供数据不参与状态更新因此不需要放进useState。4.3 三个高频问题重复画布、命中了没变化、初始化闪烁把下载包配置文档接入框架时我遇到过并且建议你重点检查的问题有三个。第一个是创建了多个 bpmn-js 实例。组件被复用而 modeler 没有随组件卸载界面会出现两张画布所有汉化项的视觉检查都会失真。判断方法很简单打开开发者工具切到 Elements 面板看container下是否出现两个.djs-container。出现两个就是旧实例没销毁。第二个是字典命中但界面不变。先确认zhDictionary[interpolated]在当前 bpmn-js 版本里真的被调用了。把上一节的 debug 分支临时打开凡是字典未命中的 template 都会打印到控制台逐个对照配置文档补 key 即可if (!zhDictionary[interpolated] !zhDictionary[trimmed]) { console.warn([bpmn-zh] 未汉化 key:, JSON.stringify(template)); }第三个是 contextPad 工具栏文字先显示英文再变中文。这不是配置错误而是 bpmn-js 初始化时先渲染默认语言再触发画布重建。只要最终呈现中文就可以接受如果产品要求严格一致可以在modeler.createDiagram()返回的 Promise 完成后再展示画布区域减少用户可见的切换闪烁。综合来看Vue 与 React 场景下除销毁时机外汉化配置文档本身是框架无关的这也是把字典独立成模块的核心收益。5. 动态语言切换与配置文档自查把漏翻项收干净5.1 运行时切换语言的常见做法销毁模型器并重建customTranslate注入发生在new BpmnModeler时这意味着语言包要换翻译器实例必须换。别试图在运行时往 bpmn-js 内部塞一个可变字典常见做法是直接销毁重建async function switchLanguage(modeler, container, locale) { if (modeler) { await modeler.destroy(); } const dict locale zh ? zhDictionary : enDictionary; const nextModeler new BpmnModeler({ container, additionalModules: [ { translate: [value, makeTranslate(dict)] } ] }); await nextModeler.createDiagram(); return nextModeler; }makeTranslate(dict)就是把前面 customTranslate 里的字典参数变成闭包变量不再从模块顶部固定导入。销毁重建的优点是代码简单、状态清得干净缺点是切换时未保存的图形状态会丢失。如果产品必须保留画布内容就在 destroy 前调用saveXML保存流程重建后importXML导回数据量不大时整个过程可以控制在几百毫秒内。5.2 五类 key 的验收清单与字典回补汉化操作收尾阶段按这张清单逐项核对检查项验证方式通过标准palette 图标左侧工具栏逐个悬停无英文残留contextPad点选 StartEvent / Task / Gateway 各一次操作菜单全中文属性面板选中节点右侧各 Tab 切换一遍Tab 名与字段名无英文校验提示删除唯一开始事件触发校验报错文案中文化数据完整性双击改名后保存再打开数据内容不因汉化被改写最后一行“数据完整性”重点验证汉化后的导出 XML 中name属性仍保存原始英文或业务值没有因为显示层翻译被写入中文。验证方法是导入一份带英文 name 的 bpmn 文件界面上中文展示导出后再用文本编辑器打开 XML确认 name 字段保持原样。漏翻项扫描留到最后一步保留调试 warn 跑一遍典型操作路径创建开始事件、追加任务、设置属性、删除节点把控制台所有未命中 key 收集起来回填配置文档。这份配置文档一旦稳定就可以固定为团队内部的语言包基线。下次升级 bpmn-js 时只需要把新版本里新增的提示类字符串 grep 出来增量补进字典整套汉化操作就完成了闭环。本文还有配套的精品资源点击获取
返回列表