ESLint

@ai-i18n/eslint-plugin 用于尽早发现不可翻译的参数、内嵌静态 markup 的翻译源文、不会随语言 切换更新的文案,以及不必要的显式导入。它不会修改你的翻译文件。

安装

npm
yarn
pnpm
bun
deno
npm install -D eslint @ai-i18n/eslint-plugin@alpha
Alpha 阶段

预发布期间请显式安装 @alpha。插件支持 ESLint 9 和 10。

pnpm monorepo 应将插件安装在实际加载 eslint.config.* 的 workspace 中。例如从仓库根目录加载 配置时,运行:

pnpm add -Dw @ai-i18n/eslint-plugin@alpha

Vue 项目还需要保留现有的 eslint-plugin-vuevue-eslint-parser@vue/compiler-sfc

使用显式导入

未开启 ai-i18n 自动导入时,Vanilla 和 React 项目使用 recommended

// eslint.config.mjs
import aiI18n from '@ai-i18n/eslint-plugin';
import { defineConfig } from 'eslint/config';

export default defineConfig([...aiI18n.configs.recommended]);

Vue 项目使用 vue

export default defineConfig([...aiI18n.configs.vue]);

将这份配置与项目已有的 Vue Flat Config 一起使用。ai-i18n 不会替代 Vue 自身的解析器和规则。

使用自动导入

aiI18n({ autoImport: true }) 时,选择与 Vite 框架模式相同的预设:

// eslint.config.mjs
import aiI18n from '@ai-i18n/eslint-plugin';
import { defineConfig } from 'eslint/config';

export default defineConfig([
  ...aiI18n.configs['vanilla-auto-import'],
  // Vue:...aiI18n.configs['vue-auto-import']
  // React:...aiI18n.configs['react-auto-import']
]);
项目使用的预设
Vanillavanilla-auto-import
Vuevue-auto-import
Reactreact-auto-import

这些预设会声明对应的 ai-i18n 全局 API,并检查其使用方式。生产配置和测试配置的 autoImport 值应保持一致。Vue 与 React preset 同时声明基础 Runtime API 和框架专属 API。

Monorepo 子包

子包不需要因为被 Vite 应用消费而重复注册 @ai-i18n/vite。但 ESLint 配置取决于实际执行 lint 的位置:

  • 仓库根 eslint.config.* 已覆盖 packages/** 时,只需在根配置使用一次对应 preset。
  • 子包拥有独立 eslint.config.* 或独立 lint 命令时,该配置也必须引入相同 preset。
  • 开启自动导入时,子包使用的 preset 必须与消费它的 Vite build 框架模式一致。

可复用子包更适合显式导入 virtual:ai-i18n 并使用普通 vuerecommended 等显式导入 preset,避免绑定到某个应用的自动导入约定。

JavaScript 项目的路径别名

纯 JavaScript 项目不需要为了 ESLint 路径解析额外创建 tsconfig.json。如果项目已在 Vite 中配置对象形式的本地源码 alias,可以导出同一个对象,并传给 ai-i18n 的 ESLint settings:

// aliases.js
import { fileURLToPath } from 'node:url';

export const alias = {
  '@': fileURLToPath(new URL('./src', import.meta.url)),
};
// vite.config.js
import { defineConfig } from 'vite';
import { alias } from './aliases.js';

export default defineConfig({
  resolve: { alias },
});
// eslint.config.js
import aiI18n from '@ai-i18n/eslint-plugin';
import { defineConfig } from 'eslint/config';
import { alias } from './aliases.js';

export default defineConfig([
  ...aiI18n.configs.recommended,
  {
    settings: {
      'ai-i18n': { alias },
    },
  },
]);

replacement 必须使用绝对路径。显式 alias 的匹配结果优先;未匹配时,插件会继续查找 tsconfig.jsonjsconfig.json。插件不会加载或执行 vite.config.*。支持范围与查找顺序见 ESLint 规则参考

常见问题

为什么 t() 参数报错

t() 只接受能在构建时确定的文案。优先使用字符串、静态 const 或条件表达式:

t('保存');

const label = '取消';
t(label);

t(canSubmit ? '提交' : '返回');

需要按索引读取一组文案时,使用 defineI18nMessages()。完整示例见 通用文案写法

为什么 React 组件中的 t() 提示不会更新

React 组件要使用 useI18n() 返回的 t,不能在渲染路径直接使用顶层 t

function SaveButton() {
  const { t } = useI18n();
  return <button>{t('保存')}</button>;
}

Vue template、render 与 computed 可以直接使用顶层 t(),它会追踪 Vue adapter revision。不要在模块初始化、state、storage 或业务数据中长期保存已经翻译的字符串。Vue setup 中需要预先声明响应式展示文案时,使用 tRef()。纯 Options 组件使用 tComputed() 时,应把它直接写成 computed 属性值;放在 data()、template、render 或模块级变量中会得到 getter 而不是译文,规则会报告该用法。纯 Options data() 直接保存 t() 结果也只会保留初始化译文,应改用 tComputed() 或执行时调用 t()

关闭自动导入时,纯 Options template 直接调用显式导入的 t(),需要在 methods 中建立 t binding;规则也识别改名导入映射。开启自动导入后,无需 methods: { t },规则会直接 检查 script 和 template 中未绑定的 t()。本地同名 method 仍然遮挡自动导入。脚本内使用 词法作用域中的 t()this.t()this.$t() 不属于静态提取写法。

getLang()getLangLoadState() 同样返回快照。组件展示当前语言或加载状态时,使用 Composition API 的 useI18n();纯 Options 组件则在 computed 中展开 ...i18nComputed()。普通 setup() 或 Options data() 保存快照会收到提示; i18nComputed() 放在 setup、data、methods、render 或 template 也会提示改回根 computed。在 action、事件处理器或工具函数中按需读取 Runtime 快照不受限制。

为什么显式导入提示多余

自动导入预设默认兼容显式导入。如果团队希望统一使用自动导入,可额外开启 no-redundant-auto-import,并执行 eslint --fix。规则选项和适用范围见 ESLint 规则参考

诊断语言

ESLint 与 Vite 的开发者诊断默认按系统时区显示中文或英文。需要固定语言时,设置:

AI_I18N_DIAGNOSTIC_LOCALE=zh-CN
AI_I18N_DIAGNOSTIC_LOCALE=en-US

设置为 auto 可恢复自动选择。该环境变量只影响提示文字,不影响规则结果。

下一步