1. 项目背景与核心挑战
去年在2ccc论坛上看到网友robinttt发布的Delphi IDE菜单翻译插件时,作为一个从Delphi 3时代就开始使用的老程序员,我立刻意识到这个项目的价值。当时这个插件主要针对Delphi 13等高版本,而经过与robinttt的深入交流和技术探讨,我们团队决定将其移植到支持多版本Delphi的CnPack IDE专家包中。
这个看似简单的"菜单翻译"需求,在实际开发中却遇到了两个令人头疼的核心问题:
- 无名菜单项困境:约40%的Delphi菜单项根本没有Name属性,传统通过控件名定位的方式完全失效
- 动态菜单时效性:超过60%的弹出菜单是动态创建的,需要在恰当的时机进行拦截和翻译
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术方案设计与实现
2.1 无名菜单项的翻译方案
面对无名菜单项的挑战,robinttt创新性地采用了"英文文本匹配"的方案。具体实现包含三个关键步骤:
-
建立翻译规则库:将需要翻译的菜单项英文文本(含可变部分的正则表达式)与对应中文翻译存储在配置文件中
示例配置片段:
code复制^&File$=文件(&F) ^&New.*=新建(&N) -
运行时文本匹配:遍历菜单项时,用配置中的正则规则匹配当前项的Caption属性
-
动态替换机制:匹配成功后,保留原菜单项的所有属性和事件,仅替换显示文本
重要提示:必须保留原菜单项的ShortCut、OnClick等属性,否则会导致功能失效。我们通过直接修改TMenuItem的FCaption字段而非调用常规属性设置方法来实现这一点。
2.2 动态菜单的捕获时机
针对不同类型的动态菜单,我们开发了三种捕获机制:
2.2.1 主菜单动态项处理
主菜单(TMainMenu)虽然是静态创建的,但其子菜单项有动态变化特性。我们的解决方案是:
- 启动时全量翻译一次
- 对可能动态变化的顶级菜单项挂接OnPopup事件
- 在事件触发时进行增量翻译
pascal复制procedure TranslateMainMenu;
var
i: Integer;
begin
// 初始翻译
for i := 0 to MainMenu
