前端项目自动中英文翻译工具

220 阅读2分钟

背景

在日常开发流程中,国际化(i18n)翻译工作一直是效率瓶颈。每次新增或修改功能时,开发人员需要手动检索代码中所有需要翻译的中文文本,然后逐一复制到翻译配置文件中,并手动完成多语言翻译。这种方式不仅耗时耗力,还容易出现遗漏或格式不一致的问题。

翻译文件:

export default {
    用户信息: 'User information',
    姓名: 'Name',
};

目标

开发一个自动化翻译工具,通过简单的 npm 命令即可完成整个翻译流程,实现 "一键翻译" 的高效工作流。

功能

  1. 解析翻译文件获取已翻译词条
  • 自动识别已存在的翻译项,避免重复处理
  1. 中文文本提取引擎
  • 使用正则表达式精准匹配 $t()t() 函数中的中文文本
  • 内置中文文本过滤器,自动排除非中文内容
  • 与现有翻译文件比对,智能过滤已翻译内容
  1. 云端翻译服务集成
  • 支持 Google Translate API 批量翻译
  1. 翻译文件生成器
  • 保持原有翻译文件结构不变
  • 自动合并新翻译与现有内容
  • 生成格式化良好的翻译文件

代码实现

项目目录

image.png

根目录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);

说明

由于自动翻译存在局限性,可能无法完全贴合您的实际需求。为确保代码质量与功能准确性,建议在提交代码前,对自动翻译的内容进行全面校验。重点关注:

  • 语义准确性:检查翻译后的文本是否准确传达原文意图,有无语义偏差或歧义
  • 代码兼容性:确认翻译后的代码能够与现有系统、框架正确集成,无语法或逻辑错误
  • 格式规范性:保证翻译内容符合项目统一的代码风格与文件格式要求
    通过细致的人工审核,可有效规避自动翻译潜在的问题,保障开发工作的顺利推进。