babaofan-translate-cli
v1.0.4-beta.0
Published
Beta local CLI for scanning i18n calls, generating semantic keys, translating with Google AI Studio, and updating locale files.
Maintainers
Readme
babaofan-translate-cli
当前版本为 Beta 测试版。功能还在快速迭代,存在已知问题与兼容性风险,生产项目请先使用
--dry-run验证,再决定是否正式改写源码。Beta 安装方式:
npm install -D babaofan-translate-cli@betaBeta 临时执行方式:
npx babaofan-translate-cli@beta create --languages zh-cn,en --files "src/**/*.vue,src/**/*.ts" --dry-runGitHub 仓库地址:
https://github.com/2285907229/babaofan-translate-cli
一个本地运行的 i18n 翻译 CLI。
它的目标很直接:扫描前端项目中的 t("...")、$t("...") 这类国际化调用,把中文词条提取出来,自动生成稳定的 i18n key,把源码里的中文调用改写成 key 调用,然后直接在本地通过 Google AI Studio 的 Gemini 模型完成翻译,最后生成对应的多语言文件。
整个过程在用户自己的终端闭环完成,不依赖自建后端服务。
功能概览
- 扫描前端项目中的 i18n 调用
- 支持
Vue、nvue、uvue、React、Next.js、Nuxt以及其他基于JS/TS的前端项目 - 使用 AST 扫描,而不是简单正则
- 直接调用 Google 官方 SDK
@google/genai - 支持通过
config.js配置默认 API Key - 支持命令行覆盖 API Key,例如
--apiKey=xxx - 支持指定扫描范围
- 支持指定语言列表
- 支持指定输出目录和输出格式
- 支持自动把源码里的中文调用改写成 i18n key
- 支持预览模式
--dry-run - 支持合并已有 locale 文件,而不是粗暴覆盖
工作原理
这个工具的执行流程分 4 步:
- 扫描项目文件
- 使用 AST 提取
t("中文")、$t("中文")、this.$t("中文")等调用中的静态字符串 - 为每个词条生成稳定的 key
- 把源码里的
t("中文")改成t("生成的.key") - 调用 Google Gemini 接口批量翻译
- 合并已有 locale 文件
- 生成或更新
locales/*.json等翻译文件
为什么用 AST
正则方案看着省事,实际上很容易误伤:
- 把普通字符串里的
t("xxx")当成真实调用 - 漏掉模板里的表达式
- 遇到嵌套、换行、模板字符串时结果不稳定
AST 扫描会靠谱得多,至少不是拿锤子当手术刀。
支持的扫描文件类型
当前支持以下文件后缀:
.js.jsx.mjs.cjs.ts.tsx.mts.cts.vue.nvue.uvue.uts
默认会忽略这些目录:
node_modulesdistbuildcoverage.next.nuxt.output.turbo.gitlocales
这样做是为了避免把依赖、构建产物和已生成翻译文件再次扫进去。
安装依赖
项目已经依赖:
npm install如果你是把这个 CLI 集成到别的项目里,确保目标环境至少满足:
- 已安装
Node.js - 已安装当前项目依赖
- 能访问 Google AI Studio / Gemini 接口
安装
建议作为开发依赖安装:
npm install -D babaofan-translate-cli如果你想明确安装测试版,建议直接指定 beta tag:
npm install -D babaofan-translate-cli@beta或者:
pnpm add -D babaofan-translate-cli或者:
yarn add -D babaofan-translate-cli方式 1:直接用 npx 执行
npx babaofan-translate create --languages zh-cn,en --files "src/**/*.vue,src/**/*.tsx" --dry-run如果你想强制使用 Beta 版本测试:
npx babaofan-translate-cli@beta create --languages zh-cn,en --files "src/**/*.vue,src/**/*.tsx" --dry-run方式 2:写进项目 scripts
在目标项目的 package.json 里加:
{
"scripts": {
"i18n:scan": "babaofan-translate create --languages zh-cn,en --files \"src/**/*.vue,src/**/*.tsx\" --dry-run",
"i18n:run": "babaofan-translate create --languages zh-cn,en --files \"src/**/*.vue,src/**/*.tsx\""
}
}然后执行:
npm run i18n:scan
npm run i18n:run方式 3:临时传入 API Key
npx babaofan-translate create --apiKey=你的_key --languages zh-cn,en --files "src/**/*.vue,src/**/*.tsx"方式 4:通过环境变量
GEMINI_API_KEY=你的_key npx babaofan-translate create --languages zh-cn,en --files "src/**/*.vue,src/**/*.tsx"Windows PowerShell 可以这样:
$env:GEMINI_API_KEY="你的_key"
npx babaofan-translate create --languages zh-cn,en --files "src/**/*.vue,src/**/*.tsx"API Key 配置
默认 API Key 配置在 config.js:
export const defaultGoogleApiKey = "你的_google_ai_studio_key";你也可以不写死在配置里,而是在命令行传入:
node bin/i18n.js create --apiKey=你的_key或者:
node bin/i18n.js create --api-key=你的_keyKey 优先级
当前优先级如下:
- 命令行传入的
--apiKey/--api-key config.js中的defaultGoogleApiKey- 环境变量
GEMINI_API_KEYGOOGLE_AI_STUDIO_API_KEYGOOGLE_API_KEY
安全提醒
如果 config.js 里写了真实 Key,别傻乎乎直接提交到公开仓库。
更稳的方式是:
- 本地开发时临时写
config.js - 或者使用环境变量
- 或者在实际项目里用命令行参数覆盖
命令说明
1. 创建翻译文件
node bin/i18n.js create [options]示例:
node bin/i18n.js create --languages zh-cn,en --files "src/**/*.{vue,js,jsx,ts,tsx}"2. 为 uni_modules 模块生成翻译文件
node bin/i18n.js add uni_modules/模块名 [options]示例:
node bin/i18n.js add uni_modules/demo --languages zh-cn,en3. 清空翻译输出目录
node bin/i18n.js clearnpm script 用法
项目里已经定义了:
"scripts": {
"i18n": "node bin/i18n.js"
}所以也可以这样用:
npm run i18n -- create --languages zh-cn,en --files "src/**/*.{vue,js,jsx,ts,tsx}"如果你要传 Key:
npm run i18n -- create --apiKey=你的_key --languages zh-cn,en --files "src/**/*.{vue,js,jsx,ts,tsx}"注意这里中间那个 -- 不能少。
少了以后,参数不会传给脚本,命令看着像执行了,实际上啥也没喂进去,贼恶心。
参数说明
通用参数
--apiKey <key>
Google AI Studio API Key,适合 npm run xxx -- --apiKey=*** 这种场景。
--api-key <key>
和 --apiKey 作用一致,只是另一种写法。
--model <model>
指定 Gemini 模型。
默认值:
gemini-2.5-flash--batch-size <size>
单批翻译条数。
默认值:
20--files <paths>
指定扫描文件或 glob,多个值用英文逗号分隔。
示例:
--files "src/**/*.vue,src/**/*.tsx"--languages <codes>
指定语言列表,多个值用英文逗号分隔。
示例:
--languages zh-cn,en,ja如果不传,CLI 会尝试自动检测项目里的语言配置。
--output-dir <dir>
指定输出目录。
默认值:
locales--output-format <format>
输出格式,可选:
autopair-arrayobject
说明:
auto:自动判断pair-array:输出二维数组,例如[[key, value]]object:输出对象,例如{ "key": "value" }
--source-locale <code>
指定源语言代码,默认是:
zh-cn--no-rewrite
只生成 locale 文件,不改写源码。
默认情况下,CLI 会自动把源码中的中文调用替换成生成后的 key。
--dry-run
预览模式。
开启后,CLI 会输出:
- 开始翻译总览
- 正在调用 Google AI 生成语义 key 的提示
- 语义 key 分批生成进度提示
- 哪些文件会被改写
- 会生成哪些 key
- 会写入哪些 locale 文件
- 对应 locale 文件是新建还是合并已有文件
不会真正执行翻译、改写源码或写入文件。
注意:
- 为了预览真正的语义 key,
dry-run仍可能调用 Google 来生成 key
输出格式说明
源码改写说明
默认情况下,工具会把源码里的调用:
t("你好")
$t("欢迎使用")
this.$t("按钮文案")自动改成类似这样:
t("home.button.title")
$t("home.welcome.message")
this.$t("header.action.confirm")同时在 locale 文件里生成:
{
"home.button.title": "你好"
}key 生成规则
当前 key 由三部分组成:
- 文件相对路径
- Gemini 生成的英文语义 key
- 必要时附加短 hash 做冲突兜底
补充说明:
- 目录层级之间使用
. - 单个目录名内部会尽量保留原始语义,例如
tmp-generic-test会保留为tmp-generic-test - 不会把一个目录名再拆成
tmp.generic.test - 对明显的临时目录或测试目录,例如
tmp-*、temp-*、test-*、playground,会自动压缩或忽略,避免 key 前缀过长 - 对真正的业务模块目录,例如
user-center、order-management,会尽量保留
这样做的目的是:
- 保持 key 稳定
- 尽量让 key 能被人看懂
- 避免简单重名冲突
- 不依赖外部服务来生成 key
如果你暂时不想改源码,可以显式传:
--no-rewrite合并已有 locale 文件
默认情况下,工具写 locale 文件时会先读取已有文件,再把本次新生成的 key 合并进去。
也就是说:
- 旧 key 会保留
- 新 key 会追加
- 同名 key 会用本次生成结果覆盖
支持两种已有文件格式:
objectpair-array
这意味着你项目里已经有一部分翻译内容时,不需要每次从零开始重建。
object
示例:
{
"你好": "Hello",
"欢迎使用": "Welcome"
}pair-array
示例:
[
["你好", "Hello"],
["欢迎使用", "Welcome"]
]自动检测语言配置
如果没有手动传 --languages,CLI 会尝试扫描这些路径里的语言配置:
plugins/locale.*src/plugins/locale.*src/i18n/**/*i18n/**/*config/**/*locale*locales/**/*
它会尝试识别这些字段:
languageslocalessupportedLocalesavailableLocalessupportedLngs
如果自动检测失败,请直接传:
--languages zh-cn,en别跟 CLI 斗气,明确告诉它最省事。
本地测试
最小测试方式
先在你的项目里建一个测试文件,比如 src/test-i18n.ts:
const a = t("你好");
const b = $t("欢迎使用");然后执行:
node bin/i18n.js create --languages zh-cn,en --files "src/test-i18n.ts"你应该看到什么
正常情况下,终端会看到类似输出:
开始翻译
● 项目 ...
● 提供方 Google AI Studio
● 模型 gemini-2.5-flash
● 词条 2 个然后输出目录里会生成:
locales/zh-cn.jsonlocales/en.json
如果开启默认回写,还会看到源文件中的中文被替换成生成后的 key。
预览测试方式
如果你想先看结果,不想真正改文件,可以执行:
node bin/i18n.js create --languages zh-cn,en --files "src/test-i18n.ts" --dry-run正常情况下,你会看到:
- 改写文件数量
- key 预览
- locale 文件输出位置
- 是新建还是合并已有文件
常见问题
1. 终端提示 词条 0 个
通常是下面几个原因:
--files路径没写对- 文件里没有
t("静态字符串")或$t("静态字符串") - 写的是
t(variable),这种动态参数当前不会提取
2. 终端提示 fetch failed
通常是:
- API Key 无效
- 当前网络访问不到 Google 接口
- 本机网络环境限制了 Gemini 服务访问
这不是扫描逻辑的问题。
现在批量调用失败时,CLI 也会额外提示失败批次,例如:
语义命名失败:第 2/5 批(20 条)执行失败这样可以更快判断是偶发网络问题,还是某一批词条太多、太杂。
3. npm run 参数不生效
检查是不是漏了这个:
npm run i18n -- create --languages zh-cn,en中间那个 -- 必须有。
4. 为什么源码没有被替换
先看是不是传了:
--no-rewrite如果传了这个参数,CLI 只生成 locale,不改源码。
另外,只有静态字符串调用才会被改写。
5. 为什么没有真正写文件
先看是不是传了:
--dry-run如果传了,CLI 只预览,不会真正翻译、改源码或写 locale。
不过为了生成可预览的语义 key,它仍可能调用 Google。
6. 为什么有些调用没被提取
当前优先提取静态字符串调用,比如:
t("你好")
$t("欢迎使用")
this.$t("按钮文案")像下面这种动态值,目前不会提取:
t(messageKey)
t(`prefix.${name}`)这是故意的,不是 bug。
动态 key 一旦瞎提,生成结果十有八九一团糟。
推荐用法
Vue / Nuxt 项目
npm run i18n -- create --languages zh-cn,en --files "src/**/*.{vue,ts,js}"React / Next 项目
npm run i18n -- create --languages zh-cn,en --files "src/**/*.{tsx,ts,jsx,js}"指定输出目录
npm run i18n -- create --languages zh-cn,en --files "src/**/*.{vue,ts}" --output-dir src/locales指定输出格式
npm run i18n -- create --languages zh-cn,en --files "src/**/*.{tsx,ts}" --output-format object只生成 locale,不改源码
npm run i18n -- create --languages zh-cn,en --files "src/**/*.{vue,ts}" --no-rewrite先预览,不真正执行
npm run i18n -- create --languages zh-cn,en --files "src/**/*.{vue,ts}" --dry-run全项目递归扫描
node bin/i18n.js create --languages zh-cn,en --files "**/*.{vue,js,jsx,ts,tsx}" --dry-run注意:
- 不要写成
/*.{vue,js,jsx,ts,tsx},那只会扫项目根目录一层 - 默认忽略目录仍然生效,所以不会去扫
node_modules、dist、locales这些地方
未来可以继续扩展的方向
- 自动合并已有 locale 文件
- 支持更多 i18n 框架约定
- 增加
--dry-run - 增加翻译缓存
- 增加忽略规则
License
MIT
