作者:
    Creation:2026-08-12Last update:2026-08-13

    ESLint x OXLint 插件

    eslint-plugin-intlayer 能够捕获 TypeScript 无法发现的几类 i18n 错误:

    1. 硬编码文本:从未写入字典中的文本。
    2. 动态调用:能够通过类型检查并正常运行,但 Intlayer 编译器无法进行优化的调用。
    3. 死内容(Dead content):项目中没有任何地方读取的字典和字段(需手动开启)。

    未知的字典键、未知的字段路径和缺失的语言环境本身已是编译错误,因此插件不会重复报告它们。

    安装

    bash
    npm install --save-dev eslint-plugin-intlayer

    需要 ESLint 9 或更高版本(Flat config)。支持 ESLint 10。

    使用方法

    该插件可在 ESLint 和 oxlint 中运行 — 拥有相同的规则和配置选项。

    或者展开某个配置并自行设置严重级别:

    预设配置

    配置 no-raw-text static-dictionary-key no-dynamic-field-access enforce-adapter-import no-unused-content
    recommended warn error error off off
    strict error (+ 非 JSX 字面量) error error error off
    contract-only off error error off off

    recommended 特意将 no-raw-text 设为 warn:将其指向现有代码库会一次性暴露所有未翻译的字符串,这不应该在第一天就导致构建中断。

    enforce-adapter-import 默认关闭 — 如果需要请显式启用。

    no-unused-content 在所有配置中均默认关闭(包括 strict)。这是唯一一个需要读取 Intlayer 配置并从磁盘遍历源文件的规则,因此启用它应当是一项经过深思熟虑的选择,而非预设自动执行的行为。

    规则列表

    no-raw-text

    报告未在字典中声明的面向用户的文本。它使用与 intlayer extract 相同的检测逻辑,因此品牌名称、CSS 类名和技术标识符都会被忽略。

    jsx
    // ✗ 报告错误<h1>Welcome to our documentation</h1><input placeholder="Enter your email address" />// ✓ 正常const { title } = useIntlayer("home");<h1>{title}</h1>

    内容声明文件(*.content.ts, …)会被跳过。

    若要一次性修复整个文件,运行 npx intlayer extract,让编译器自动将字符串移入字典。

    配置选项

    static-dictionary-key

    要求字典键必须是字符串字面量。

    编译器只有在调用位置直接读取到键时,才能预加载字典。使用计算键会静默跳过优化,转而打包所有字典。

    typescript
    // ✗ 报告错误useIntlayer(dictionaryKey);useIntlayer(`home-${suffix}`);getTranslations({ namespace: page });// ✗ 变量仍然不是字面量const key = "home";useIntlayer(key);// ✓ 正常useIntlayer("home");getTranslations({ namespace: "home" });

    这适用于 useIntlayergetIntlayer 以及所有兼容适配器(useTranslationuseTranslationsformatMessage<FormattedMessage id><Trans i18nKey> 等)。

    no-dynamic-field-access

    要求从字典中读取的字段必须是静态已知的。

    编译器会移除它未检测到使用的字段。动态计算访问对其不可见,因此该读取在运行时可能会返回 undefined

    typescript
    // ✗ 报告错误const content = useIntlayer("home");content[fieldName];const t = useTranslations("home");t(messageKey);// ✓ 正常content.title;content["title"];content.items[0];t("hero.title");

    enforce-adapter-import

    优先使用 @intlayer/* 兼容适配器而非原始包。原始包仅在配置了打包工具别名时才会解析为 Intlayer;而适配器始终生效。可通过 --fix 自动修复。

    typescript
    // ✗ 报告错误import { useTranslation } from "react-i18next";import { getTranslations } from "next-intl/server";// ✓ 正常import { useTranslation } from "@intlayer/react-i18next";import { getTranslations } from "@intlayer/next-intl/server";

    no-unused-content

    默认关闭。 报告项目中没有任何地方读取的内容,以及在多个位置声明的字典键。

    src/home.content.ts
    export default {  key: "home", // ✗ 当项目中没有任何调用方请求 "home" 时报告  content: {    title: t({ zh: "标题", en: "Title" }),    // ✗ 当没有任何地方读取 `hero` 时报告    hero: {      subtitle: t({ zh: "副标题", en: "Subtitle" }),    },  },};

    与其他规则不同,此规则无法仅凭眼前的文件给出判断 — 字段是否未使用仅相对于整个项目而言。在一次 lint 运行的首次内容声明时,它会加载你的 Intlayer 配置,匹配该配置声明的源文件(build.traversePatterncompiler.transformPattern),并运行驱动 @intlayer/lsp 和 VS Code 扩展中“未使用”删除线的同一套使用情况分析器。结果会缓存 cacheTtl 毫秒,因此每次运行只会扫描一次,而不是每个文件扫描一次。

    配置选项

    如果你在长期运行的编辑器服务中进行 lint 且希望更快看到修改结果,可以降低 cacheTtl;当单次 lint 运行跨越 monorepo 中的多个 Intlayer 项目时,请设置 baseDir

    倾向于保持沉默。 此处的误报会导致翻译被误删,因此当字典以分析器无法跟踪的方式被使用时,不会报告任何内容:内容对象被整体传递、从中绑定的翻译函数(const t = useTranslations("home"))、通过直接导入访问的声明(useDictionary(myDictionary))、来自另一个字典的 nest()、或者因 spread 展开而不详尽的字段列表。单文件组件(.vue.svelte.astro)计为使用了它们提及的字典中的所有字段,因为它们的脚本块在此处不会被解析。

    reportDuplicateKeys 读取构建时写入 .intlayer/ 下的未合并字典,因此在项目至少构建过一次之前它会保持静默。共享一个键的两个声明会被合并,这是一种合法的模式 — 该报告之所以存在,是因为在两边同时定义的字段会静默保留两个值中的一个。

    分析器从以 ESM 形式分发的 @intlayer/lsp 中加载。因此该规则需要能够 require() ES 模块的 Node 版本 — Node 20.19+ 或 22.12+。在更低版本上,它不会报错中断 lint 运行,而是什么都不报告。

    框架支持

    每条规则均适用于所有 Intlayer 集成,包括 Vue、Svelte 和 Angular 模板内部。你只需告诉 ESLint 哪个解析器负责读取对应的文件类型即可。

    框架 文件 解析器
    React, Preact, Solid, Lit .jsx .tsx typescript-eslint
    Next.js .jsx .tsx typescript-eslint
    Vue, Nuxt .vue vue-eslint-parser
    Svelte, SvelteKit .svelte svelte-eslint-parser
    Angular .ts typescript-eslint
    Angular 模板 .component.html @angular-eslint/template-parser
    Astro .astro astro-eslint-parser

    请仅安装项目所需的解析器。

    已知局限性。 在 Vue 和 Angular 模板中,类似于 {{ content[key] }} 的表达式不会被 no-dynamic-field-access 检查。写在 script 块中的动态读取仍会被正常捕获。