sublime text划词翻译不触发的根本原因是其不支持系统级划词事件监听,需插件通过on_selection_modified事件双重校验选区有效性,并延迟50ms读取以确保稳定性。

Sublime Text 本身不支持系统级划词事件监听,所谓“划词即译”必须靠插件主动捕获 on_selection_modified 并做多重校验,否则 90% 的失效都源于选区未真正生效或插件读取过早。
为什么 on_selection_modified 总是拿不到选中文本?
根本原因不是事件没触发,而是 Sublime 在快捷键选词(如 Ctrl+Shift+Right)或视图刚激活时,view.sel() 返回的选区可能为空、跨行、或尚未完成渲染。Windows 下尤其明显。
- 必须双重判断:
len(view.sel()) > 0 and not view.sel()[0].empty(),缺一不可 - 不能在
on_activated里直接读选区——要sublime.set_timeout(lambda: read_selection(), 50)延迟 50ms - 对
move类命令(如光标跳转、快捷键选词)需额外监听on_post_text_command并过滤command_name in ["move", "select_word"] - 避免用
view.expand_to_scope('comment')自动扩展——它会把//后面的空格甚至换行也吞进去,导致翻译结果带多余空白或乱码
并发调用多个翻译 API(DeepL / 百度 / 有道)的正确姿势
Sublime 插件运行在主线程,Python 的 threading 会阻塞 UI;所有 HTTP 请求必须走 sublime.set_timeout_async 封装,且手动控流。
- 用
concurrent.futures.ThreadPoolExecutor(max_workers=2)限制并发数,百度/有道接口极易因并发超 2 而返回429 Too Many Requests - 每个请求必须设
timeout=8,并显式捕获requests.exceptions.Timeout和requests.exceptions.ConnectionError - 参数编码差异大:
DeepL的text要urllib.parse.quote(),有道要原始 UTF-8 字节流 POST,百度返回的trans_result是 list,DeepL返回的是 dict —— 解析前务必先response.json()再判结构
中英文混合文本的划词边界为什么总切错?
view.word() 按空白和标点切分,对 "hello世界123" 这类字符串返回整个区域,但用户真实意图往往是只译 “hello” 或 “世界”,而非整块。
- 禁用默认
view.word(),改用正则粗分:re.findall(r'[a-zA-Z]+|[\u4e00-\u9fff]+|\d+', text) - 结合光标位置反向匹配:取
view.sel()[0].begin(),遍历分块后找最近一块起始位置最接近的 - 自动收缩误选:若
text[0]是 ASCII 字母且text[-1]是中文,说明跨语言选中,应截取首个连续字母段或汉字段 - 特别注意注释内引号:
// "Hello 世界"中的双引号会被expand_to_scope错误包含,导致翻译结果多出引号和转义符
为什么不推荐装现成的“实时翻译注释”插件?
Package Control 中无稳定维护的实时翻译插件;旧插件多数因 API 失效、限流或 Python 运行时缺陷而卡死、崩溃或返回空响应。
- 所谓“悬浮翻译”插件,每次悬停都发请求 → 几秒内触发服务端限流,后续全部失败
- 无法区分
//单行注释和/* */多行块,常把整个函数体当注释翻译 - Sublime 的 Python 3.3 运行时对异步 HTTP 支持弱,插件若用
urllib同步阻塞,编辑器直接卡住 - 更可靠的做法是用 Build System 接
trans(translate-shell):配置${selected_text}变量 +-brief参数,按Ctrl+B即得纯文本结果
真正难的不是调 API,而是让选区稳定、让分词合理、让并发可控、让错误可恢复——这些细节一旦漏掉一个,插件就退化成“偶尔能用”的半成品。











