UNPKG

i18-fe-automator

Version:

前端代码提取中文并替换成$t函数

412 lines (411 loc) 17.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const fs_extra_1 = __importDefault(require("fs-extra")); const inquirer_1 = __importDefault(require("inquirer")); const path_1 = __importDefault(require("path")); const prettier_1 = __importDefault(require("prettier")); const glob_1 = __importDefault(require("glob")); const merge_1 = __importDefault(require("lodash/merge")); const cloneDeep_1 = __importDefault(require("lodash/cloneDeep")); const transform_1 = __importDefault(require("./transform")); const log_1 = __importDefault(require("./utils/log")); const getAbsolutePath_1 = require("./utils/getAbsolutePath"); const collector_1 = __importDefault(require("./collector")); const translate_1 = __importDefault(require("./translate")); const getLang_1 = __importDefault(require("./utils/getLang")); const constants_1 = require("./utils/constants"); const stateManager_1 = __importDefault(require("./utils/stateManager")); const exportExcelEnAndCn_1 = __importDefault(require("./exportExcelEnAndCn")); const initConfig_1 = require("./utils/initConfig"); const saveLocaleFile_1 = require("./utils/saveLocaleFile"); const assertType_1 = require("./utils/assertType"); function isValidInput(input) { const inputPath = (0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), input); if (!fs_extra_1.default.existsSync(inputPath)) { log_1.default.error(`路径${inputPath}不存在,请重新设置input参数`); process.exit(1); } // if (!fs.statSync(inputPath).isDirectory()) { // log.error(`路径${inputPath}不是一个目录,请重新设置input参数`) // process.exit(1) // } return true; } function getSourceFilePaths(input, exclude) { if (isValidInput(input)) { // 先判断是否是单个文件 if (path_1.default.extname(input)) { return [input]; } return glob_1.default.sync(`${input}/**/*.{cjs,mjs,js,ts,tsx,jsx,vue}`, { ignore: exclude, }); } else { return []; } } function saveLocale(localePath, collector) { const keyMap = collector.getKeyMap(); const localeAbsolutePath = (0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), localePath); if (!fs_extra_1.default.existsSync(localeAbsolutePath)) { fs_extra_1.default.ensureFileSync(localeAbsolutePath); } if (!fs_extra_1.default.statSync(localeAbsolutePath).isFile()) { log_1.default.error(`路径${localePath}不是一个文件,请重新设置localePath参数`); process.exit(1); } (0, saveLocaleFile_1.saveLocaleFile)(keyMap, localeAbsolutePath); log_1.default.verbose(`输出中文语言包到指定位置:`, localeAbsolutePath); } function getPrettierParser(ext) { switch (ext) { case 'vue': return 'vue'; case 'ts': case 'tsx': return 'babel-ts'; default: return 'babel'; } } function getOutputPath(input, output, sourceFilePath) { let outputPath; if (output) { const filePath = sourceFilePath.replace(input + '/', ''); outputPath = (0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), output, filePath); fs_extra_1.default.ensureFileSync(outputPath); } else { outputPath = (0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), sourceFilePath); } return outputPath; } function formatInquirerResult(answers) { if (answers.translator === constants_1.YOUDAO) { return { translator: answers.translator, youdao: { key: answers.key, secret: answers.secret, }, }; } else if (answers.translator === constants_1.BAIDU) { return { translator: answers.translator, baidu: { key: answers.key, secret: answers.secret, }, }; } else if (answers.translator === constants_1.CHAT_GPT) { return { translator: answers.translator, chatGPT: { key: answers.key, proxy: answers.proxy, }, }; } else if (answers.translator === constants_1.GOOGLE) { return { translator: answers.translator, google: { proxy: answers.proxy, }, }; } else { return { translator: answers.translator, baiduAI: { access_token: answers.access_token, }, }; } } async function getTranslationConfig() { const cachePath = (0, getAbsolutePath_1.getAbsolutePath)(__dirname, '../.cache/configCache.json'); fs_extra_1.default.ensureFileSync(cachePath); const cache = fs_extra_1.default.readFileSync(cachePath, 'utf8') || '{}'; const oldConfigCache = JSON.parse(cache); const answers = await inquirer_1.default.prompt([ { type: 'list', name: 'translator', message: '请选择翻译接口', default: constants_1.BAIDU, choices: [ { name: '百度AI翻译', value: constants_1.BAIDU_AI }, { name: '百度翻译', value: constants_1.BAIDU }, { name: '有道翻译', value: constants_1.YOUDAO }, { name: '谷歌翻译', value: constants_1.GOOGLE }, { name: 'chatGPT翻译', value: constants_1.CHAT_GPT }, ], when(answers) { return !answers.skipTranslate; }, }, { type: 'input', name: 'proxy', message: '使用谷歌服务需要翻墙,请输入代理地址(如果已经翻墙,直接回车)', default: oldConfigCache.proxy || '', when(answers) { return answers.translator === constants_1.GOOGLE; }, // validate(input) { // return input.length === 0 ? '代理地址不能为空' : true // }, }, { type: 'input', name: 'proxy', message: '使用chatGPT服务需要翻墙,请输入代理地址(如果已经翻墙,直接回车)', default: oldConfigCache.proxy || '', when(answers) { return answers.translator === constants_1.CHAT_GPT; }, // validate(input) { // return input.length === 0 ? '代理地址不能为空' : true // }, }, { type: 'input', name: 'key', message: '使用chatGPT的OPENAI_API_KEY', default: oldConfigCache.key || '', when(answers) { return answers.translator === constants_1.CHAT_GPT; }, validate(input) { return input.length === 0 ? 'OPENAI_API_KEY不能为空' : true; }, }, { type: 'input', name: 'key', message: '请输入有道翻译appKey', default: oldConfigCache.key || '', when(answers) { return answers.translator === constants_1.YOUDAO; }, validate(input) { return input.length === 0 ? 'appKey不能为空' : true; }, }, { type: 'input', name: 'secret', message: '请输入有道翻译appSecret', default: oldConfigCache.secret || '', when(answers) { return answers.translator === constants_1.YOUDAO; }, validate(input) { return input.length === 0 ? 'appSecret不能为空' : true; }, }, { type: 'input', name: 'key', message: '请输入百度翻译appId', default: oldConfigCache.key || '', when(answers) { return answers.translator === constants_1.BAIDU; }, validate(input) { return input.length === 0 ? 'appKey不能为空' : true; }, }, { type: 'input', name: 'secret', message: '请输入百度翻译appSecret', default: oldConfigCache.secret || '', when(answers) { return answers.translator === constants_1.BAIDU; }, validate(input) { return input.length === 0 ? 'appSecret不能为空' : true; }, }, { type: 'input', name: 'access_token', message: '请输入百度AI翻译access_token', default: oldConfigCache.access_token || '', when(answers) { return answers.translator === constants_1.BAIDU_AI; }, validate(input) { return input.length === 0 ? 'access_token不能为空' : true; }, }, ]); const newConfigCache = Object.assign(oldConfigCache, answers); fs_extra_1.default.writeFileSync(cachePath, JSON.stringify(newConfigCache), 'utf8'); const result = formatInquirerResult(answers); return result; } function formatCode(code, ext, prettierConfig) { let stylizedCode = code; if ((0, assertType_1.isObject)(prettierConfig)) { stylizedCode = prettier_1.default.format(code, { ...prettierConfig, parser: getPrettierParser(ext), }); log_1.default.verbose(`格式化代码完成`); } return stylizedCode; } async function default_1(options) { let i18nConfig = (0, initConfig_1.getI18nConfig)(options); if (!i18nConfig.skipTranslate) { const translationConfig = await getTranslationConfig(); i18nConfig = (0, merge_1.default)(i18nConfig, translationConfig); } // 全局缓存脚手架配置 stateManager_1.default.setToolConfig(i18nConfig); const { input, exclude, output, rules, localePath, locales, skipExtract, skipTranslate, adjustKeyMap, } = i18nConfig; log_1.default.debug(`命令行配置信息:`, i18nConfig); let oldPrimaryLang = {}; // 主语言,中文json const primaryLangPath = (0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), localePath); oldPrimaryLang = (0, getLang_1.default)(primaryLangPath); const skipFiles = []; if (!skipExtract) { const cnCollector = collector_1.default.getInstance(); log_1.default.info('正在转换中文,请稍等...'); const sourceFilePaths = getSourceFilePaths(input, exclude); // const bar = new cliProgress.SingleBar( // { // format: `${chalk.cyan('提取进度:')} [{bar}] {percentage}% {value}/{total}`, // }, // cliProgress.Presets.shades_classic // ) const startTime = new Date().getTime(); // bar.start(sourceFilePaths.length, 0) sourceFilePaths.forEach((sourceFilePath) => { log_1.default.verbose(`正在提取文件中的中文:`, sourceFilePath); const sourceCode = fs_extra_1.default.readFileSync(sourceFilePath, 'utf8'); const ext = path_1.default.extname(sourceFilePath).replace('.', ''); cnCollector.resetCountOfAdditions(); cnCollector.setCurrentCollectorPath(sourceFilePath); // 判断sourceCode中是否包含$hxt if (sourceCode.indexOf('$hxt') > -1) { log_1.default.info(`当前文件包含$hxt,说明已经执行过脚本,跳过提取中文:` + sourceFilePath); skipFiles.push(sourceFilePath); return; } const { code } = (0, transform_1.default)(sourceCode, ext, rules, sourceFilePath, { collector: cnCollector, }); log_1.default.verbose(`完成中文提取和语法转换:`, sourceFilePath); // 只有文件提取过中文,或文件规则forceImport为true时,才重新写入文件 if (cnCollector.getCountOfAdditions() > 0 || rules[ext].forceImport) { const stylizedCode = formatCode(code, ext, i18nConfig.prettier); const outputPath = getOutputPath(input, output, sourceFilePath); fs_extra_1.default.writeFileSync(outputPath, stylizedCode, 'utf8'); log_1.default.verbose(`生成文件:`, outputPath); } // 自定义当前文件的keyMap if (adjustKeyMap) { const newkeyMap = adjustKeyMap((0, cloneDeep_1.default)(cnCollector.getKeyMap()), cnCollector.getCurrentFileKeyMap(), sourceFilePath); cnCollector.setKeyMap(newkeyMap); cnCollector.resetCurrentFileKeyMap(); } // bar.increment() }); // 增量转换时,保留之前的提取的中文结果 if (i18nConfig.incremental) { const newkeyMap = (0, merge_1.default)(oldPrimaryLang, cnCollector.getKeyMap()); cnCollector.setKeyMap(newkeyMap); } saveLocale(localePath, cnCollector); // bar.stop() const endTime = new Date().getTime(); log_1.default.info(`耗时${((endTime - startTime) / 1000).toFixed(2)}s`); } log_1.default.success('中文转换完毕!'); // 以上这些是把中文提取出来,并且更新zh-CN.json,还有cnCollector console.log(''); // 空一行 let targetContent = {}; if (!skipTranslate) { // localePath: 'src/locales/zh-CN.json', // locales: ['en-US'], // oldPrimaryLang,现在中文的内容 targetContent = await (0, translate_1.default)(localePath, locales, oldPrimaryLang, { translator: i18nConfig.translator, google: i18nConfig.google, youdao: i18nConfig.youdao, baidu: i18nConfig.baidu, chatGPT: i18nConfig.chatGPT, baiduAI: i18nConfig.baiduAI, }); log_1.default.success('英文转换完毕!'); const enCollector = collector_1.default.getInstance(); // log.success('英文JSON') // 全驼峰,无空格的英文key,hump-en-US.json // {你好世界: "HelloWorld"} log_1.default.success(JSON.stringify(targetContent)); // 将$t中的中文翻译成英文后再写入项目中 log_1.default.info('正在将$t代码中的key转成该中文(desc)对应的英文,请稍等...'); const sourceFilePaths = getSourceFilePaths(input, exclude); // const bar = new cliProgress.SingleBar( // { // format: `${chalk.cyan('提取进度:')} [{bar}] {percentage}% {value}/{total}`, // }, // cliProgress.Presets.shades_classic // ) // bar.start(sourceFilePaths.length, 0) sourceFilePaths.forEach((sourceFilePath, i) => { if (skipFiles.includes(sourceFilePath)) { return; } // log.verbose(`正在提取文件中的英文:`, sourceFilePath) const sourceCode = fs_extra_1.default.readFileSync(sourceFilePath, 'utf8'); const ext = path_1.default.extname(sourceFilePath).replace('.', ''); enCollector.resetCountOfAdditions(); enCollector.setCurrentCollectorPath(sourceFilePath); log_1.default.debug(`当前操作第${i + 1}个文件,路径是:${sourceFilePath}`); const { code } = (0, transform_1.default)(sourceCode, ext, rules, sourceFilePath, { sourceContent: targetContent, collector: enCollector, }); // log.verbose(`完成英文提取和语法转换:`, sourceFilePath) log_1.default.debug('enCollector.getCountOfAdditions()数量', enCollector.getCountOfAdditions()); if (enCollector.getCountOfAdditions() > 0) { log_1.default.debug('开始写入'); const stylizedCode = formatCode(code, ext, i18nConfig.prettier); const outputPath = getOutputPath(input, output, sourceFilePath); fs_extra_1.default.writeFileSync(outputPath, stylizedCode, 'utf8'); // log.verbose(`生成文件:`, outputPath) } // 自定义当前文件的keyMap if (adjustKeyMap) { const newkeyMap = adjustKeyMap((0, cloneDeep_1.default)(enCollector.getKeyMap()), enCollector.getCurrentFileKeyMap(), sourceFilePath); enCollector.setKeyMap(newkeyMap); enCollector.resetCurrentFileKeyMap(); } // bar.increment() }); // bar.stop() (0, exportExcelEnAndCn_1.default)(enCollector.getKeyValueMap()); log_1.default.success(`导出完毕!`); // 第三次处理 // 找到目录下所有$hxt方法,并且包含desc等于''的,用正则匹配 // sourceFilePaths.forEach((sourceFilePath, i) => {} } // if (i18nConfig.exportExcel) { // log.info(`正在导出excel翻译文件`) // exportExcel() // log.success(`导出完毕!`) // } } exports.default = default_1;