babel-plugin-auto-i18n-ast
v1.0.0
Published
Babel plugin for auto i18n with full AST transformation - More precise Chinese to t(key) conversion
Maintainers
Readme
babel-plugin-auto-i18n-ast
基于完整 AST 遍历的 Babel i18n 转换插件,用于 Webpack 等构建工具。相比简单的字符串匹配,AST 方案更加精确,能够准确识别代码结构,避免误转换。
✨ 特性
- 🎯 完整 AST 遍历 - 使用 Babel 的 visitor 模式精确遍历所有节点
- 🔍 语义理解 - 自动跳过 import、console、类型注解等不应转换的内容
- 📦 完整支持 - 支持 JSX、TypeScript、普通 JavaScript
- 🛡️ 智能检测 - 自动识别已在 i18n 函数中的字符串,避免重复转换
- 🔧 可配置 - 丰富的配置选项
🔬 AST vs 正则方案对比
| 特性 | AST 方案 (本包) | 正则方案 | |------|----------------|----------| | 精确度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | | 跳过注释 | ✅ 自动 | ❌ 需特殊处理 | | 跳过 import | ✅ 自动 | ❌ 需特殊处理 | | 跳过 console | ✅ 自动 | ❌ 需特殊处理 | | 避免重复转换 | ✅ 完美 | ⚠️ 可能出问题 | | JSX 结构 | ✅ 完美支持 | ⚠️ 可能误匹配 |
📦 安装
# npm
npm install babel-plugin-auto-i18n-ast -D
# pnpm
pnpm add babel-plugin-auto-i18n-ast -D
# yarn
yarn add babel-plugin-auto-i18n-ast -D🚀 快速开始
Webpack + Babel 配置
// babel.config.js
module.exports = {
presets: [
'@babel/preset-env',
'@babel/preset-react', // 如果使用 React
'@babel/preset-typescript', // 如果使用 TypeScript
],
plugins: [
['babel-plugin-auto-i18n-ast', {
localesDir: 'locales', // 语言包目录名(向上查找)或绝对路径
sourceLocale: 'zh-CN',
translateFn: 't',
debug: process.env.NODE_ENV === 'development',
}],
],
}Webpack 配置
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
// babel.config.js 配置会自动加载
},
},
},
],
},
}语言包结构
// src/locales/zh-CN.json
{
"hello": "你好世界",
"welcome": "欢迎使用",
"button": {
"submit": "提交",
"cancel": "取消"
}
}转换示例
转换前:
import React from 'react'
function App() {
const message = '欢迎使用'
console.log('调试信息') // 不会转换
return (
<div>
<h1>你好世界</h1>
<button title="提交按钮">提交</button>
</div>
)
}转换后:
import React from 'react'
function App() {
const message = t('welcome')
console.log('调试信息')
return (
<div>
<h1>{t('hello')}</h1>
<button title={t('button.submit')}>{t('button.submit')}</button>
</div>
)
}⚙️ 配置选项
interface LocalesRule {
/** 文件路径匹配模式(glob 或正则) */
match: string | RegExp
/** 该匹配使用的语言包目录 */
localesDir: string
/** 可选的命名空间前缀 */
namespace?: string
}
interface BabelI18nAstPluginOptions {
/** 语言包目录名(向上查找)或绝对路径(直接使用)
*
* - 字符串:单一目录名,如 'locales'
* - 数组:多个目录名,按优先级排序,如 ['locales', 'i18n', 'langs']
* - 绝对路径:直接使用,不进行向上查找
*
* @default 'locales'
*/
localesDir?: string | string[]
/** 路径匹配规则(优先级高于 localesDir)
* 用于特殊项目的精确控制
*/
localesRules?: LocalesRule[]
/** 源语言代码
* @default 'zh-CN'
*/
sourceLocale?: string
/** 翻译函数名
* @default 't'
*/
translateFn?: string
/** 调试模式 - 输出详细转换日志
* @default false
*/
debug?: boolean
/** 排除的文件模式
* @default [/node_modules/, /\.d\.ts$/, /\/locales\//, /\/langs\//]
*/
exclude?: (string | RegExp)[]
/** 缺少翻译时的处理方式
* - 'warn': 控制台警告(默认)
* - 'error': 抛出错误,中断构建
* - 'ignore': 静默忽略
* @default 'warn'
*/
onMissing?: 'warn' | 'error' | 'ignore'
}🔍 AST 转换原理
Babel 插件工作流程
源代码 (.js/.jsx/.ts/.tsx)
│
▼
@babel/parser (解析)
│
▼
AST
│
▼
babel-plugin-auto-i18n-ast (转换)
├── visitor.JSXText
├── visitor.JSXAttribute
├── visitor.JSXExpressionContainer
├── visitor.StringLiteral
└── visitor.TemplateLiteral
│
▼
转换后的 AST
│
▼
@babel/generator (生成)
│
▼
输出代码Visitor 模式
插件使用 Babel 的 visitor 模式遍历 AST:
visitor: {
// JSX 文本: <div>中文</div>
JSXText(path) {
// 转换为 <div>{t('key')}</div>
},
// JSX 属性: <div title="中文">
JSXAttribute(path) {
// 转换为 <div title={t('key')}>
},
// JSX 表达式: {'中文'}
JSXExpressionContainer(path) {
// 转换为 {t('key')}
},
// 普通字符串: const x = '中文'
StringLiteral(path) {
// 转换为 const x = t('key')
},
// 模板字符串: `中文`
TemplateLiteral(path) {
// 转换为 t('key')
},
}自动跳过的上下文
基于 AST 分析,自动跳过:
Import 声明
import xxx from '路径' // ✅ 跳过Console 调用
console.log('中文日志') // ✅ 跳过已在 i18n 函数中
t('已经转换的') // ✅ 跳过,不会变成 t(t('xxx')) tt('直接翻译') // ✅ 跳过对象非计算 Key
const obj = { '中文key': value } // ✅ 跳过 key类型注解
type Status = '成功' | '失败' // ✅ 跳过Tagged Template
css`color: red;` // ✅ 跳过
🎯 最佳实践
1. 配合 Vue Webpack
// babel.config.js
module.exports = {
presets: ['@babel/preset-env'],
plugins: [
['babel-plugin-auto-i18n-ast', {
localesDir: 'src/locales',
translateFn: 't', // Vue 脚本中使用 t()
}],
],
}注意:Vue 模板需要配合 vue-loader 和专门的 Vue i18n 插件处理。
2. 配合 React Webpack
// babel.config.js
module.exports = {
presets: [
'@babel/preset-env',
['@babel/preset-react', { runtime: 'automatic' }],
],
plugins: [
['babel-plugin-auto-i18n-ast', {
localesDir: 'src/locales',
translateFn: 't',
}],
],
}3. 生产环境关闭调试
['babel-plugin-auto-i18n-ast', {
debug: process.env.NODE_ENV === 'development',
}]4. 严格模式
['babel-plugin-auto-i18n-ast', {
onMissing: 'error', // 缺少翻译时报错
}]📊 调试输出
开启 debug: true 后,控制台会输出:
[babel-i18n-ast] Processing: /src/App.tsx
[babel-i18n-ast] JSX Text: "你好世界" → {t('hello')}
[babel-i18n-ast] JSX Attr: "提交" → {t('button.submit')}
[babel-i18n-ast] Script: "欢迎使用" → t('welcome')
[babel-i18n-ast] Completed: 3 transforms (JSX: 2, Script: 1)⚠️ 注意事项
性能考虑:AST 转换在每次编译时执行,建议在生产构建时关闭 debug。
运行时依赖:需要在运行时提供
t函数,配合@mico_fe/i18n-core或其他运行时库使用。动态字符串:以下情况无法自动转换:
// ❌ 变量 const key = someCondition ? '成功' : '失败' // ❌ 带表达式的模板字符串 const msg = `欢迎 ${name}!` // ✅ 需要手动处理 const key = someCondition ? t('success') : t('failure') const msg = t('welcome.user', { name })Vue 模板:此插件只处理
<script>部分,Vue 模板需要额外的 loader 处理。
🔗 相关包
- @mico_fe/i18n-core - 核心运行时库
- @mico_fe/i18n-vue - Vue 运行时支持
- @mico_fe/i18n-react - React 运行时支持
- babel-plugin-auto-i18n - 正则方案(更简单但精确度较低)
📄 License
MIT
