ESLint 规则参考
本页面向需要自定义 ESLint 行为的项目。常规接入请先阅读 ESLint。
规则总览
官方预设已经注册适用规则。需要调整默认值时,先引入对应预设,再覆盖目标规则。下面以
recommended 为例:
import aiI18n from '@ai-i18n/eslint-plugin';
import { defineConfig } from 'eslint/config';
export default defineConfig([
...aiI18n.configs.recommended,
{
rules: {
'ai-i18n/static-candidate-limit': ['warn', { maxStaticCandidates: 2000 }],
},
},
]);
通用规则
t-static-args
检查 t()、Vue tRef()、tComputed(),以及 useI18n() 返回的 t。source 必须能在构建
阶段确定;options 必须是仅包含 comment 的静态对象。动态字符串、不支持的调用形式和不推荐的
集合成员引用会报错。
no-embedded-markup
检查 t()、tagged template、Vue tRef()、tComputed() 以及 useI18n() 返回的
t。规则分析最终可提取 source;直接字符串、静态 const、条件候选和文案树共用同一口径。
下列写法会收到 warning:
t`<div>温度:<span style="color:${color}">${temp}℃</span></div>`;
处理原则、推荐写法和 HTML 插值的安全边界见
通用文案写法。规则不限制长文案、多行文案、
占位符数量、条件候选或文案树规模,也不检查仅在插值运行时值中出现的 HTML。
第一版不识别 JSON、URL、SQL 或 Shell,也不把纯 Markdown 语法视为 markup。
no-eager-translation
检查模块初始化或组件初始化期间保存的 t() 结果。长期保存的译文不会随语言切换更新。普通
函数和 getter 在执行时重新调用 t(),因此可以使用。Vue setup() 与 Options data() 的
额外检查见下方 Vue Tab。
这条规则不代表文案无法提取,而是提醒“提取成功”和“切换语言后刷新”是两件事。例如图表配置、
路由标题等长生命周期对象,不要在模块加载时保存译文快照:
// warning:模块加载时只翻译一次
export const chartOptions = {
title: { text: t('销量') },
};
// 允许:在创建或重建图表时读取当前语言
export function createChartOptions() {
return {
title: { text: t('销量') },
};
}
工厂函数需要在首次渲染和语言变化后重新调用;如果调用方仍只在初始化时执行一次,结果仍然不会
刷新。有限的集中式标题集合可以先声明文案,再在实际取值时翻译:
const ROUTE_TITLES = defineI18nMessages({
detail: '详情',
edit: '编辑',
});
export function getRouteTitle(name: keyof typeof ROUTE_TITLES) {
return t(ROUTE_TITLES[name]);
}
Vue setup 中需要长期持有单个译文时使用 tRef();纯 Options API 在根 computed 中使用
tComputed()。模板、render、computed getter、事件处理器和普通延迟函数可以在执行时直接
调用 t()。
部分第三方配置允许把文案写成函数,例如表单校验规则。此时优先使用第三方 API 提供的延迟
回调,不要为了消除 warning 改回固定的源语言字面量:
const passwordRules = {
userPassword: {
required: true,
// warning:初始化时保存译文快照
message: t('请输入旧密码'),
},
};
const lazyPasswordRules = {
userPassword: {
required: true,
// 允许:校验产生错误时读取当前语言
message: () => t('请输入旧密码'),
},
};
只有第三方 API 明确支持函数值时才能使用这种写法;否则使用工厂函数或框架提供的响应式 API。
no-unsubscribed-runtime-state
检查 getLang() 与 getLangLoadState() 返回的快照。模块顶层不能缓存这些值,组件渲染也应
改用框架提供的响应式状态。事件处理器、action、普通工具函数和即时日志可以按需读取。
static-candidate-limit
检查单个翻译调用展开后的 source 与 options 组合。默认超过 1000 个静态候选时发出 warning。
确实存在大型有限集合时,可以提高阈值:
'ai-i18n/static-candidate-limit': [
'warn',
{ maxStaticCandidates: 2000 },
],
这项设置只影响 ESLint 警告,不改变 Vite 的翻译结果。
no-redundant-auto-import
自动导入预设默认不启用该规则。启用后,它会报告 virtual:ai-i18n 中已经由当前框架自动注入的
同名值导入,并支持 eslint --fix。改名导入、命名空间导入和类型导入会保留;import 内有注释
时只报告,不自动修改。
框架规则
新项目优先使用与 Vite 框架模式一致的预设。下面按框架说明额外检查,并列出自动导入预设的
完整规则配置。框架自动导入 API 见 自动导入。
自动导入项目使用 vanilla-auto-import。该预设的规则配置如下:
{
rules: {
'ai-i18n/t-static-args': ['error', { autoImport: ['t'] }],
'ai-i18n/no-embedded-markup': ['warn', { autoImport: ['t'] }],
'ai-i18n/no-eager-translation': ['warn', { autoImport: ['t'] }],
'ai-i18n/no-unsubscribed-runtime-state': [
'warn',
{ autoImport: ['getLang', 'getLangLoadState'] },
],
'ai-i18n/static-candidate-limit': ['warn', { autoImport: ['t'] }],
},
}
Vanilla 只使用通用规则。它没有组件渲染生命周期,因此 vanilla-auto-import 不启用
no-unsubscribed-t。
启用可选的 no-redundant-auto-import 时,传入 Vanilla 注入的完整 Runtime API:
{
autoImport: [
't',
'setLang',
'getLang',
'getLangs',
'getLangLoadState',
'subscribe',
],
}
自动导入项目使用 vue-auto-import。该预设的规则配置如下:
{
rules: {
'ai-i18n/t-static-args': [
'error',
{ autoImport: ['t', 'tRef', 'tComputed', 'useI18n'] },
],
'ai-i18n/no-embedded-markup': [
'warn',
{ autoImport: ['t', 'tRef', 'tComputed', 'useI18n'] },
],
'ai-i18n/no-eager-translation': [
'warn',
{
autoImport: ['t', 'tRef', 'tComputed', 'useI18n'],
framework: 'vue',
},
],
'ai-i18n/no-unsubscribed-runtime-state': [
'warn',
{
autoImport: ['getLang', 'getLangLoadState', 'i18nComputed'],
framework: 'vue',
},
],
'ai-i18n/no-unsubscribed-t': [
'warn',
{
autoImport: ['t', 'tRef', 'tComputed', 'useI18n'],
framework: 'vue',
},
],
'ai-i18n/static-candidate-limit': [
'warn',
{ autoImport: ['t', 'tRef', 'tComputed', 'useI18n'] },
],
},
}
Vue template、render 和 computed 可以直接调用词法作用域中的顶层 t()。规则还会检查以下
Composition API 与 Options API 生命周期问题:
自动导入模式下,纯 Options template 可以直接使用未绑定的 t();本地同名值仍然遮挡。关闭
自动导入时,methods: { t } 或 methods: { t: translate } 必须解析到 ai-i18n Runtime
t,才能作为 template binding。
启用可选的 no-redundant-auto-import 时,传入 Vue 注入的完整 API:
{
autoImport: [
'useI18n',
't',
'setLang',
'getLang',
'getLangs',
'getLangLoadState',
'subscribe',
'tRef',
'i18nComputed',
'tComputed',
],
}
自动导入项目使用 react-auto-import。该预设的规则配置如下:
{
rules: {
'ai-i18n/t-static-args': [
'error',
{ autoImport: ['t', 'useI18n'] },
],
'ai-i18n/no-embedded-markup': [
'warn',
{ autoImport: ['t', 'useI18n'] },
],
'ai-i18n/no-eager-translation': [
'warn',
{ autoImport: ['t', 'useI18n'] },
],
'ai-i18n/no-unsubscribed-runtime-state': [
'warn',
{ autoImport: ['getLang', 'getLangLoadState'] },
],
'ai-i18n/no-unsubscribed-t': [
'warn',
{ autoImport: ['t', 'useI18n'] },
],
'ai-i18n/static-candidate-limit': [
'warn',
{ autoImport: ['t', 'useI18n'] },
],
},
}
React 在通用规则之外增加组件订阅检查:
启用可选的 no-redundant-auto-import 时,传入 React 注入的完整 API:
{
autoImport: [
'useI18n',
't',
'setLang',
'getLang',
'getLangs',
'getLangLoadState',
'subscribe',
],
}
规则选项
翻译调用规则中的 autoImport: true 是兼容性简写,只启用 t 与 useI18n,不包含 Vue 专属的
tRef 和 tComputed。状态快照规则中的 autoImport: true 会启用 getLang、
getLangLoadState 与 i18nComputed。框架项目应优先使用预设;手动配置时使用 Tabs 中的明确
API 数组。
no-eager-translation、no-unsubscribed-t 和 no-unsubscribed-runtime-state 只判断当前
文件内可以确定的生命周期问题,不追踪跨文件 store 数据流。
路径别名与项目配置
项目可以通过共享 settings 显式提供本地源码 alias。显式 alias 拥有最高优先级,适合只在
Vite resolve.alias 中配置别名的 JavaScript 项目:
import { fileURLToPath } from 'node:url';
export default [
{
settings: {
'ai-i18n': {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
},
},
];
第一版支持字符串到字符串的对象形式。replacement 必须使用绝对路径,并指向项目本地源码。
暂不支持 Vite 的数组形式、正则 find、customResolver 或 resolver plugin。ESLint 不会加载
或执行 vite.config.*;需要与 Vite 保持一致时,建议让两份配置导入同一个 alias 对象。
显式 alias 未匹配当前导入时,规则会从正在检查的文件向上寻找最近的 tsconfig.json 或
jsconfig.json。同一目录同时存在两者时,优先使用 tsconfig.json。纯 JavaScript 项目可以
直接使用 jsconfig.json:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*.js", "src/**/*.jsx"]
}
项目使用非标准配置名、项目引用或特殊工作目录时,可以指定入口:
'ai-i18n/t-static-args': [
'error',
{ tsconfigPath: './tsconfig.json' },
],
tsconfigPath 路径以 ESLint 的工作目录为基准,并覆盖自动发现入口。无论使用
tsconfig.json 还是 jsconfig.json,插件都会解析 extends、项目 references 以及
files、include、exclude。该选项沿用现有名称,也可以直接指向 jsconfig.json。
Vue SFC 必须被所选项目配置的 files 或 include 显式覆盖。例如:
{
"include": ["src/**/*.ts", "src/**/*.vue"]
}