ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Vale:面向自然语言文本的Linter,用规则统一技术文档风格

Vale:面向自然语言文本的Linter,用规则统一技术文档风格 Vale 是一个面向自然语言文本的 Linter英文定位就叫 Linter for Prose。简单说它用命令行方式帮你检查散文、技术文档、博客文章里的用词、术语、一致性和风格问题而不是检查语法错误或者做排版。这个定位让它和拼写检查器、Markdown 格式化工具完全不一样。如果你写英文技术文档或者团队有明确的中英文写作规范又不想每次 review 都靠人工去抓“这个术语前后不一致”“这个词不该用”“那个表达太口语化”这类问题Vale 值得认真了解一下。这篇文章按我自己的落地顺序写先讲它到底适合解决什么问题再讲怎么安装、怎么配置、怎么写自己的规则最后是批量任务和实测中最容易踩到的坑。我不会把项目 README 复述一遍只会写我实际用下来觉得关键的环节。1. 先搞清楚 Vale 到底解决写作里的什么问题1.1 它不是拼写检查器也不是排版神器很多人第一次接触 Vale 会误以为它是“高级版拼写检查”。实际上它的定位更接近“基于规则的文本检查器”。拼写检查器解决的是“这个单词是否拼错了”排版工具解决的是“代码块缩进是否统一、空行是否一致”。Vale 更关心的是这句话里是不是用了某个团队禁用的词某个术语的大小写是不是统一某个动词的搭配是否更符合你所在领域的惯例。举几个典型场景文档里既有JavaScript又出现Javascript规则可以自动标记后者。团队要求避免使用utilize这类词统一写成use规则可以提醒。文案里出现whether if、in order to这类冗长或错误的表达规则可以建议替换。产品文档规定必须写Windows 11不能写成Win11规则可以校验。这类检查靠人工 review 也能做但问题是文档一多、团队一大人人工 review 很难保持标准一致。Vale 的价值就是把这些机械、可枚举的判断写成规则提交代码时自动跑一遍。顺便说一个它在工程上的好处Vale 是本地执行的命令行工具默认情况下检查的是本地文件不会把文档内容上传到别的服务。对内部文档和隐私要求较高的项目这个特性比在线语法检查工具更可控。1.2 适合谁不适合谁如果你属于下面这几类人Vale 会很有用技术文档工程师需要维护大量 Markdown、HTML、reStructuredText 文档。开源项目维护者希望 contributors 提交的文档能和项目风格保持一致。团队里有文档评审环节经常因为术语不统一、禁用词反复提意见。独立博主或写作者希望给自己建立一个固定的写作用词规范。如果你只是偶尔想检查一段英文的语法和拼写那在线工具可能更省事。Vale 本身不提供 AI 式的句子改写也不做语法树分析。它更像一个“白名单和黑名单管理器”你把约定写成规则它替你严格执行。还有一点需要提前理解Vale 默认只提供引擎不提供现成规则。你可以通过内置的样式包机制拉取一些社区维护的规则也可以自己写规则但不能装完就直接用。这个设计既是门槛也是它可定制的来源。2. 在电脑上把 Vale 跑起来安装和环境准备2.1 Windows / macOS / Linux 安装Vale 提供全局二进制安装方式取决于你的系统。macOS 且使用 Homebrew可以直接安装brew install valeWindows 如果使用 Chocolatey 或 Scoop也可以从包管理器安装例如choco install vale不想用包管理器也没关系。去它的 GitHub Releases 页面下载对应系统的压缩包解压后得到一个vale可执行文件把它放到PATH目录或者放指定目录后在命令里写全路径。安装完成后先确认命令可用vale --version能正常打印版本号说明环境没问题。后面所有配置都和这个命令联动所以这一步别跳过。2.2 验证命令和最小示例Vale 不是装完就能检查文本的。它要求目录里有一个.vale.ini配置文件并且配置文件里指定的样式目录存在。如果直接对没有配置的目录执行会提示缺少配置或样式。我建议把第一次尝试拆成三步建目录、放配置、跑一个测试文件。先创建一个临时目录mkdir vale-demo cd vale-demo在目录里新建一个最简单的.vale.iniStylesPath styles MinAlertLevel suggestion [*.md] BasedOnStyles Demo再创建样式目录和测试文件mkdir -p styles/Demo touch styles/Demo/example.yml touch test.mdtest.md里随便写一段英文This is a demo document for testing Vale.然后运行vale test.md如果styles/Demo/example.yml是空文件Vale 会认为该目录下没有可用的规则输出会显示“没有发现问题”或者提示规则为空。这很正常因为规则还没写。2.3 文件格式和第一份配置Vale 默认支持常见文档格式包括 Markdown、HTML、LaTeX、AsciiDoc、reStructuredText、纯文本等。它会根据文件扩展名自动判断解析方式。如果你项目的文档不是默认扩展名可以在配置里加一个[formats]段做映射[formats] myext md这样.myext文件会按 Markdown 解析。这里有个容易忽略的点Vale 的配置是分作用域的。[*.md]表示只对 Markdown 文件启用后面的规则但如果不加[*.md]而直接写BasedOnStyles通常对所有文件生效。实际项目中我建议按文件类型区分因为技术文档和 HTML 页面的写法规范往往不一样。.vale.ini里几个核心字段需要先理解StylesPath规则目录路径也就是存放样式文件的目录。MinAlertLevel最低告警级别可以是suggestion、warning、error。Vocab项目词汇表用于处理人名、产品名、专有名词。Packages需要从远程拉取的样式包列表。[*.md]glob 匹配模式指定规则作用于哪些文件。基础配置不需要一次全部写满先跑通最小集更好。3. 配置 .vale.ini把规则目录和检查范围理清楚3.1 StylesPath 和基础字段StylesPath是 Vale 最核心的配置。它指向一个目录里面放所有.yml规则文件和Vocab词汇目录。路径可以用相对路径也可以写绝对路径。我习惯用相对路径比如项目根目录下的styles目录这样对应仓库迁移时配置不会失效StylesPath styles如果你的团队成员各自 clone 项目路径是相对项目根的维系列表就少踩坑。MinAlertLevel的作用是过滤告警级别。比如MinAlertLevel warning那么suggestion级别的提示就不会输出。这个字段很适合刚引入 Vale 时使用。团队第一次接入可以先只输出error避免一堆 suggestion 刷屏等大家接受之后再把级别放开。BasedOnStyles的作用是快速加载某个样式目录下的所有规则。比如[*.md] BasedOnStyles DemoVale 会加载styles/Demo下的所有.yml文件。这个机制的好处是不用每条规则单独列坏处是目录里的规则如果没整理好可能误伤很多文档。如果你只想启用某几条规则不推荐无脑加载整个目录。可以改成[*.md] Demo.禁用词 YES Demo.术语一致性 NO这里Demo是样式目录名禁用词和术语一致性是目录里的规则文件名。实际使用时规则名建议用英文或拼音避免不同终端在文件名处理上出问题。3.2 按文件类型启用规则我给文档项目做配置时通常会区分几个文件类型[*.md] BasedOnStyles Demo [*.html] BasedOnStyles Demo Demo.html-specific YES [*.txt] BasedOnStyles Demo Demo.术语一致性 NO这种写法适合一个仓库里同时存在多种文档格式的情况。比如md是给开发看的文档html是给外部用户看的帮助页面两者的用词和语气可以分开控制。值得注意的是 glob 匹配是走 Vale 自己的文件匹配逻辑。[*.md]匹配根目录下的 md 文件[docs/**/*.md]匹配docs目录下的 md 文件。如果你在子目录里跑vale .全局文件都会按对应段配置检查。配置的优先级是这个阶段最容易混乱的地方同一类文件同时命中多个配置段时更具体的匹配会覆盖通用配置。如果某条规则意外没生效先看是否被更具体的配置段关闭了。3.3 Vocab 处理人名、产品名和术语Vocab是 Vale 处理专有名词和术语的机制。它解决的核心问题是规则里标记了某个词是错的但文档里确实需要出现这个词怎么办。词汇表目录结构如下styles/ Vocab/ MyDocs/ accept.txt reject.txt在.vale.ini里声明使用这个词汇表Vocab MyDocsaccept.txt里放允许出现的词VSCode TypeScript JavaScript GitHubreject.txt里放强制不允许出现的词VSCode Typescript Javascript Jscript这个机制配合spelling类规则很好用内置的拼写规则会认为不在词典里的词是拼写错误accept.txt相当于给拼写规则加白名单而reject.txt明确列出即使拼写正确也不允许使用的形式。实际项目中我建议把产品名、人名、缩写、团队内部叫法都维护到accept.txt。这样规则报错时你一眼就能看出是真正的错误还是专有名词没登记。注意Vocab 不是万能开关。如果你没有启用任何与拼写相关的规则reject.txt 不会自动检测。它是在规则引擎读取单词时参与候选判断的不是独立检查器。4. 用手写一个样式文件来理解 Vale 的规则机制4.1 YAML 规则的核心字段规则文件是 YAML 格式每个文件通常代表一条规则。一个最简单的existence规则长这样extends: existence message: 不要使用 %s。 level: warning ignorecase: true tokens: - very - really - basically这种规则表示只要文本中出现very、really、basically这些词就产生一条 warning 级别的提示。message里的%s会被替换成实际匹配到的文本。字段含义extends规则类型。message告警时输出的提示文字。level告警级别可以是suggestion、warning、error。ignorecase匹配时是否忽略大小写。tokens需要匹配的词或正则表达式。scope检查范围常见取值有text、sentence、heading等。scope的作用很关键。比如你想只检查标题里有没有某个词就写extends: existence message: 标题里不要使用 %s。 level: error scope: heading tokens: - TODO这样正文里出现 TODO 不会报警只有标题里出现才会提示。这种细化能让规则更精准避免误报。4.2 从 existence 到 substitutionexistence只能检测某个词是否存在适合“禁用词”场景。但更多时候你希望不仅提示“这个词不对”还要告诉作者“应该改成什么”这时候用substitution类型的规则。一个典型例子extends: substitution message: 建议使用 %s不要使用 %s。 level: warning swap: utilize: use a lot of: many in order to: toswap是一个映射表左边是应该避免的词右边是建议替换的词。Vale 在匹配到utilize时会输出一条替换建议且提示文本里会带上两个词。这种规则特别适合团队术语表落地。比如禁止使用click on要求使用click。禁止使用login作为名词要求使用log in。禁止使用info要求使用information。每一条都可以写成swap里的一个映射积累一段时间后一份很厚的术语表就变成了一套可自动执行的规则。existence和substitution是写规则时最常用的两种先把它们用熟比堆很多复杂类型更有价值。4.3 用 occurrence、conditional 处理上下文existence只能判断是否存在无法判断“出现几次”和“前后文关系”。如果你希望限制某个词的出现次数比如一个句子里however最多出现一次可以写occurrence类型规则extends: occurrence message: 不要在一句话里使用超过一次 %s。 level: warning scope: sentence max: 1 tokens: - howeveroccurrence会统计tokens在指定scope内出现的次数超过max时触发提示。这类规则适合处理“用词重复”或者“某一类连接词过密”的问题。如果你需要处理“前面出现了某个词后面就不能出现另一个词”的场景可以看conditional类型规则。它的用途是表达上下文限制比如“如果标题里出现了will后面就不要跟着be able to”。这类规则的字段会比 existence 多一点常见的是first、second、exceptions。实际使用中我会先手写一个简单的 existence 规则验证思路再慢慢换成 conditional。原因是 conditional 涉及前后顺序和匹配范围调起来更容易遇到边界问题。把这个机制想明白之后你就会发现 Vale 的规则不是一成不变的死字典而是可以表达比较复杂判断的检查器。理解了这个后面批量接入就不慌了。5. 从单文件检查到批量文档与 CI 集成5.1 命令行批量操作和输出格式Vale 最简单的用法是检查单个文件vale test.md也可以一次检查多个文件vale docs/api.md docs/guide.md目录检查更常用vale docs/如果要匹配某个目录下的所有 Markdown 文件建议加引号防止 shell 先展开vale docs/**/*.md批量任务里我一般会在命令最后加上--no-wrap避免输出被终端宽度自动换行一方面看起来乱另一方面不方便复制告警内容。Vale 还支持不同输出格式。默认输出是适合人看的格式但在脚本里解析不好用。如果你想把检查结果接到自己的流程里可以输出 JSONvale --outputJSON docs/JSON 结果包含文件路径、行号、列号、规则名、消息、级别等信息。这样无论是给 CI 做统计还是给内部工具做展示都方便。如果想在脚本里只关心错误级别可以覆盖配置里的最低告警级别vale --min-alert-levelerror docs/这样只输出 error 级别的告警suggestion 和 warning 一律忽略。CI 阶段用这个命令最合适。5.2 编辑器插件与本地反馈命令行适合批量跑和 CI但写文档时最好还是在编辑器里直接看到提示。Vale 官方提供 VS Code 扩展。安装后它会在你打开项目时读取.vale.ini并在编辑 Markdown 文件时不断给出告警。效果很像代码编辑器里的 lint 提示哪一行有问题鼠标放上去就能看到规则说明。我用下来觉得编辑器插件的最大价值是规则能从“CI 报错”变成“写的时候就知道”。尤其是新成员不熟悉团队写作规范时边写边被提示能减少大量返工。如果你用的不是 VS Code也可以通过命令行和编辑器任务机制接入。具体能不能做到最低延迟要看你编辑器的任务运行方式但 Vale 的命令行接口足够小接入并不复杂。5.3 CI 中配置 Vale 的通用思路把 Vale 接入 CI是让团队统一写作规范的最关键一步。没有 CI 强制执行本地跑不跑全看个人自觉。基础流程是安装 Vale。拉取或检查样式包。运行 Vale 检查文档目录。根据退出码判断是否中断流水线。GitHub 项目里官方提供errata-ai/vale-action可以直接在 workflow 中使用。通用的做法是让 action 读取项目根目录下的.vale.ini检查docs/目录并将注释写回 PR。如果你不用 GitHub也完全可以自己在 Jenkins、GitLab CI 里跑命令。核心就三步vale sync vale docs/vale sync会根据.vale.ini里的Packages字段拉取远程样式包。如果团队不需要远程包只使用本地 styles 目录这一步可以跳过。CI 接入有个建议第一次不要开全部规则。哪怕你已经写了很多规则也先只用warning级别跑几天让团队成员理解和适应规则再慢慢收紧。规则质量远比规则数量重要一堆误报很容易让大家对 Vale 失去信任。6. 实测时最容易踩的几个坑6.1 默认配置不够用包也要有取舍Vale 安装后并没有内置任何文本规则。这意味着你需要自己提供样式或者从样式仓库拉取别人维护的规则。常见的做法是在.vale.ini里配置Packages然后执行vale sync拉取。比如引入一些社区维护的英文写作风格包。这些包的好处是开箱即用坏处是规则噪音比想象中大。我自己实测的感受是不要一次引入太多包。两个风格包叠加经常会出现同一句话报三四个不同建议里面一半是“可以用更好表达”这类主观提醒对团队没有实际约束力反而让真正需要关注的 error 被淹没。建议选一个包跑完整批文档把误报规则关掉或降级再决定要不要引入第二个包。6.2 中文场景的边界Vale 面向英文散文设计对中文的支持是有边界的。这一点在接入前就要想清楚。中文文本的问题是英文按空格分词Vale 的很多默认 scope 和词边界逻辑依赖空格和标点。中文没有空格句子拆分会变得不确定。如果你写一条规则要求“一句话中不能出现某个词超过一次”对中文文档可能不会按预期触发。但这不意味着中文场景完全不能用。像“禁用词”“术语统一”“需要改为指定写法”这类基于 token 的检查中文也能跑。前提是规则里直接写中文 token并保存为 UTF-8 编码extends: existence message: 文档中不要使用 %s。 level: error tokens: - 非常 - 我们 - 请注意还要注意Vale 的正则引擎支持一些 Unicode 属性但不要指望它做中文分词和句法分析。如果团队文档以中文为主我建议把 Vale 定位成“术语和禁用词检查器”不要拿它当完整的中文语法检查工具。6.3 先看日志和退出码再改规则接入过程中遇到问题先别急着改规则。Vale 的报错一般分几类配置找不到、样式目录不存在、规则文件名对不上、规则语法错误。我的排查顺序是先确认vale --version正常。检查当前目录是否存在.vale.ini以及字段拼写是否正确。确认StylesPath指向的目录真实存在。运行单个测试文件并用--outputJSON看完整输出。如果规则没有生效检查规则文件名和你配置里引用的名字是否完全一致。如果规则报语法错误单独打开.yml文件检查 YAML 缩进和引号。一个很常见的坑是在.vale.ini里写了BasedOnStyles Demo但实际目录名是demo大小写不一致。Vale 在区分大小写的系统上会直接找不到样式。另一个常见问题是规则文件里用到了正则特殊字符比如*或.结果匹配范围比预期大很多。此时建议在 tokens 里给特殊字符加转义或者先用一个非常简单的 token 验证规则路径通不通。记得先造一个一定能命中的测试文本再验证规则是否真正触发。很多时候规则没报错不是配置问题而是测试文本里根本没有规则要匹配的词。7. 更进一步的规则把团队自己的写作规范沉淀成 Vale 样式7.1 从风格手册到 YAML 规则团队如果已经有人工维护的文档风格手册那 Vale 规则可以直接从手册里提取。比如手册里写着“不要使用 please kindly 这种过于客套的表达”就可以转成一条 existence 规则。写着“产品名称统一使用DataSync不要使用Datasync或data sync”就可以转成 substitution 规则。我建议按优先级分三批整理第一批硬性错误。拼写不一致、产品名写错、严重禁用词。这些规则直接设为error。第二批风格偏好。冗长表达、口语化表达、建议替换的搭配。这些规则先设为warning让作者自己决定是否修改。第三批需要上下文的检查。比如标题不要用某些词、正文某类词出现次数不能过多。这些规则比较敏感需要更多测试再启用。分批的好处是能控制告警数量。如果第一次就导入 80 条规则文档满屏飘红团队成员很难接受。7.2 维护和版本管理Vale 的配置和规则本质上是文本文件完全可以纳入 Git 仓库管理。我建议把.vale.ini和整个styles/目录放在文档项目根目录这样任何 clone 项目的人都能得到相同的规则。当规则越来越复杂后可以考虑为规则单独建立仓库然后用 Vale 的Packages机制按版本拉取Packages https://github.com/your-org/vale-styles然后执行vale sync这样文档项目只需要维护一份配置规则升级走单独仓库更适合中大型团队。规则的变更也应该像代码一样走 review。每次增加或修改规则时最好附上一条能命中的测试文本和一条不应该命中的文本。比如# good: Please read the guide. # bad: Please kindly read the guide.这种注释看起来简单但后面维护的人看一眼就知道这条规则的意图和边界。7.3 让 Vale 成为文档评审的一部分而不是替代最后说一个我比较深的体会Vale 再强也只能替代文档评审里的机械部分。真正需要人判断的问题比如结构是否合理、内容是否准确、读者是否能理解这些它做不了。但把术语、拼写、禁用词、风格偏好这些是是而非的问题交给 Vale 处理之后人工 review 的时间可以更集中在内容本身。我实践下来的路径是先跑一个最小配置只检查最重要的几十个词用几天时间观察误报率然后把确定性的规则提升到error接入 CI再根据团队反馈慢慢扩充规则集。这个节奏比一开始就配一个超全的规则包要舒服很多。如果你正准备在项目里引入 Vale我建议你也从最小集开始跑通一个文件再铺开。Linter 的价值不在于规则多而在于每一条规则都稳定、可解释、真的对团队有帮助。
返回列表