Mac 翻译工具实战:选区捕获与安全回填
作者分享 Mac 翻译与听写工具的实现,重点处理选区上下文识别、结果确认、文本回填验证及格式保留。技术栈包括 Swift、AppKit、SwiftUI,以及系统翻译框架、Gemini 和 Soniox。
AI 深度解读
选中文字,双击 ⌘,直接看翻译,听起来只是给翻译接口加个快捷键。作者做了一款原生 Mac 应用后发现,真正费工夫的是选区能否替换、焦点是否变化、链接会不会出错,以及插入之后怎么确认成功。
这篇开发复盘的价值,在于把一个小工具拆成了可检查的操作流程。对做编辑器、桌面助手或 AI 文本处理功能的程序员来说,它提醒我们:生成结果只是中间一步,怎样把结果安全地送回原稿,才决定工具能不能放心用。
读到了选区,为什么还不能直接替换
作者把入口定为双击 ⌘:有选区时打开翻译预览,没有选区时打开语音输入。同一个快捷键,背后却需要区分不同的上下文。
网页上的段落可以选中,编辑器里的草稿也可以选中,但前者未必允许修改。因此,应用必须分别回答三个问题:能否读取选区,能否识别原来的编辑位置,以及能否在那里安全插入或替换文字。
捕获到文本,不等于获得了替换文本的条件。
作者采用的翻译流程是:捕获选中文字及其上下文,展示翻译,让用户审阅,确认后才替换。生成过程中,原稿保持不变。
这里的预览有实际用途。原文举的例子包含两层承诺:周五可以交初稿,最终交付取决于修改情况。翻译即使流畅,也可能改动期限或条件。预览无法证明翻译正确,但能让用户在原稿被修改前检查这些关键内容。
粘贴动作完成,怎样才算插入成功
异步请求会制造一个时间差:开始翻译时,用户正在编辑某段文字;结果回来时,焦点可能已经变了。应用如果只记住翻译内容,没有保留原编辑上下文,就可能把正确的结果送到错误的位置。
即使目标位置没错,判断成功也不简单。编辑器可能重新整理段落,或用不同方式表示格式。逐字符、逐格式严格比较,可能把正常插入误报为失败;发出粘贴动作后立刻宣布成功,又缺少证据。
作者最近的工作方向,是检查原编辑上下文是否发生了预期变化,同时确认光标处于预期位置、周围文字保持不变。
这仍是方向性描述。原文没有提供具体校验算法,也没有说明适配了哪些编辑器,不能据此认定兼容性问题已经解决。
结果不确定时,还需要恢复路径。尤其不能不停重试插入,否则一次状态判断失败,就可能变成多次重复写入。作者提出了这个要求,但没有交代恢复界面的具体实现。
保留格式时,哪些内容不该交给模型
作者希望保留粗体、斜体和真实网页链接。其中,链接需要拆开处理:可见文字可以翻译,目标地址必须保持原样。
他的做法是把链接地址留在本地,在翻译请求中使用每次操作专用的不透明引用。可以把它理解为临时编号:模型处理编号附近的文字,应用负责将编号对应回原地址。
返回结果中的引用,还要与源文本捕获到的引用核对。出现未知引用就丢弃,不根据它猜测链接。
链接地址由本地数据保管,模型只参与可翻译内容的转换。
这个约束也划清了富文本与 Markdown 的边界。看起来像 Markdown 的文字,不会自动被当作真实超链接。支持粗体、斜体和链接,同样不代表能够保留整个文档的版式。格式能保留多少,取决于来源和目标编辑器双方的能力。
语音输入为什么要多留一道审阅
加入听写后,无选区时双击 ⌘ 会打开语音输入。用户看着转写结果出现,审阅最终文字,再决定直接插入转写稿,还是先翻译后插入。
作者明确保留了这条链路:
Speech → transcript → optional translation → insertion
转写和翻译解决的是两个问题。前一步已经听错,后一步可能把错误润色得更自然,反而增加发现问题的难度。语音源语言也不能根据翻译目标推断:用户想输出英文,并不代表他说的是英文。
技术栈方面,应用使用 Swift、AppKit 和 SwiftUI,通过 AVAudioEngine 采集语音,由 Soniox 做流式转写。翻译可以选择 Apple 的系统 Translation framework 或 Gemini。
这些路径的使用条件不同。Apple 翻译依赖 macOS 版本和受支持的语言模型,但原文没有给出具体版本清单;Soniox 流式听写和 Gemini 翻译需要联网。界面必须让用户看清这些区别,原生 Mac 应用的外观不能成为宣称云端处理在设备本地完成的理由。
我的判断
我认同作者把工程重点放在操作边界上。对会修改用户草稿的工具,翻译质量和写入可靠性都重要。尤其是保留原稿、确认后替换、校验链接引用,这些做法都有明确的失败场景作为依据。
不过,这篇提供的是作者的实现思路和开发经验,没有成功率、延迟、编辑器兼容范围,也没有与其他方案的对照数据。双击 ⌘ 是否比普通快捷键顺手,文中同样没有验证,不能直接当成通用交互结论。
与手动复制粘贴相比,这套流程能减少切换应用的步骤,但也把定位、校验和恢复的责任交给了工具。与生成后自动覆盖相比,预览增加了一次确认,却给期限、数量和条件的检查留下了空间。对重要草稿,我更倾向于保留这一步;低风险场景是否需要相同流程,还要结合实际使用成本判断。
能拿来做什么
- 给编辑器增加 AI 翻译或改写功能时,把读取选区、判断可编辑、确认目标位置分别处理,并检查异步结果返回时原位置是否仍然有效。
- 处理富文本链接时,在本地保存原始 URL,让模型返回可校验的引用;遇到未知引用时拒绝生成猜测地址。
- 做语音输入时,先让用户检查转写稿,再提供可选翻译,并分别设置语音源语言与翻译目标语言。
- 为插入结果设计成功、失败和不确定三种状态。不确定时提供恢复入口,避免自动重复插入;同时明确标注联网要求和实际支持的格式范围。