Node.js如何读取多TS文件导出内容合并生成i18n统一配置对象
实现方案
这个需求完全可实现,比当前拼接txt的方案稳定性、可维护性高很多,不需要手动拼接代码字符串,也不会出现TS语法错误、内容漏写的问题,根据你的项目技术栈选下面任意一种方案即可。
方案1:独立Node构建脚本(通用,适配所有技术栈)
这个方案灵活性最高,支持自定义键冲突检测、命名空间前缀等自定义逻辑,不管项目用什么构建工具都能用。
- 安装依赖:只需要装两个轻量包,
tsx用来直接运行TS脚本不用提前转译,glob用来批量匹配目录下的i18n文件npm i -D tsx glob - 在项目下新建
scripts/merge-i18n.ts脚本,核心逻辑是自动扫描所有模块的i18n文件、按语言分组合并、输出最终的TS文件:import { glob } from 'glob' import { writeFileSync } from 'fs' import path from 'path' // 匹配所有模块下的i18n TS文件 const i18nFilePaths = await glob('src/modules/**/i18n/*.ts') const messages: Record<string, Record<string, string>> = {} for (const filePath of i18nFilePaths) { // 用文件名作为语言标识,比如en-US.ts对应en-US语言 const lang = path.basename(filePath, '.ts') // 动态导入TS文件,拿到默认导出的多语言对象 const i18nModule = await import(path.resolve(filePath)) const langContent = i18nModule.default if (!messages[lang]) messages[lang] = {} // 合并内容,加重复键检测避免静默覆盖 for (const [key, value] of Object.entries(langContent)) { if (messages[lang][key]) { throw new Error(`[i18n合并错误] 语言「${lang}」下存在重复key:${key},冲突文件:${filePath}`) } messages[lang][key] = value } } // 生成最终的index.ts文件内容,不用手动拼字符串 const outputContent = `export default { messages: ${JSON.stringify(messages, null, 2)} } ` writeFileSync(path.resolve('src/i18n/index.ts'), outputContent) - 在
package.json里加执行脚本,绑定到构建、开发启动的前置钩子,每次运行前自动生成最新的合并文件:{ "scripts": { "predev": "tsx scripts/merge-i18n.ts", "prebuild": "tsx scripts/merge-i18n.ts" } }
- 可以把生成的
src/i18n/index.ts加到.gitignore里,不用提交到代码仓库,避免多人协作时出现生成文件冲突。
方案2:构建工具原生能力(无需额外脚本,适合Vite/Webpack项目)
如果你的项目用Vite、Rspack这类现代构建工具,不需要写独立脚本,直接用构建工具提供的glob导入能力,在代码里动态合并即可,连物理生成的index.ts都不需要。
以Vite为例,直接在i18n入口文件里写:
// src/i18n/index.ts // eager: true表示构建时直接静态解析导入,不用运行时异步加载 const i18nModules = import.meta.glob<{ default: Record<string, string> }>( '../modules/**/i18n/*.ts', { eager: true } ) const messages: Record<string, Record<string, string>> = {} for (const [filePath, mod] of Object.entries(i18nModules)) { const lang = filePath.split('/').pop()?.replace('.ts', '') as string if (!messages[lang]) messages[lang] = {} // 这里同样可以加重复key检测逻辑 Object.assign(messages[lang], mod.default) } export default { messages }
Webpack/Rspack可以用require.context实现同样的效果,逻辑完全一致。
优化建议
- 不要直接用
Object.assign做无感知合并,一定要加重复key检测,不同模块写了同名key时直接抛错,避免线上出现文案被覆盖的问题,排查成本极高 - 如果后续模块多了怕key重,可以在合并时自动给每个模块的key加前缀,比如
clients模块下的Key1自动变成clients.Key1,从根源避免冲突 - 如果需要保留TS类型提示,可以在生成文件时额外导出多语言key的联合类型,不用手动维护类型定义
内容的提问来源于stack exchange,提问作者Trent
相关产品推荐
相关产品推荐

