背景
在日常开发流程中,国际化(i18n)翻译工作一直是效率瓶颈。每次新增或修改功能时,开发人员需要手动检索代码中所有需要翻译的中文文本,然后逐一复制到翻译配置文件中,并手动完成多语言翻译。这种方式不仅耗时耗力,还容易出现遗漏或格式不一致的问题。
翻译文件:
export default {
用户信息: 'User information',
姓名: 'Name',
};
目标
开发一个自动化翻译工具,通过简单的 npm 命令即可完成整个翻译流程,实现 "一键翻译" 的高效工作流。
功能
- 解析翻译文件获取已翻译词条
- 自动识别已存在的翻译项,避免重复处理
- 中文文本提取引擎
- 使用正则表达式精准匹配
$t()和t()函数中的中文文本 - 内置中文文本过滤器,自动排除非中文内容
- 与现有翻译文件比对,智能过滤已翻译内容
- 云端翻译服务集成
- 支持 Google Translate API 批量翻译
- 翻译文件生成器
- 保持原有翻译文件结构不变
- 自动合并新翻译与现有内容
- 生成格式化良好的翻译文件
代码实现
项目目录
根目录package.json
新增translate命令
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"analyze": "vite build --mode analyze",
"lint": "eslint --color --fix --ext .ts,.tsx,.js,.jsx,.vue src",
"translate": "node node/index.js"
},
调用
npm run translate
node/index.js
注意根据自己项目翻译文件所在路径进行修改
const path = require('path');
const fse = require('fs-extra');
/**
* 遍历项目文件夹,查找需要翻译的中文
*/
let youEn = {};
const projectPath = path.join(__dirname, '../src/'); // 需要遍历的目录
const chKeys = {};
function matchContent(content) {
const matches = content.matchAll(/\$?t\(['|"]([^\)]*)['|"]\)/g);
// eslint-disable-next-line no-restricted-syntax
for (const match of matches) {
if(match && match[1]) {
const str = match[1];
if(/[\u4e00-\u9fa5]/.test(str)) { // 是否包含中文
if(!youEn[`${str}`]) {
chKeys[`${str}`] = '';
}
}
}
}
}
const fileDisplaySync = async (filePath) => {
const files = await fse.readdir(filePath);
for(let i = 0, len = files.length; i < len; i++) {
const filename = files[i];
// 获取当前文件的绝对路径
const filedir = path.join(filePath,filename);
const stats = fse.lstatSync(filedir);
const isFile = stats.isFile();// 是文件
const isDir = stats.isDirectory();// 是文件夹
if(isFile){
const content = fse.readFileSync(filedir, 'utf8');
matchContent(content);
}
if(isDir){
// eslint-disable-next-line no-await-in-loop
await fileDisplaySync(filedir);// 递归,如果是文件夹,就继续遍历该文件夹下面的文件
}
}
}
const translate = async () => {
// Translate Chinese keys to English using Google Translate
const translatePromises = Object.keys(chKeys).map(async (key) => {
try {
// Use Google Translate API to translate from Chinese to English
const response = await fetch(`https://translate.googleapis.com/translate_a/single?client=gtx&sl=zh-CN&tl=en&dt=t&q=${ encodeURIComponent(key)}`);
const data = await response.json();
// Get the translated text from response
const translatedText = data[0][0][0];
// Convert to Title Case and store translation
chKeys[key] = translatedText
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ');
} catch (err) {
console.error(`Translation failed for key "${key}":`, err);
// Keep original Chinese if translation fails
chKeys[key] = key;
}
});
// Wait for all translations to complete
await Promise.all(translatePromises);
};
const main = async (youEnPath) => {
// 读取英文翻译文件
try {
const content = await fse.readFile(youEnPath, 'utf8');
const start = content.indexOf('export default {');
const end = content.indexOf('};');
const strO = content.slice(start + 15, end + 1);
// eslint-disable-next-line no-eval
youEn = eval(`(${strO})`);
} catch (err) {
console.error(`fse.readFileSync(youEnPath, 'utf8') error: `, err);
}
// 遍历项目文件夹,查找需要翻译的中文
await fileDisplaySync(projectPath);
// 通过谷歌翻译chKeys
await translate();
// 写入文件
await fse.writeFile(
youEnPath,
`// https://odocs.myoas.com/docs/B1Aw1N4yd1TRaVqm/ 《端内运营v2翻译文档》
export default ${JSON.stringify({...youEn, ...chKeys}, null, 4)};
`.replaceAll(/"/g, `'`),
);
console.log('查找完成,请查看../src/locale/en.ts');
}
// TODO 根据你的实际情况修改翻译文件路径
const youEnPath = path.join(__dirname, '../src/locale/en.ts');
main(youEnPath);
说明
由于自动翻译存在局限性,可能无法完全贴合您的实际需求。为确保代码质量与功能准确性,建议在提交代码前,对自动翻译的内容进行全面校验。重点关注:
- 语义准确性:检查翻译后的文本是否准确传达原文意图,有无语义偏差或歧义
- 代码兼容性:确认翻译后的代码能够与现有系统、框架正确集成,无语法或逻辑错误
- 格式规范性:保证翻译内容符合项目统一的代码风格与文件格式要求
通过细致的人工审核,可有效规避自动翻译潜在的问题,保障开发工作的顺利推进。