@tardis-ksh/intl-extract
v1.0.4
Published
CLI for extracting intl strings into Excel
Readme
intl-extract
用于扫描前端源码中的多语言调用,提取中文文案并导出为 intl.xlsx。
当前实现基于 TypeScript + ESM,支持递归扫描 ts / tsx / js / jsx 文件,提取以下两类调用:
getIntl('key', '中文')intl.get('key').d('中文')
同时支持一定容错能力,包括:
- 多行格式化调用
- 带对象参数的
intl.get(...) - 注释与双引号字符串
- 嵌套的
intl.get(...).d(...)
功能特性
- 递归扫描指定目录源码文件
- 提取
getIntl与intl.get().d()文案 - 将 key 拆分为“模板代码”和“代码”
- 按配置语言输出行,默认
zh_CN,vi_VN,en_US - 未配置翻译接口且缓存未命中时,非
zh_CN描述留空 - 配置 OpenAI Responses API 兼容接口后可自动生成目标语言翻译,请求接口期间会在终端显示 loading 动画
- 通过全局
~/.intl-extract/.env或--config读取翻译配置 - 通过全局
~/.intl-extract/cache.db按目标语言复用中文翻译缓存 - 支持从已有 Excel 中导入完整中文到目标语言的翻译组到
cache.db - 将运行日志写入
~/.intl-extract/logs/intl-extract.log并自动轮转 - 在重复判断前先合并完全相同的
key + 中文,并将同 key 不同中文的冲突项在 Excel 中高亮
安装
pnpm install运行环境需使用支持
node:sqlite的 Node.js 版本,否则翻译缓存会自动降级为不可用。
开发命令
运行测试:
pnpm test本地运行 CLI:
pnpm dev -- --cwd . --out ./intl.xlsx命令行用法
源码扫描模式:
pnpm dev -- --cwd <target-dir> --out <output-file>Excel 补全模式:
pnpm dev -- --from-excel <input.xlsx> --out <output.xlsx>Excel 导入缓存模式:
pnpm dev -- --import-excel-db <input.xlsx>或构建后使用 npm bin:
pnpm build
node dist/cli.js --cwd <target-dir> --out <output-file>参数
--cwd:要扫描的目录,默认当前工作目录;传入--from-excel时不会扫描源码--out:输出 Excel 路径,默认<cwd>/intl.xlsx--ext:要扫描的扩展名列表,默认ts,tsx,js,jsx--formatter-codes:额外指定模板代码列表,使用英文逗号分隔;会和源码扫描、.env配置一起合并去重--languages:输出语言列表,使用英文逗号分隔,默认zh_CN,vi_VN,en_US;若未包含zh_CN会自动补到首位--from-excel:读取已有 Excel 并补齐配置语言中空白的非zh_CN描述;启用后不扫描源码--import-excel-db:读取已有 Excel 中完整的中文到目标语言翻译组并写入cache.db;启用后不扫描源码,也不会导出 Excel--use-cache:是否读取并写入翻译缓存,默认true;设为false时不读缓存也不写缓存--config:自定义配置文件路径,默认~/.intl-extract/.env--api-base:翻译接口地址--api-key:翻译接口密钥--model:翻译模型名
示例:
pnpm dev -- \
--cwd ./src \
--out ./dist/intl.xlsx \
--ext ts,tsx \
--languages zh_CN,vi_VN,en_USExcel 补全模式
当已有 Excel 中存在空白目标语言描述时,可以使用 --from-excel 继续补齐:
pnpm dev -- --from-excel ./intl.xlsx --out ./intl-filled.xlsx规则:
- 启用
--from-excel后不会扫描--cwd源码 - 保留原 Excel 全部行和已有描述
- 只补齐配置语言中非
zh_CN且描述为空的行 - 通过相同
模板代码 + 代码的zh_CN行获取中文源文案 - 找不到对应中文时,该目标语言行保持为空
- 结果写入
--out
Excel 导入缓存模式
当已有 Excel 中已经包含完整的中文到目标语言对照时,可以将其直接写入全局缓存库:
pnpm dev -- --import-excel-db ./intl.xlsx规则:
- 启用
--import-excel-db后不会扫描--cwd源码 - 该模式走独立分支,
--out会被忽略,不会生成新的 Excel - 启动时仍会沿用现有初始化逻辑,自动准备
~/.intl-extract/、cache.db、日志目录等全局资源 - 仅要求输入 Excel 文件存在且可读取
- Excel 表头必须仍然是
模板代码 / 代码 / 语言 / 描述 - 同一
模板代码 + 代码视为一组,一行对应一种语言 - 空白行、缺字段行、空语言行、空描述行会直接跳过,不参与导入
- 缓存导入使用
zh_CN作为源语言,配置语言中的其他语言作为目标语言 - 若同一组内任一语言出现多条且描述不一致,视为用户填写错误,命令会直接失败且不写入 db
- 同一组内重复行只要描述完全一致就允许导入
- 只有同时存在可用
zh_CN和目标语言描述的组才会写入 db;缺目标语言的组会被忽略 - 若不同组里出现“同一中文在同一目标语言下对应多个不同翻译”,命令会直接失败且不写入 db
- 写入
cache.db时按中文原文 + 目标语言作为 key;若 db 中已存在相同组合,会用 Excel 中的描述覆盖更新
翻译配置
当同时提供以下 3 个参数时,会调用 OpenAI Responses API 兼容接口生成目标语言翻译:
--api-base--api-key--model
配置优先级如下:
- CLI 参数
--config指定文件- 全局默认文件
~/.intl-extract/.env - 环境变量
支持的环境变量:
INTL_EXTRACT_API_BASEINTL_EXTRACT_API_KEYINTL_EXTRACT_MODELINTL_EXTRACT_FORMATTER_CODESINTL_EXTRACT_LANGUAGES
默认配置文件示例:
INTL_EXTRACT_API_BASE=https://example.com/v1
INTL_EXTRACT_API_KEY=your-token
INTL_EXTRACT_MODEL=gpt-4o-mini
INTL_EXTRACT_FORMATTER_CODES=srm.common,srm.composition
INTL_EXTRACT_LANGUAGES=zh_CN,vi_VN,en_US自定义配置文件示例:
pnpm dev -- \
--cwd ./src \
--out ./intl.xlsx \
--config ./custom.env如果未提供完整翻译配置:
- 仍会生成 Excel
zh_CN行正常输出- 非
zh_CN行在缓存未命中时会保留为空字符串
全局目录
工具会使用用户主目录下的全局目录:
~/.intl-extract/
├─ .env
├─ .env.example
├─ cache.db
└─ logs/
├─ intl-extract.log
├─ intl-extract.1.log
└─ ...说明:
- CLI 启动时会自动创建
~/.intl-extract/、.env.example、cache.db和logs/ .env.example为带默认模板注释的示例文件;如需默认翻译配置,请复制为.env后填写cache.db基于node:sqlite以中文原文 + 目标语言为 key 缓存翻译,避免重复调用接口logs/intl-extract.log记录每次运行的配置摘要、扫描结果和缓存统计- 日志文件超过阈值后会自动轮转,保留最近 5 份
缓存控制:
- 默认启用缓存,相同中文和目标语言组合会复用
~/.intl-extract/cache.db中的翻译 --use-cache=false时不会读取缓存,也不会把 API 翻译结果写入缓存- 当没有 API 配置但缓存命中时,仍可使用缓存补齐目标语言
- 当启用缓存且全部命中时,不会请求 API
输出说明
生成的 Excel 工作表名为 intl,列结构如下:
模板代码代码语言描述
每个提取项会按 --languages / INTL_EXTRACT_LANGUAGES 输出对应语言行。默认输出三行:
- 一行
zh_CN - 一行
vi_VN - 一行
en_US
key 拆分规则
- 工具会先扫描当前目录源码中的
formatterCollections({ code: [...] }) - 同时会合并
--formatter-codes和INTL_EXTRACT_FORMATTER_CODES中配置的额外 code - 若 key 命中一个或多个收集到的 code,则优先使用最长匹配的 code 作为
模板代码 - 命中后,去掉此前缀后的剩余部分作为
代码 - 若未命中任何 code,则继续使用原有回退规则:
hzero.common.*→模板代码 = hzero.common- 其他 key 默认取前二段作为
模板代码
例如:
| 原始 key | 模板代码 | 代码 |
| --- | --- | --- |
| hzero.common.button.save | hzero.common | button.save |
| hzero.document.upload.model.version | hzero.document.upload | model.version |
| srm.composition.supplier.list.title | srm.composition | supplier.list.title |
终端输出
CLI 运行完成后会打印摘要:
当存在未缓存文案且翻译接口配置完整时,等待接口返回期间会显示 正在请求翻译接口... 的 spinner;接口返回或失败后会自动清理该 loading 行。
files:扫描文件数items:提取到的文案条数duplicates:重复 key 数量,仅统计“同一 key 对应多个不同中文”的冲突 key
重复判定规则
- 在判断重复和输出 Excel 之前,会先按
key + 中文完全匹配去重 - 完全相同的
key + 中文只保留其中一组,不会重复导出,也不会计入duplicates - 若
key相同但中文不同,则视为重复 - 这类重复项会继续保留,并在 Excel 中高亮,便于人工处理
cacheHits:命中缓存的条数cacheMisses:未命中缓存的中文和目标语言组合数(即使翻译接口配置不完整、不会发起请求,也会计入缓存未命中)groups:导入缓存模式下识别到的完整组数量translated:成功翻译数量translationFailures:翻译失败数量imported:导入缓存模式下成功写入 db 的条数output:输出文件路径
当前注意事项
- 扫描器当前忽略
node_modules和.git - 如果在仓库 root 运行,并且仓库里保留了
.worktrees,这些 worktree 下的源码也可能被一并扫描 - 翻译返回值会校验占位符,若占位符不一致则该条目标语言翻译会被丢弃并计为失败
- Responses 接口返回的翻译结果支持直接 JSON、```json 代码块,以及
output[*].content[*].text形式的文本提取
构建与 npm 使用
构建:
pnpm build构建产物输出到 dist/,npm bin 指向:
dist/cli.js发布前脚本会执行:
pnpm test && pnpm build本地构建后可直接运行:
node dist/cli.js --cwd ./src --out ./intl.xlsx
node dist/cli.js --from-excel ./intl.xlsx --out ./intl-filled.xlsx
node dist/cli.js --import-excel-db ./intl.xlsx测试
项目使用 Vitest,当前覆盖内容包括:
- CLI 参数解析
- 配置优先级
- 文件递归扫描
getIntl提取intl.get().d()提取- 格式化/嵌套/注释场景提取
- key 归一化
- 目标语言翻译层
- 翻译缓存降级
- 日志写入与轮转
- Excel 导出
- Excel 导入缓存校验
- CLI 最小端到端流程
运行:
pnpm test