架构总览
相关源文件
本页面内容基于以下源文件生成:
- src/bin/index.ts
- src/lib/index.ts
- src/bin/translate/index.ts
- src/bin/config.ts
- src/lib/type.ts
- src/type.ts
- test/utils.ts
- src/bin/fetch.ts
- src/bin/chalk.ts
- src/bin/constants.ts
- index.js
- docs/src/commandline/utils/index.ts
- package.json
- i18nrc.js
- global.d.ts
- .eslintrc.js
- .prettierrc.js
- rollup.config.js
- vitest.config.ts
- jsx-to-md.config.js
i18n-pro/core 是一个轻量级的国际化(i18n)解决方案,采用分层架构设计,将命令行工具、翻译服务与运行时库清晰分离。该项目支持 8 种主流翻译平台(百度、有道、腾讯、阿里云、微软、Google、GoogleX、OpenAI),提供从源码文本提取到多语言包生成的完整工作流。
核心架构分层
系统采用三层架构设计,各层职责明确,通过配置文件和类型系统进行解耦。
正在加载图表渲染器...
CLI 入口层
CLI 入口层负责命令行参数解析与命令分发,是用户与系统交互的入口点。
职责边界:
- 解析
process.argv获取命令和参数 - 分发到对应的命令处理函数
- 处理国际化语言包加载和设置
入口 API:
execCommand():主入口函数,解析命令并分发
关键数据结构:
typescript1// 命令行参数对象 2const argObj = transferArgsToObj(args) 3const configPath = (argObj['--path'] || argObj['-P']) as string
命令分发逻辑:
init:初始化配置文件translate/t:执行翻译任务version/v:显示版本信息help/h:显示帮助信息
证据:src/bin/index.ts:213-251 展示了完整的命令分发逻辑,包括参数解析和 switch-case 命令路由。
翻译服务层
翻译服务层是核心业务逻辑所在,负责多平台翻译器适配与配置管理。
职责边界:
- 管理翻译器配置(支持 8 种平台)
- 实现文本翻译的核心逻辑
- 处理翻译请求的分批与限流
入口 API:
setTranslateConfig():设置翻译器配置translateTextsToLang():翻译文本到指定语言
关键数据结构:
typescript1// 翻译器配置 2config = configProp[`${translator}Config`] 3currentTranslatorImpl = translatorImplMap[translator] 4 5// 翻译请求参数 6{ 7 texts: string[], // 需要翻译的文本内容 8 from: string, // 源语言 9 to: string, // 目标语言 10 tokens: number // token 长度 11}
错误处理:
- 翻译器不存在时:
process.exit(1)终止进程 - 配置为空时:输出错误信息并退出
证据:src/bin/translate/index.ts:107-169 展示了翻译器配置验证和翻译实现函数的完整逻辑。
运行时库层
运行时库层提供国际化状态管理与翻译函数,供应用程序在运行时使用。
职责边界:
- 管理多命名空间的 i18n 状态
- 支持动态加载语言包
- 提供翻译函数
t()
入口 API:
initI18n():初始化 i18n 实例setI18n():更新 i18n 状态
关键数据结构:
typescript1// i18n 状态 2state[namespace] = Object.freeze(newState) 3 4// 命名空间与条件 5type Condition = { 6 namespace: string 7 locale: null | string 8}
动态语言包加载: 当语言包为函数类型时,异步加载并合并到状态中。
证据:src/lib/index.ts:11-77 展示了 setI18n 的状态管理逻辑和 initI18n 的初始化流程。
配置系统设计
配置系统支持 TypeScript 和 JavaScript 两种格式,通过 esbuild 编译 TS 配置文件实现动态加载。
多格式配置文件支持
TS 配置编译流程:
- 检测运行环境(测试/生产)
- 使用 esbuild 编译 TS 为 ESM 模块
- 动态导入编译后的模块
- 返回配置对象
关键实现:
typescript1await build({ 2 entryPoints: [tsPath], 3 outfile: outputPath, 4 bundle: true, 5 format: 'esm', 6 platform: 'node', 7 logLevel: 'silent', 8})
证据:src/bin/config.ts:28-103 展示了 TS 配置文件的 esbuild 编译加载逻辑和 initConfig 初始化函数。
配置解析与验证流程
解析流程:
- 验证文件是否存在
- 调用
loadTsEsmConfig加载配置 - 验证配置对象有效性(非空对象)
错误处理:
- 文件不存在:返回
false - 配置无效:抛出错误并退出进程
证据:src/bin/config.ts:110-149 展示了 parseTsConfig 的文件验证和错误处理逻辑。
多翻译平台配置类型定义
配置类型系统采用联合类型设计,支持 8 种翻译平台的差异化配置。
基础配置结构:
typescript1type BasicConfig = { 2 funcName: string, // 自定义函数名,默认为 t 3 entry?: string, // 入口文件 4 fileRegExp?: RegExp, // 匹配文件名的正则表达式 5 input?: string | string[], // Glob 语法过滤文件 6 output: { 7 path: string, // 输出目录 8 langType?: 'single' | 'multiple', // 输出方式 9 indentSize?: number // 缩进大小 10 }, 11 translator?: Translator // 翻译平台 12}
平台配置示例:
| 平台 | 必需配置 | 可选配置 |
|---|---|---|
| 百度 | appid, key | delay, codeLocaleMap |
| 有道 | appKey, key | delay, codeLocaleMap |
| 腾讯 | secretId, secretKey, region | projectId, language |
| 阿里云 | accessKeyId, accessKeySecret | scene, apiType, endpoint |
| 微软 | key, location | delay, codeLocaleMap |
| projectId | location | |
| GoogleX | - | proxy |
| OpenAI | key | model, proxy |
证据:src/type.ts:1-100 展示了基础配置结构和各翻译平台的配置类型定义。
类型系统与接口设计
类型系统是架构稳定性的基石,通过严格的类型定义确保配置和接口的正确性。
翻译函数接口
Translate 接口定义了翻译函数的完整契约:
typescript1export interface Translate { 2 (text: string, ...args: Array<string | number | unknown>): string 3 t: (key: string, text: string, ...args: Array<string | number | unknown>) => string 4 withLocale: (locale?: string) => Translate 5}
接口说明:
- 主函数:直接翻译文本,支持动态参数插值
t方法:基于自定义 key 的翻译withLocale方法:返回绑定指定 locale 的新翻译函数
证据:src/lib/type.ts:126-157 展示了 Translate 接口的完整定义和 Condition 类型。
多翻译平台配置联合类型
系统使用联合类型管理多平台配置:
typescript1export type UnionTranslatorConfig = 2 | BaiduConfig 3 | YoudaoConfig 4 | TencentConfig 5 | AliyunConfig 6 | MicrosoftConfig 7 | GoogleConfig 8 | GooglexConfig 9 | OpenAIConfig
类型推导机制:
通过 translator 字段自动推导对应的配置类型:
typescript1type DefineTranslatorConfig<T extends Translator, C extends object> = { 2 translator: T 3} & Record<`${T}Config`, C>
证据:src/type.ts:200-281 展示了联合类型定义和 MaxLengthConfig 等核心类型。
语言包与内部配置类型
语言包类型:
typescript1export type LangPack = Record<string, string> 2export type Langs = Record<string, LangPack>
内部配置类型:
typescript1export type InnerConfig = { 2 maxLengthConfig: MaxLengthConfig 3} 4 5export type MaxLengthConfig = { 6 maxLengthType: MaxLengthType // 限制类型 7 maxLength: number // 最大字符数 8 maxArrayLength?: number // 数组最大长度 9 separator?: string // 分隔符 10}
证据:src/type.ts:100-200 展示了各翻译平台配置类型和内部配置定义。
翻译流程数据流
以下时序图展示了从命令行输入到语言包生成的完整数据流:
正在加载图表渲染器...
流程要点说明:
- 配置加载阶段:CLI 入口调用
readConfig解析配置文件,获取翻译器配置和输出设置 - 文本提取阶段:根据
entry、fileRegExp、input参数扫描源码文件,提取待翻译文本 - 翻译执行阶段:
- 根据
maxLength配置分批处理文本 - 调用翻译平台 API 进行翻译
- 根据
delay配置添加请求间隔,避免频率限制
- 根据
- 结果输出阶段:根据
langType配置生成单文件或多文件语言包
关键边界条件:
- 文件列表为空时:直接返回,不执行翻译
- 翻译失败时:记录错误信息,继续处理其他文本
- 增量模式:跳过已翻译的文本
核心设计决策与取舍
1. 采用 esbuild 编译 TS 配置文件
决策:使用 esbuild 而非 ts-node 或 tsc 编译 TypeScript 配置文件
理由:
- esbuild 编译速度比 tsc 快 10-100 倍
- 配置文件通常较小,不需要完整的类型检查
- 支持 ESM 动态导入,与现代构建工具兼容
限制:
- 不支持某些高级 TypeScript 特性(如 const enum)
- 测试环境下需要特殊处理,避免编译问题
证据:src/bin/config.ts:54-65 展示了 esbuild 编译配置。
2. 多翻译器适配器模式
决策:使用适配器模式统一 8 种翻译平台的接口
理由:
- 不同平台 API 差异大(认证方式、请求格式、响应结构)
- 适配器模式隔离平台差异,核心逻辑保持稳定
- 便于扩展新的翻译平台
实现:
typescript1const translatorImplMap = { 2 baidu: baiduTranslate, 3 youdao: youdaoTranslate, 4 // ... 5} 6currentTranslatorImpl = translatorImplMap[translator]
限制:
- 需要为每个平台实现适配器
- 平台特定功能(如术语库)难以统一暴露
3. 分批翻译策略
决策:根据 MaxLengthType 实现多种分批策略
理由:
- 不同翻译平台对请求大小限制不同
- GoogleX 无官方限制,但需要控制请求大小
- OpenAI 使用 Token 计费,需要控制 Token 数量
策略类型:
| 类型 | 说明 | 适用平台 |
|---|---|---|
| allStrLength | 所有字符数限制 | 百度、有道 |
| strLengthAndArrLength | 单字符+数组长度限制 | 腾讯 |
| allStrLengthAndArrLength | 总字符+数组长度限制 | 阿里云 |
| allTokenLength | Token 长度限制 | OpenAI |
证据:src/type.ts:243-269 展示了 MaxLengthType 和 MaxLengthConfig 定义。
4. 命名空间隔离的 i18n 状态管理
决策:使用命名空间隔离不同模块的 i18n 状态
理由:
- 大型应用可能有多个独立模块,各自维护语言包
- 避免语言包 key 冲突
- 支持按需加载语言包
实现:
typescript1state[namespace] = Object.freeze(newState)
限制:
- 增加了 API 复杂度
- 需要开发者手动管理命名空间
证据:src/lib/index.ts:55-76 展示了命名空间管理逻辑。
5. 自定义 Chalk 实现替代第三方库
决策:实现轻量级 Chalk 替代品,而非依赖 chalk 库
理由:
- 减少依赖体积
- 仅需基础样式功能(颜色、加粗)
- 避免 chalk ESM 迁移带来的兼容性问题
实现:
typescript1const chalk = function (...res: Array<string | number>) { 2 return res.join(' ') 3} as Chalk
证据:src/bin/chalk.ts:78-125 展示了类 Chalk 的链式调用实现。
6. 双模式语言包输出
决策:支持 single 和 multiple 两种语言包输出模式
理由:
single模式:适合小型项目,减少文件数量multiple模式:适合大型项目,按需加载语言包
实现差异:
javascript1// single 模式:langs.json 2{ "en": {...}, "jp": {...} } 3 4// multiple 模式:en.json, jp.json 5{ "key": "value" }
证据:src/type.ts:36-63 展示了 langType 配置说明。
7. 增量翻译模式
决策:默认启用增量翻译,通过 --non-incremental 参数禁用
理由:
- 避免重复翻译已处理的文本
- 节省翻译 API 调用成本
- 提高翻译速度
实现:
typescript1incrementalMode: !args.includes(NON_INCREMENTAL)
证据:src/bin/index.ts:233-236 展示了增量模式判断逻辑。
技术选型
| 技术 | 用途 | 选型理由 | 替代方案 |
|---|---|---|---|
| TypeScript | 主要开发语言 | 类型安全,提升代码质量 | JavaScript + JSDoc |
| esbuild | TS 配置编译 | 极快的编译速度 | ts-node, tsc |
| Rollup | 库打包 | 支持 UMD 格式,Tree-shaking | webpack, esbuild |
| Vitest | 单元测试 | 快速、兼容 Jest API | Jest, Mocha |
| Node https | HTTP 请求 | 内置模块,无依赖 | axios, node-fetch |
| https-proxy-agent | 代理支持 | 支持 HTTP/HTTPS 代理 | proxy-agent |
| ESLint | 代码检查 | 社区标准,插件丰富 | Biome |
| Prettier | 代码格式化 | 统一代码风格 | dprint |
| jsx-to-md | 文档生成 | 支持 JSX 编写 Markdown | TypeDoc, Docusaurus |
模块依赖关系
正在加载图表渲染器...
依赖关系说明:
- 命令行模块:
bin/index.ts作为入口,依赖配置解析和翻译服务 - 翻译服务:依赖 HTTP 客户端和类型定义
- 运行时库:独立模块,仅依赖类型定义
- 类型系统:作为基础层,被所有模块依赖
关键设计:
- 运行时库与命令行工具完全解耦,可独立使用
- 类型定义集中在
type.ts,便于跨模块共享 - 外部依赖最小化,仅保留必要工具
关键配置与启动流程
配置文件示例
javascript1// i18nrc.js 2module.exports = { 3 funcName: 't', 4 entry: path.join(__dirname, './src/bin/'), 5 fileRegExp: /.*\.[jt]s$/, 6 output: { 7 path: path.join(__dirname, './i18n/'), 8 langType: 'single', 9 }, 10 translator: 'googlex', 11 googlexConfig: { 12 from: 'zh-CN', 13 to: ['en'], 14 proxy: 'http://127.0.0.1:7997', 15 }, 16}
证据:i18nrc.js:1-17 展示了项目的实际配置文件。
启动流程
- 环境检测:检查
NODE_ENV确定运行模式 - 语言包加载:尝试加载
i18n/langs.json,失败则使用默认中文 - 命令解析:解析
process.argv获取命令和参数 - 配置读取:根据
--path参数定位配置文件 - 命令执行:分发到对应的命令处理函数
模块导出入口:
javascript1// index.js 2if (process.env.NODE_ENV === 'production') { 3 module.exports = require('./dist/src/lib/index.min.js') 4} else { 5 module.exports = require('./dist/src/lib/index.js') 6}
证据:index.js:1-7 展示了根据环境变量区分导出策略。
构建配置
项目使用 Rollup 构建 UMD 格式输出:
javascript1export default formats.map((format, index) => { 2 return { 3 input: 'src/lib/index.ts', 4 output: { 5 file: `dist/src/lib/index${suffix ? '.' + suffix : ''}.js`, 6 format: format.includes('.') ? format.split('.')[0] : format, 7 name: 'i18nPro', 8 }, 9 plugins: [ 10 ts({ /* TypeScript 配置 */ }), 11 prettier(), 12 terser({ /* 压缩配置 */ }) 13 ], 14 } 15})
证据:rollup.config.js:1-61 展示了完整的 Rollup 构建配置。
测试配置
使用 Vitest 作为测试框架:
typescript1export default defineConfig({ 2 test: { 3 globals: true, 4 coverage: { 5 provider: 'istanbul', 6 reporter: ['json', 'html', 'text-summary', 'text'], 7 }, 8 }, 9})
证据:vitest.config.ts:1-12 展示了 Vitest 测试配置。
