装完 StarUML 6.3.0 第一次打开,多数人的第一反应不是"这工具真强",而是"Model Explorer、Toolbox、Properties 这几个面板里全是英文,我到底该点哪个"。菜单栏那七个单词谁都认识,真正卡住人的是类图里那些 Stereotype、Association End、Aggregation 之类的术语,以及右键菜单里一堆长得差不多的 Export 选项。于是就有了汉化这件事。
这篇讲的是我这两天在 6.3.0 上折腾界面本地化的完整过程:安装包怎么放、Electron 的 app.asar 是什么结构、字符串从哪儿找、改完怎么打包、哪些地方一改就崩、升级之后成果怎么保住。顺带把"汉化完之后到底该怎么学 StarUML"这件事说透——毕竟界面看懂只是入场券,建模思路才是真东西。适合刚接触 UML 建模工具、又不想被英文术语反复打断节奏的人看,也适合想搞清楚 Electron 桌面应用本地化套路的人参考。
需要提前说明一点:界面语言本地化只涉及前端资源文件,不涉及任何授权相关操作。评估期结束后按官方渠道获取授权,这是前提。
1. 先想清楚:为什么要给一个建模工具做界面本地化
1.1 英文界面的真实门槛不在菜单栏
很多人对"汉化"的想象停留在把 File 改成文件、Edit 改成编辑。真上手会发现这层翻译毫无价值,因为 File 和 Edit 下面那几个命令你在任何一个桌面软件里都见过,肌肉记忆比翻译管用。
真正消耗注意力的是第二层和第三层。第二层是建模语义词汇,比如类图里一个属性可以设置 visibility 为 public、protected、private、package,可以设置 isStatic、isAbstract;关联关系要区分 Association、Aggregation、Composition、Generalization、Realization、Dependency。这些词在 UML 规范里有严格定义,翻译错了比不翻译更麻烦。第三层是操作过程中的提示语,比如拖拽元素时的吸附提示、属性面板底下的说明文字、导出失败时的报错弹窗,这些一闪而过的信息如果读不懂,你会反复在同一个地方卡壳。
我自己的判断标准是:如果一个英文词你能在三秒内反应出它的准确含义,就别翻;如果每次都要愣一下,或者要靠猜,那就值得改。按这个标准筛下来,一份完整的 6.3.0 汉化其实只覆盖了大约六七百个字符串,其中真正高频的不到两百个。
1.2 三条路线摆在一起比一比
在动手之前我把能走的路都列了一遍,最后选了工作量最大但最可控的那条。
| 路线 | 具体做法 | 优点 | 风险与代价 |
|---|---|---|---|
| 整包替换 | 直接下载别人做好的 app.asar 覆盖原文件 | 五分钟搞定,覆盖最全 | 版本必须严格对应,来源不可控,可能夹带额外脚本 |
| 自行解包改写 | 解出 app.asar,逐条替换界面字符串,重新打包 | 完全可控,改了什么心里有数 | 工作量大,需要 Node 环境和一点前端基础 |
| 外挂注入 | 用扩展机制在运行时替换菜单和词典 | 不动原始文件,升级不怕 | 覆盖范围有限,深层面板和弹窗改不到 |
| 实时翻译工具 | 悬浮取词、截屏翻译 | 零成本 | 打断操作节奏,专业术语翻得离谱 |
我选第二条的理由很直接:第一条路的风险不对称。一个 app.asar 里装的是整个前端工程,包括所有视图模板、样式和业务脚本,你把一个来路不明的文件丢进安装目录,等于让它在你的机器上执行任意代码。而这个文件本身没有任何签名可验。相比之下,第二条路最多花两个小时,但每一个字节的改动你都清楚。
第三条路其实值得单独说一句。如果你只是想改菜单栏,StarUML 的扩展机制确实能做到——写一个扩展,在主进程启动时读取原生菜单模板再逐项替换文本。但它改不到渲染进程里的属性面板和工具箱,而这恰恰是最需要中文化的地方。所以外挂方案我只推荐给"只想让菜单顺眼一点"的人。
1.3 一个反直觉的结论:不要全翻
我第一版汉化把能看到的英文全翻了,结果用起来极其别扭。原因是 StarUML 的很多界面文字和 UML 规范术语是强绑定的,你搜教程、看规范文档、问人的时候用的都是英文原词。把 Generalization 翻成"泛化",把 Realization 翻成"实现",看中文界面的时候觉得挺顺,回头去查资料发现对不上号。
后来我调整了策略:菜单、按钮、对话框标题、提示语全部中文化;UML 元模型里的元素名和属性名保留英文,只在悬停提示和属性面板的说明文字里加中文注释。这个混合方案用起来最舒服,也避免了"汉化完反而看不懂教程"的尴尬。
2. 6.3.0 安装这一步就决定了后面能不能改
2.1 安装路径别用默认的
Windows 上默认装到C:\Program Files\StarUML\,这个位置是受保护目录。你后面要改 resources 下的文件,要么每次用管理员权限启动编辑器,要么在保存的时候被系统拦一道,运气不好还会出现"文件已被占用"的诡异情况。
我的做法是安装时手动指定到非系统盘,比如D:\Tools\StarUML\。这一步在安装向导里就能改,不需要任何技巧。装完之后整个安装目录都是普通权限可写,后面解包、替换、备份全程不用提权。
提示:如果你已经装在了系统盘,不必重装。可以把整个安装目录复制一份到别处,在副本上做汉化,验证没问题后再决定是否替换。副本目录里的 exe 可以直接运行,Electron 应用的路径依赖是相对的。
macOS 上的情况略有不同,应用是.app包,右键"显示包内容"进去后路径是Contents/Resources/app.asar。Linux 版通常是解压即用的目录结构,同理。三个平台的核心文件位置一致,只是外层壳子不同。
2.2 装完先看清 resources 目录长什么样
在动手之前,先把安装目录的结构摸清楚。这是后面所有操作的坐标系。
StarUML/ ├── StarUML.exe # 主程序入口 ├── chrome_100_percent.pak # Chromium 资源包 ├── icudtl.dat # 国际化数据 ├── resources/ │ ├── app.asar # 整个前端工程,打包成一个文件 │ └── app.asar.unpacked/ # 部分原生模块被排除在归档外 ├── locales/ # Chromium 层面的多语言资源 └── 各种 .dll 和 .pak 文件这里有个容易误解的点:locales/目录看着像是语言包,实际上是 Chromium 自己的多语言资源,只影响右键菜单里的"剪切/复制/粘贴"这类系统级文字和部分内置对话框。你往里塞中文资源也改不了应用本身的界面。真正的界面文字全在resources/app.asar里。
app.asar.unpacked目录也值得留意。打包工具可以把某些文件排除在归档之外(通常是需要被 Node 直接加载的.node原生模块),这些文件在归档里只留一个占位记录。如果你重新打包时没有正确处理这个目录,启动后可能直接报模块加载失败。
3. app.asar 是什么:改文件之前必须搞懂的一层壳
3.1 归档格式的索引原理
asar 是 Electron 自己定义的一种归档格式,本质上是把一棵目录树序列化成一个二进制文件。文件开头是一段 JSON 索引,记录了每个条目的路径、类型、大小和在文件中的字节偏移;索引之后是各个文件的内容首尾相接。
Electron 运行时通过内置的 asar 模块读取这个文件,把它当普通目录用。应用代码里写require('./views/main.html')和写fs.readFileSync('...')都能正常工作,因为运行时在文件系统层做了一次映射。
对汉化来说,这个机制的含金量在于:改动是可逆的、可对比的。解包出来的是一个完整的目录树,你可以用 VS Code 打开,用全局搜索定位字符串,改完之后重新打包。整个过程和改一个普通前端项目没有任何区别。
3.2 解包与重打包的工具链准备
需要 Node.js 环境,版本用 LTS 就行,不需要特别新。工具用官方维护的@electron/asar包,老的asar包已经不再更新。
# 建议全局装一次,后面几条命令都能直接用 npm install -g @electron/asar # 确认装好了 asar --version如果没有全局安装的权限,用npx @electron/asar也能跑,只是每次都要联网确认一次。
解包命令很简单,但要先把工作目录准备好:
# 建一个独立的工作目录,把 app.asar 复制进去再操作 mkdir D:\work\staruml-localize cd D:\work\staruml-localize # 从安装目录复制原始文件过来 copy "D:\Tools\StarUML\resources\app.asar" . # 解包 asar extract app.asar app_unpacked解包完成后,app_unpacked目录里就是完整的前端工程。你会看到熟悉的node_modules、src、package.json、各种.html和.js。看到package.json里那一行"main": "...",就说明找到主进程入口了。
重新打包装回去的命令是反过来的:
asar pack app_unpacked app-new.asar这里有个细节要注意:打包时的目录名会影响到归档内部的条目路径。如果你用app_unpacked这个名字打包,某些情况下会多一层前缀,导致主进程找不到入口。稳妥的做法是先确认原归档的顶层结构,然后保持同名打包。
4. 定位需要翻译的字符串:从关键词反查文件
4.1 用全局搜索代替瞎翻目录
解包出来的目录有几百个文件,一个个点开看是不现实的。最快的方式是从界面上抄一个词,然后全局搜。
比如你想知道"Export Diagram as Image"这句提示在哪个文件里,就这样做:
# 在解包目录下递归搜索,Windows 自带命令 findstr /s /i /n /c:"Export Diagram" *.*Linux 和 macOS 上用grep -rn "Export Diagram" .就是同一个意思。不过我更推荐直接用 VS Code 打开app_unpacked目录,按Ctrl+Shift+F全局搜,因为搜索结果会带上下文预览,你能一眼看出这个字符串是出现在 HTML 的文本节点里、JS 的配置对象里,还是某个渲染函数里。这个判断直接决定了它能不能改。
一般来说,界面字符串会出现在这么几个地方:
.html文件里的标签文本,比如<button>Export</button>- JS 文件里的常量表或者配置对象,形如
{ file: 'File', edit: 'Edit' } - 主进程脚本里构建菜单的部分,通常是
Menu.buildFromTemplate([...])这类调用 - 模板字符串里,形如
`<div>${title}</div>`中的静态文字
前三种可以放心改文本内容,第四种要小心,改的时候只动引号里的汉字,别碰${}里的表达式。
4.2 哪些字符串能改,哪些一个字都不能碰
这是整个流程里最容易翻车的地方。我按优先级列了一张对照表:
| 位置 | 是否可改 | 原因 |
|---|---|---|
| HTML 标签之间的文本 | 可以 | 纯展示,不影响逻辑 |
菜单模板里的label字段 | 可以 | 只用于显示 |
| 对话框按钮文字 | 可以 | 同上 |
| 属性面板的字段说明 | 可以 | 同上 |
JSON 配置里的label/tooltip | 可以 | 同上 |
| JS 变量名、函数名 | 绝对不行 | 改了就报错 |
| 对象 key、枚举值 | 绝对不行 | 用于逻辑判断 |
| 文件路径、模块名 | 绝对不行 | 加载会失败 |
| CSS 类名 | 绝对不行 | 样式会失效 |
| 快捷键描述字符串 | 视情况 | 有的用于注册,有的纯展示 |
判断某个 JS 字符串能不能改,有个简单的测试:看它在代码里是作为"值"被输出,还是作为"键"被比较。如果这个字符串后面跟着=然后被赋给某个显示变量,安全;如果它出现在if (x === 'xxx')或者作为对象的属性名obj['xxx'],那就别动。
我在改的过程中养成了一个习惯:每改一个文件之前先把它复制一份到originals/目录,改完在 git 里能看到 diff。这样一旦出问题,两分钟就能定位到是哪次改动引入的。
5. 动手改:一轮完整的替换与回滚演练
5.1 备份与目录外试验
在动任何真实文件之前,第一步是把原始app.asar备份好,命名带上版本号和日期,比如app.asar.bak-6.3.0-20241105。这一步不能省,因为后面如果打包出了问题,你唯一的退路就是这个文件。
然后我在解包目录里做了个分层策略:
app_unpacked/ ├── src/ │ ├── ... # 原始代码,只读不改 │ └── ... ├── originals/ # 每个被改文件的原始副本 └── ...改的时候我按模块推进,一个模块改完就打包一次、启动一次、验证一次。千万别憋着一次性改完几百个字符串再打包,那样一旦启动崩溃,你根本不知道是哪条改动导致的。
第一轮我只改主菜单,大概二十几个词。打完包启动,菜单栏显示正常,说明工具链是通的。第二轮改工具箱和属性面板,第三轮改对话框和提示语。每一轮结束都打包验证,这个节奏虽然慢,但整体上比"一把梭然后疯狂排查"要快得多。
5.2 改完之后的重新打包与体积校验
打包之后别急着替换,先做两项检查。
第一项是体积对比。正常的汉化改动只会让文件大小有小幅波动,通常在几百 KB 以内。如果新生成的 asar 比原始文件小了一大截,说明打包参数不对,可能漏掉了node_modules;如果大了一大截,说明打包时把originals/备份目录也打进去了。
# 对比两个文件大小 dir app.asar app-new.asar第二项是条目数量对比。用asar list可以列出归档内的所有条目,跟原始文件比对一下,看看有没有缺漏。
asar list app.asar > list-original.txt asar list app-new.asar > list-new.txt两份列表行数应该基本一致,只在你新增或删除文件的地方有差异。如果差了几百行,说明打包范围有问题。
确认无误后,把新文件复制到安装目录覆盖,启动测试。第一次覆盖之后建议先别关窗口,把常用功能都点一遍,确认没问题再关。
注意:如果覆盖之后应用直接崩溃、白屏或者控制台报 asar 完整性校验相关的错误,说明这个版本的安装包启用了归档校验。这种情况下降级到外挂方案,或者只做菜单层面的本地化,不要硬啃。
6. 汉化后逐个界面验收:六个必查位置
6.1 主菜单与右键菜单
主菜单是最显眼的位置,也是最先被验证的。StarUML 的菜单分为 File、Edit、Format、Model、View、Tools、Help 七组,每组下面十几到二十几个命令。改完之后重点看三件事:菜单项文字是否正常显示(有没有乱码)、下拉菜单宽度是否合适(中文比英文短,一般不会溢出)、快捷键提示是否还在右侧对齐。
右键菜单是第二个必查位置。在图编辑区空白处右键、在元素上右键、在 Model Explorer 的节点上右键,三个位置的菜单内容完全不同,而且这些菜单往往是在 JS 里动态构建的,字符串位置和主菜单不在一处。我第一次改的时候只改了主菜单,右键菜单还是英文,用起来割裂感很强。
6.2 工具箱、属性面板与弹窗
工具箱(Toolbox)在左侧,列出当前图类型可用的元素。类图下有 Class、Interface、Enumeration、Package、Association 等等。这里的文字我按前面说的策略保留英文,只在鼠标悬停的 tooltip 里加中文注释。
属性面板(Properties)在右侧,是信息密度最高的地方。选中一个类,下面会列出 Name、Visibility、Is Abstract、Is Leaf、Documentation 一堆字段。这个面板值得中文化的是说明性文字和分组标题,字段名本身保留英文更利于对照规范。
弹窗是最后一块,也是最容易被忽略的。新建图的对话框、导出的配置对话框、偏好设置的各个标签页,这些地方的文字如果没改,整个汉化的完整度就打了折扣。验证方法很土但有效:把每个菜单项挨个点一遍,凡是弹出窗口的都记下来,对照检查。
7. 踩过的坑:白屏、乱码、布局撑爆与更新覆盖
7.1 编码与 JSON 语法这两类低级错误
第一类坑是编码。有些文件是 UTF-8 无 BOM 保存的,用系统自带记事本打开改完再保存,会被自动转成带 BOM 的 UTF-8 或者干脆变成 GBK。前者会让 JS 解析器在文件开头遇到三个不可见字节,报一个莫名其妙的语法错误;后者直接导致中文全部变成问号。
这个坑我踩过一次,症状是应用启动后白屏,开发者工具里的报错指向一个看起来完全正常的文件的第一行。解决办法只有一条:所有文件都用 VS Code 打开,看右下角编码标识,确认是 UTF-8。如果已经被改坏了,从备份恢复重来。
第二类坑是 JSON 语法。改配置文件的时候多一个逗号、少一个引号、中文引号混进英文引号里,整个文件就废了。这类错误的特点是报错信息极不友好,往往只告诉你"意外的标记",不告诉你在哪一行。我的做法是改完立刻在 VS Code 里看有没有红色波浪线,或者用一个 JSON 校验的小工具过一遍。对于大文件,可以先用格式化快捷键整理一遍,语法错误的地方会立刻暴露。
7.2 中文比英文长带来的排版问题
这个坑比较隐蔽。英文单词普遍短,Export 六个字母,Aggregation 十一个字母;中文两个字就能表达,但有些短语中文反而更长,比如 "Association End" 翻成"关联端点"是四个字,看着短,但在某些紧凑的列表布局里反而会撑破容器。
具体表现是按钮文字被截断、表格列宽不够导致文字换行、下拉菜单项出现横向滚动条。因为 StarUML 的界面样式是用 CSS 写死的,很多元素有固定的 width 或者white-space: nowrap,中文一变长就溢出。
应对策略是控制字数。能用两个字的不用三个字,能用短语的不用完整句子。比如 "Documentation" 在属性面板里占一整行,翻成"文档说明"刚好;如果翻成"文档说明信息",在某些窗口宽度下就会被截断。实在压不下去的,就保留英文。
7.3 升级把成果冲掉之后怎么办
软件自动更新是汉化的天敌。新版本安装时会整个替换 resources 目录,你改的 app.asar 直接被覆盖,一夜回到解放前。
我的处理方式是把汉化工程当成一个正经项目来管:
- 在
D:\work\staruml-localize下建 git 仓库,每次改完提交一次 - 提交信息里写清楚改动的模块,比如"菜单栏 + 右键菜单"
- 主分支放当前版本的完整解包目录,每个大版本开一个分支
- 升级之后先解包新版本,把新目录和老目录做 diff,看官方改了哪些文件
这样做的额外好处是:你能知道新版本改了哪些界面文字。如果一个文件在 diff 里显示被大改,说明官方重构了那部分界面,你之前的汉化不能直接套用,需要重新对照。
至于自动更新本身,如果你打算长期用自己汉化的版本,可以在设置里关掉自动检查更新,改成手动。每次升级都走一遍"备份—解包—迁移改动—打包—验证"的流程,虽然麻烦,但心里有数。
8. 界面看懂之后:StarUML 真正值得学的建模套路
8.1 从类图切入的三天入门路线
界面语言只是降低摩擦,真正要学的是怎么用工具把想法表达清楚。我给自己的安排是三天打基础,顺序是这样:
第一天只玩类图。搞清楚一个类能挂哪些东西:属性、方法、可见性、是否静态、是否抽象、构造型和注释。然后重点练六种关系——关联、聚合、组合、泛化、实现、依赖。这六种关系在工具栏里长得都像线,区别在箭头形状和线型,画错了整个图的语义就变了。我的建议是每种关系画三遍,画完在旁边用文字标注它的含义,加深印象。
第二天练用例图和时序图。用例图简单,参与者、用例、系统边界,加上 include 和 extend 两条关系线,半小时能摸透。时序图是重点,生命线、同步消息、异步消息、返回消息、激活条、组合片段,这几样东西组合起来能表达很复杂的交互。练的时候找一个自己熟悉的场景,比如"用户登录",从用户发起请求画到数据库返回,画完对照别人的图看看哪里不对。
第三天练活动图和状态机图,然后回头把三天的图串成一套。一套完整的建模练习应该是:需求整理成用例图,用例展开成时序图,时序图里出现的名词沉淀成类图,关键对象的状态变化画成状态机图。
8.2 Model 与 Diagram 的分离:这个设计决定了很多操作习惯
StarUML 有个设计容易让新手困惑,但理解之后会觉得很合理:模型(Model)和图(Diagram)是两套东西。模型是数据,存在 Model Explorer 里;图是视图,是模型在画布上的一次呈现。同一个类可以同时出现在两张类图上,改其中一处,两处同步更新。
这个分离带来的直接后果是拖拽行为有歧义。你把 Model Explorer 里的一个类拖到画布上,默认是创建一个新的视图;如果你想引用已有的视图,需要按住 Ctrl 再拖。这两个操作看起来一样,结果完全不同——前者会在模型里多出一个重名类,后者才是你想要的"同一个类的两个视角"。
我在第一天就被这个坑到了,画第二张图的时候拖了三次,模型里出现了四个同名类,导出文档的时候全露馅了。后来养成习惯:新建图之后先看 Model Explorer 的结构,确认拖进来的是引用而不是副本。
另外,删除也要分清。在画布上按 Delete 删的是视图,模型还在;在 Model Explorer 里删节点才是真正删模型。这个区别在整理项目结构的时候特别有用——你可以先把所有想到的类都建在模型里,然后在不同的图上挑需要的部分呈现,而不是边画边建。
8.3 .mdj 文件是纯 JSON,这件事能玩出很多花样
StarUML 保存的项目文件扩展名是.mdj,打开看就是一个结构化的 JSON 文件。这个特性价值很大,但很多人不知道。
第一,可以进版本控制。JSON 是文本格式,git 能 diff、能合并、能追溯每一次修改。团队协作的时候,谁在什么时候加了哪个类、改了哪个属性,一目了然。相比之下,二进制的工程文件只能靠"最后保存者覆盖"这种原始方式协作。
第二,可以批量处理。如果你有一个几百个类的模型,想批量给所有类加一个构造型,手工点不现实。写个小脚本读 JSON、遍历节点、改字段、写回去,几分钟搞定。我试过用这种方式给一批实体类统一加前缀,比在界面上一个个改省事太多。
第三,可以做模型校验。用脚本检查所有关联关系的两端是否都有名称、所有用例是否都有参与者、是否存在孤立的类,这类检查在大型模型里很有必要,手工看根本看不过来。
需要提醒的是,直接改 JSON 有风险。有些字段之间存在引用关系,用 ID 相互指向,手工改错一个 ID,模型加载时就会报错或者丢元素。稳妥的做法是先在界面上做好结构,再用脚本做批量微调,改完立刻打开验证。
最后分享一个我自己用了很久的小习惯:每完成一个阶段性的建模工作,除了保存.mdj,再导出一份 PNG 和一份 XMI。PNG 方便贴到文档里给别人看,XMI 是标准交换格式,万一以后换工具,模型资产不至于全部作废。导出图形的时候注意选分辨率,StarUML 默认导出的清晰度在小屏上看还行,投到大屏上就糊了,导出对话框里可以把缩放倍数调到 2 倍或 3 倍,代价是文件大一点。