技术解读
把拼写检查从“语言问题”变成“数据问题”:wooorm/dictionaries 深度剖析
项目背景与痛点
拼写检查看起来是个小功能,落到工程上却是一连串的麻烦事。业界事实标准是 Hunspell——LibreOffice、Firefox、macOS 的拼写服务背后都是它。但 Hunspell 的词典生态长期停留在“桌面软件资源包”的状态:编码五花八门(ISO-8859-1、ISO-8859-2、KOI8-R 比比皆是),目录结构随手命名,许可证散落在各个上游仓库,想在现代 JS 工程里直接用,几乎必然踩坑。
wooorm/dictionaries 切中的正是这个断层。它本身不是拼写引擎,而是一个词典数据的 monorepo 与分发流水线:把各语言的上游 Hunspell 词典收集起来,统一转成 UTF-8,规范化为 index.aff + index.dic 的固定结构,再按语言拆成 dictionary-en、dictionary-de 这样的独立 npm 包。一句话概括它的价值:它把“支持某语言的拼写检查”从一项调研任务,降级成一次 npm install。
核心技术揭秘
理解这个项目,要先理解 Hunspell 词典的双文件模型:
.aff是规则文件,声明字符编码(SET)、词缀标志类型(FLAG long/num/UTF-8)、前缀后缀规则(PFX/SFX,含剥离串、添加串与适用条件)、复合词规则(COMPOUNDMIN、COMPOUNDRULE)、替换建议(REP)等;.dic是词条文件,每行一个词根加一组标志位,标志位指向.aff中的规则,从而“展开”出成千上万的屈折形式。
因此词典的体积远小于其表达能力——英语词典不过几万词根,却能覆盖数百万词形。这也解释了为什么一个语言包通常只有几百 KB 到几 MB。
项目的技术含量集中在流水线上,而非某个算法。其数据流大致如下:
这个流程里最容易被低估的是编码转换。Hunspell 的 SET 指令与文件字节必须严格一致,否则 ä、ñ、西里尔字母会整体错位;土耳其语的 İ/i 大小写映射、荷兰语的 ij 连字,还会在转换中暴露断词与大小写折叠的边缘情况。项目选择“全部 UTF-8 化”,本质上是用一次性成本换掉下游所有平台的编码适配成本——这是它最务实的设计决策。
另一个隐性难点是许可证治理。不同上游词典分别采用 LGPL、MPL、GPL、BSD 等许可,monorepo 必须逐包记录来源与授权,否则下游商用会踩雷。每个 dictionary-* 包都随附 license 文件,正是为此。
功能亮点与差异
第一,数据与引擎解耦。 这是它和“直接调用系统 Hunspell”的根本区别。词典包不绑定运行时,你可以选 C++ 绑定的 Nodehun 追求吞吐,也可以选同作者的纯 JS 实现 nspell 追求零编译、跨平台、可进浏览器。同作者维护引擎与数据,语义对齐的摩擦被压到最低。
第二,语言级细粒度分发。 不支持“一个大包塞进所有语言”。你需要英语就装 dictionary-en,需要德语再装一个,天然契合按需加载与前端体积控制。
第三,可复现的自动化。 词典不是手工堆进去的,而是脚本抓取、转换、生成 README 后发布,上游更新能低成本跟进,版本可追溯。
第四,UTF-8 一致性。 相比直接扒上游资源包,它消灭了“为什么某些词永远拼不对”这类幽灵 bug。
应用场景与落地建议
适合的场景很明确:文档编辑器与 Markdown 工具的拼写提示(retext-spell 一类插件)、CMS 与工单系统的输入校验、多语言 SaaS 的辅助输入、以及离线优先的桌面/移动端应用。
落地时有几点必须注意:
- 体积与加载策略。词典动辄数百 KB,前端务必懒加载或放进 Web Worker,别塞进首屏 bundle。
- 引擎选型。Node 服务端追求性能用 Nodehun,但要接受原生模块编译与 CI 交叉构建的代价;浏览器或 Serverless 环境优先
nspell。 - 词典质量不均。小语种词典的词覆盖与规则完备度差异很大,专业术语(医学、法律、品牌名)基本一定要叠加自定义词典。
- 许可证合规。上生产前逐包核对 license,尤其 GPL 系词典混入商业闭源产品会有风险。
- 版本锁定。词典会随上游更新,拼写结果可能随版本漂移,测试用例里要固定版本。
综合评价
优点:定位极其克制——只做数据不做引擎,反而获得了最大的复用面;UTF-8 统一与规范化目录解决了真实痛点;语言级 npm 包粒度合理;自动化流水线保证了可维护性与可追溯性;与 nspell 的组合提供了罕见的“纯 JS 全链路”选项。
缺点:它是数据仓库,不是解决方案——词形还原、分词、上下文纠错一概不管,CJK 等无空格语言基本帮不上忙;各语言词典质量参差且不受本项目控制;上游许可证复杂,商用需要额外法务工作;文档偏向“包说明”而非“集成指南”,初次接入仍需自行摸索引擎侧的规则支持度。
一句话:如果你的产品需要“靠谱的多语言拼写检查数据源”,这是目前 JS 生态里最省事的起点;如果你期待它替你把拼写检查做完,那你会失望——但它本来也没打算这么做。
评论