本地英汉词典
完全离线的 VS Code 英汉词典插件。选中文本后立即在状态栏显示中文释义,不依赖任何在线翻译 API。
功能
- 选中即显示:选中文本后状态栏立刻给出释义,无防抖延迟
- 标识符译成短语:
getUserInfo → 获取用户信息,MAX_BUFFER_SIZE → 最大缓冲区大小
- 汉译英:选中中文词给出英文候选,
用户 → user, consumer, sub,用于给变量命名时找词
- 查不到就显示原文:词典没收录的内容原样显示英文,不会留空
- 光标所在词:没有选中内容时,翻译光标所在的单词(可关闭)
- 词组优先匹配:
getUserName 会识别出词典收录的词组 user name,而不是拆成两个孤立的词
- 词形还原:
books → book、running → run、better → good
- 完整释义:鼠标悬停状态栏可看到每一段原词、音标、全部义项、考纲标签与词频
准备
npm install
npm run fetch # 下载词典数据(约 75 MB)到 data/
npm run build:dict # 编译成 dict/index.bin 与 dict/data.bin
npm run compile
按 F5 启动扩展开发宿主即可试用。
npm run fetch 若因网络原因失败,会打印手动下载地址与存放路径;文件就位后直接跑 npm run build:dict。
构建默认严格校验原始数据,若上游已经更新,需要先检查变更,再显式运行 npm run build:dict:update 接受新版数据并更新校验基线。
数据源
| 文件 |
大小 |
用途 |
授权 |
ecdict.csv |
65.9 MB |
ECDICT 76 万词条,英译汉 |
MIT |
lemma.en.txt |
2.3 MB |
ECDICT 词形还原表 |
MIT |
cedict.txt |
9.8 MB |
CC-CEDICT 12.5 万词条,汉译英 |
CC BY-SA 4.0 |
CC-CEDICT 是 gzip 格式,npm run fetch 会自动解压。下载只在构建时发生一次——编译进 dict/ 之后,插件的安装与运行全程不联网。
数据来源校验
两个上游都是滚动更新,且不提供校验和或签名。npm run build:dict 每次都会打印三份原始数据的 SHA-256,并与上次构建对比:
原始数据校验和(SHA-256)
ecdict.csv 1a6947e04785db63613a92e14903cdae7954f7e84860b10e68e5c7cbb3f9c3cf
lemma.en.txt e255b097404e3e0052060e2ddf6e15a1414f577071d63d51d2ca0ce9dacee0fc
cedict.txt be95f07f7d7bfb7405d8acdc1e0cb039fb03d8ddacc0c025b42ada4975d1b641
与上次构建(2026-08-10T10:30:10.793Z)一致
基线记在项目根目录的 dict-sources.json(进版本库,不进 vsix)。默认构建发现缺失、新增、大小或哈希不一致时会直接失败,不会覆盖现有基线。确认上游变化符合预期后运行 npm run build:dict:update;只有完整构建成功,才会写入新基线。
架构
多窗口是常见使用场景,而 VS Code 每个窗口都有独立的扩展宿主进程。把整个词典读进内存会让占用随窗口数线性翻倍,因此这里采用索引常驻内存 + 释义数据走操作系统页缓存:
index.bin 18 MB 启动时载入,每个窗口私有
└─ 词表 blob(按 UTF-8 字节序排列)+ 偏移表 + 变形表
+ 中文反查表,全部二分查找
data.bin 39 MB 留在磁盘按需读取
└─ 由内核页缓存托管,所有窗口共享同一份物理内存
中文反查表只存主表下标,data.bin 一个字节都没有增加。状态栏展示英文候选时从内存词表直接取词,不碰磁盘。
页缓存里的文件页是干净页,内存紧张时被内核直接丢弃而非写入 pagefile;相比之下,大 JS 堆属于匿名内存,换出后 V8 GC 遍历堆会把页全部拉回,停顿远比多读一次磁盘严重。
构建期做的事:小写归一并合并大小写冲突的词条、丢弃无释义且无原型的条目、把 exchange 字段与 lemma.en.txt 消化成变形表、按 UTF-8 字节序排序。运行时的二分查找直接比较字节,与构建期排序保持一致。
实测
本机(Node 22 / Windows 11)npm run bench 结果:
| 指标 |
实测 |
| 主表词条 |
768,739 |
| 变形表 |
32,927 |
| 中文反查 |
122,209 |
| 索引载入耗时 |
11.3 ms |
| 预读整个 data.bin |
9.6 ms |
| 英文查询 p50 / p99(页缓存命中) |
6.5 μs / 20.3 μs |
| 中文反查 p50 / p99 |
1.4 μs / 3.2 μs |
| 查询 p50(LRU 命中) |
0.1 μs |
| 每窗口索引内存 |
18.8 MB |
作为对比,把 39 MB 词典整个读进 JS Map 大约要占 260 MB,5 个窗口就是 1.3 GB。
显示规则
选中标识符(拆得出多段)时,逐段取核心译词直接拼成短语:
getUserInfo → 获取用户信息
setUserConfig → 设置用户配置
handleReqError → 处理请求错误
onClickButton → 当点击按钮
user_id → 用户_标识 ← 原文的分隔符保留下来
MAX_BUFFER_SIZE → 最大_缓冲区_大小
fooBarBaz → 富/夫棒形图巴兹 ← 词典数据本身的局限
词与词之间的分隔符(下划线、连字符)原样保留,能看出原标识符的结构;驼峰命名本来就没有分隔符,不受影响。
汉译英
选中中文词,状态栏平铺英文候选,悬停看每个候选的音标与完整释义:
用户 -> user, consumer, sub
文件 -> file, paper, document, documentation
创建 -> create, promotion
缓存 -> cache
共 12.2 万个中文词、20.7 万条候选,索引 2.7 MB。三个来源按优先级合并:
REVERSIBLE_TERMS(src/customDictionary.ts)—— 人工确认的编程译词,压住前两者在编程语境下的偏差(错误 给 error 而不是 mistaken,栈 给 stack 而不是 warehouse)
- CC-CEDICT —— 原生汉英词典,主要来源,贡献了 4.5 万个第三条来源给不出的词
- ECDICT 反查 —— 构建期从英汉释义里抽中文词做的倒排,兜底覆盖
第三条是引入 CC-CEDICT 之前的唯一来源,靠「英文词频 + 义项位置 + 是否 [计] 义项」打分,质量有限——循环 的首选曾是 unwinding 而不是 loop。CC-CEDICT 补上后这类问题基本消失。
仍不建议当标准译法用。 候选顺序是启发式合并的结果,适合「想不起某个词英文怎么写,给我几个候选」。
只做整词精确匹配,不做中文分词:选中 用户信息 查不到就不显示,超过 6 个汉字视为句子直接跳过,中英混杂、日文假名、韩文都不处理。
这是词典,不是翻译引擎
逐词拼接只适用于标识符。选中一整句话时把每个词的释义拼起来,产出的是劣质翻译而非查词,所以有两道闸:
- 含空格的内容只做整体查询。词典或词组表能整体命中就展示(
give up、user name、pull request、anti-high energy radiation rubber),命中不了就不显示——不会把 the quick brown fox jumps 拼成「那 快的 褐色 狐狸 跳跃」,也不会把 const user = new User() 拼成「常量 用户 = 新建 用户」。
- 一个标识符最多拆 15 段。这个上限只用来挡 base64、随机串这类明显不是命名的东西,长命名一律照常拆。段数多时状态栏宽度会不够,可以把
localDictionary.statusBarMaxWidth 调大。
另外选中超过 64 个字符直接跳过查询。
这一层是逐词拼接,不是真正的句子翻译,语序不会调整(indexOf → 索引的)。
选段处在明确的编程语境里,因此优先采用 ECDICT 的 [计] 义项:user 取「用户」而非「使用者」,id 取「标识符」而非「遗传素质」,string 取「字符串」而非「线」。
选中单个词时问的是这个词本身的意思,改用通用义项并展示完整的一条释义,book 是「书, 书籍, 帐簿…」而不是「工作簿」。
自定义译词
ECDICT 是通用词典,不少编程高频词的译法不合习惯(get 是「得到」而非「获取」,render 是「回报」而非「渲染」),缩写词更是大量缺失(msg 查出来是「谷氨酸一钠」,ctx 是「环磷酰胺」)。
src/customDictionary.ts 里有两张表,直接改源码增删,改完 npm run compile 重新加载即可。
COMMON_TERMS(180 余条单词)在拼接标识符时优先于词典。查表会先用原词、再用构词规则还原后的形式,所以 users 能命中 user、handlers 能命中 handler、loadedModules 能命中 load。
COMMON_PHRASES(20 条词组)覆盖编程搭配,同时参与词组切分判定,所以词典没收录的 pull request 也能整体成段:
callBack → 回调 · 收回
rollBack → 回滚 · 回降, 卷回, 推回去
pullRequest → 合并请求
单选一个词时自定义译词显示在前面,词典释义跟在 · 后面补充(msg → 消息 · 谷氨酸一钠)。
配置
只有两项真正因人而异,其余都是源码里的常量。
| 键 |
默认 |
说明 |
localDictionary.enableCursorWord |
true |
无选中时翻译光标所在的词 |
localDictionary.statusBarMaxWidth |
40 |
状态栏显示宽度上限(汉字算 2) |
命令
本地词典:显示统计信息 —— 词条数、索引内存、缓存命中率、查询耗时 p50/p99、进程内存。点击状态栏条目也可打开。
p99 长期稳定在几十微秒说明页缓存保持热态;明显升高则说明缓存页被系统回收过。
本地词典:查询当前选中内容 —— 手动触发一次查询
打包与备份
npm run package # 测试并产出 vscode-local-dictionary-0.1.1.vsix(约 25 MiB)
vsix 自带编译好的词典(dict/ + out/),装到任何机器上都能直接用,不需要重新下载 ECDICT,也不需要重新构建:
code --install-extension vscode-local-dictionary-0.1.1.vsix
也可以在扩展面板右上角 ... → 「从 VSIX 安装」。
把这个 vsix 存一份就不用担心下载失败了——npm run fetch 要下载约 78 MB 原始数据,国内直连 GitHub raw 可能超时。三种备份体积对比:vsix 约 25 MiB(压缩过,装机即用)< dict/ 两个 bin 约 58 MiB < data/ 原始数据约 75 MiB。改了代码之后重新 npm run package 即可,词典数据不用重建。
开发
npm run compile # 编译
npm run watch # 监听编译
npm test # 构建固定小词典并运行全部测试,不依赖 data/ 与 dict/
npm run test:coverage # 同上,并输出覆盖率
npm run bench # 查询性能基准
测试使用 test/fixtures/ 中带 SHA-256 基线的固定数据,完整跑通“原始词典 → 二进制索引 → 查询 → 扩展激活”链路;缺少或损坏 fixture 会直接失败,不会静默跳过。GitHub Actions 会在 Node 18 上执行同一套覆盖率测试。
test/activation.test.cjs 用 vscode API 桩验证激活流程与选区处理,无需启动编辑器宿主。npm run package 还会检查版本一致性、正式词典规模和关键查询,再生成 VSIX。
许可
本扩展以 MIT 协议发布,见 LICENSE。
内置词典数据来自两个第三方项目,版权声明与许可证全文随包分发,见 THIRD-PARTY-NOTICES.md:
CC BY-SA 4.0 含相同方式共享条款,因此本扩展中由 CC-CEDICT 派生的词典数据同样以 CC BY-SA 4.0 授权。该条款只约束这部分数据,不影响源代码的 MIT 授权。
参考
以下做法借鉴自 program-in-chinese/vscode_english_chinese_dictionary(MIT):
| 借鉴点 |
出处 |
[计] 词性优先、清除释义括号注解、词性白名单 |
src/翻译/处理.ts 的 首选()、消除所有括号内容() |
| 自定义译词表与词组表 |
src/翻译/自定义词典.ts 的 常用命名、常用短语 |
| 查表前先做词形还原 |
src/查词.ts 里 取原型() 之后再查 常用命名 |
| 译文保留原文分隔符 |
src/查词.ts 的 逐词翻译() |
架构上则完全不同:该项目把 39 MB 词典写成 JS 对象字面量全量载入内存、activationEvents 用 *,本项目改为索引常驻 + 数据走页缓存。它也不支持含空格的词组查询(取字段中所有词() 遇到空格直接返回空数组),本项目做了最大正向词组匹配。
它的「省略号回填」(各释义[0].replace("...", 后续.join("")),用来修正「把...送交」这类模板释义的语序)没有采用:实测 6 万条抽样里首条义项含省略号的不到 1.5%,且几乎全是多词短语词条,在本项目的架构下会被词组匹配整体命中、走单段完整展示,不进拼接路径。