i18n-transform-cli
Version:
这是一款能够自动将代码里的中文转成i18n国际化标记的命令行工具。当然,你也可以用它实现将中文语言包自动翻译成其他语言。适用于vue2、vue3和react
314 lines (313 loc) • 12.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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 chalk_1 = __importDefault(require("chalk"));
const path_1 = __importDefault(require("path"));
const prettier_1 = __importDefault(require("prettier"));
const cli_progress_1 = __importDefault(require("cli-progress"));
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 exportExcel_1 = __importStar(require("./exportExcel"));
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_extra_1.default.statSync(inputPath).isDirectory()) {
log_1.default.error(`路径${inputPath}不是一个目录,请重新设置input参数`);
process.exit(1);
}
return true;
}
function getSourceFilePaths(input, exclude) {
if (isValidInput(input)) {
return glob_1.default.sync(`${input}/**/*.{cjs,mjs,js,ts,tsx,jsx,vue}`, {
ignore: exclude,
});
}
else {
return [];
}
}
function saveLocale(localePath) {
const keyMap = collector_1.default.getKeyMap();
console.log('keyMap', keyMap);
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 {
return {
translator: answers.translator,
google: {
proxy: answers.proxy,
},
};
}
}
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.prompt([
// {
// type: 'list',
// name: 'translator',
// message: '请选择翻译接口',
// default: YOUDAO,
// choices: [
// { name: '有道翻译', value: YOUDAO },
// { name: '谷歌翻译', value: GOOGLE },
// { name: '百度翻译', value: BAIDU },
// ],
// when(answers) {
// return !answers.skipTranslate
// },
// },
// {
// type: 'input',
// name: 'proxy',
// message: '使用谷歌服务需要翻墙,请输入代理地址',
// default: oldConfigCache.proxy || '',
// when(answers) {
// return answers.translator === GOOGLE
// },
// validate(input) {
// return input.length === 0 ? '代理地址不能为空' : true
// },
// },
// {
// type: 'input',
// name: 'key',
// message: '请输入有道翻译appKey',
// default: oldConfigCache.key || '',
// when(answers) {
// return answers.translator === YOUDAO
// },
// validate(input) {
// return input.length === 0 ? 'appKey不能为空' : true
// },
// },
// {
// type: 'input',
// name: 'secret',
// message: '请输入有道翻译appSecret',
// default: oldConfigCache.secret || '',
// when(answers) {
// return answers.translator === YOUDAO
// },
// validate(input) {
// return input.length === 0 ? 'appSecret不能为空' : true
// },
// },
// {
// type: 'input',
// name: 'key',
// message: '请输入百度翻译appId',
// default: oldConfigCache.key || '',
// when(answers) {
// return answers.translator === BAIDU
// },
// validate(input) {
// return input.length === 0 ? 'appKey不能为空' : true
// },
// },
// {
// type: 'input',
// name: 'secret',
// message: '请输入百度翻译appSecret',
// default: oldConfigCache.secret || '',
// when(answers) {
// return answers.translator === BAIDU
// },
// validate(input) {
// return input.length === 0 ? 'appSecret不能为空' : true
// },
// },
// ])
const answers = {
translator: 'youdao',
key: '5b2194113e67d35a',
secret: 'ZQ78pgasKncCNBjzDryKAsoeBPpd4o19',
};
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, localeFileType, } = i18nConfig;
log_1.default.debug(`命令行配置信息:`, i18nConfig);
let oldPrimaryLang = {};
const primaryLangPath = (0, getAbsolutePath_1.getAbsolutePath)(process.cwd(), localePath);
oldPrimaryLang = (0, getLang_1.default)(primaryLangPath);
if (!skipExtract) {
log_1.default.info('正在转换中文,请稍等...');
const sourceFilePaths = getSourceFilePaths(input, exclude);
const bar = new cli_progress_1.default.SingleBar({
format: `${chalk_1.default.cyan('提取进度:')} [{bar}] {percentage}% {value}/{total}`,
}, cli_progress_1.default.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('.', '');
collector_1.default.resetCountOfAdditions();
collector_1.default.setCurrentCollectorPath(sourceFilePath);
const { code } = (0, transform_1.default)(sourceCode, ext, rules, sourceFilePath);
log_1.default.verbose(`完成中文提取和语法转换:`, sourceFilePath);
// 只有文件提取过中文,或文件规则forceImport为true时,才重新写入文件
if (collector_1.default.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)(collector_1.default.getKeyMap()), collector_1.default.getCurrentFileKeyMap(), sourceFilePath);
collector_1.default.setKeyMap(newkeyMap);
collector_1.default.resetCurrentFileKeyMap();
}
bar.increment();
});
// 增量转换时,保留之前的提取的中文结果
if (i18nConfig.incremental) {
const newkeyMap = (0, merge_1.default)(oldPrimaryLang, collector_1.default.getKeyMap());
collector_1.default.setKeyMap(newkeyMap);
}
const extName = path_1.default.extname(localePath);
const savePath = localePath.replace(extName, `.${localeFileType}`);
console.log('savePath', savePath);
saveLocale(savePath);
bar.stop();
const endTime = new Date().getTime();
log_1.default.info(`耗时${((endTime - startTime) / 1000).toFixed(2)}s`);
}
console.log(''); // 空一行
console.log('localePath', localePath);
if (!skipTranslate) {
await (0, translate_1.default)(localePath, locales, oldPrimaryLang, {
translator: i18nConfig.translator,
google: i18nConfig.google,
youdao: i18nConfig.youdao,
baidu: i18nConfig.baidu,
});
}
log_1.default.success('转换完毕!');
if (i18nConfig.exportExcel) {
log_1.default.info(`正在导出excel翻译文件`);
(0, exportExcel_1.exportFieldExcel)();
(0, exportExcel_1.default)();
log_1.default.success(`导出完毕!`);
}
}
exports.default = default_1;