UNPKG

@erda-ui/cli

Version:

Command line interface for rapid Erda UI development

382 lines (381 loc) 18.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.batchSwitchNamespace = exports.switchSourceFileNs = exports.extractPendingSwitchContent = exports.restoreSourceFile = exports.writeI18nTToSourceFile = exports.extractUntranslatedWords = exports.extractAllI18nD = exports.filterTranslationGroup = exports.writeLocaleFiles = exports.prepareEnv = exports.findMatchFolder = exports.tempTranslatedWordPath = exports.tempFilePath = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const log_1 = require("./log"); const i18n_extract_1 = __importDefault(require("./i18n-extract")); const ora_1 = __importDefault(require("ora")); const lodash_1 = require("lodash"); const chalk_1 = __importDefault(require("chalk")); const inquirer_1 = __importDefault(require("inquirer")); const file_walker_1 = require("./file-walker"); const i18n_config_1 = require("./i18n-config"); exports.tempFilePath = path_1.default.resolve(process.cwd(), './temp-zh-words.json'); exports.tempTranslatedWordPath = path_1.default.resolve(process.cwd(), './temp-translated-words.json'); const findMatchFolder = (folderName, workDir) => { let targetPath = null; const loopFolder = (rootPath) => { const children = fs_1.default.readdirSync(rootPath, { withFileTypes: true }); if (children.length > 0) { children.some((child) => { const itemName = child.name; if (child.isDirectory() && !itemName.includes('node_modules') && !itemName.startsWith('.')) { const childPath = path_1.default.resolve(rootPath, itemName); if (itemName === folderName) { targetPath = childPath; return true; } return loopFolder(childPath); } return false; }); } }; loopFolder(workDir); return targetPath; }; exports.findMatchFolder = findMatchFolder; const prepareEnv = (isExternal, switchNs) => { let zhResource = {}; let enResource = {}; if (!switchNs && !fs_1.default.existsSync(exports.tempFilePath)) { fs_1.default.writeFileSync(exports.tempFilePath, JSON.stringify({}, null, 2), 'utf8'); } if (!switchNs && !fs_1.default.existsSync(exports.tempTranslatedWordPath)) { fs_1.default.writeFileSync(exports.tempTranslatedWordPath, JSON.stringify({}, null, 2), 'utf8'); } const localeMap = isExternal ? i18n_config_1.externalLocalePathMap : i18n_config_1.internalLocalePathMap; const localePaths = Object.values(localeMap); const originalLocaleResources = localePaths.reduce((acc, localePath) => { const zhJsonPath = `${localePath}/zh.json`; const enJsonPath = `${localePath}/en.json`; zhResource = JSON.parse(fs_1.default.readFileSync(zhJsonPath, 'utf8')); enResource = JSON.parse(fs_1.default.readFileSync(enJsonPath, 'utf8')); const moduleName = Object.keys(localeMap).find((key) => localeMap[key] === localePath); acc[moduleName] = [zhResource, enResource]; return acc; }, {}); return originalLocaleResources; }; exports.prepareEnv = prepareEnv; const writeLocaleFiles = (isExternal) => __awaiter(void 0, void 0, void 0, function* () { const promise = new Promise((resolve) => { (0, i18n_extract_1.default)(resolve, isExternal); }); const loading = (0, ora_1.default)('writing locale file...').start(); yield promise; loading.stop(); (0, log_1.logSuccess)('write locale file completed'); }); exports.writeLocaleFiles = writeLocaleFiles; const filterTranslationGroup = (toTranslateEnWords, zhResource, untranslatedWords, translatedWords) => { const notTranslatedWords = [...toTranslateEnWords]; Object.keys(zhResource).forEach((namespaceKey) => { const namespaceWords = zhResource[namespaceKey]; toTranslateEnWords.forEach((enWord) => { const convertedEnWord = enWord.replace(/:/g, ':'); if (namespaceWords[convertedEnWord] && !translatedWords[convertedEnWord]) { translatedWords[convertedEnWord] = namespaceKey === 'default' ? namespaceWords[convertedEnWord] : `${namespaceKey}:${namespaceWords[convertedEnWord]}`; (0, lodash_1.remove)(notTranslatedWords, (w) => w === enWord); } }); }); notTranslatedWords.forEach(untranslatedWords.add, untranslatedWords); }; exports.filterTranslationGroup = filterTranslationGroup; const i18nDRegex = /i18n\.d\(["'](.+?)["']\)/g; const extractAllI18nD = (isExternal, originalResource, translatedWords, untranslatedWords) => __awaiter(void 0, void 0, void 0, function* () { const dirMap = isExternal ? i18n_config_1.externalSrcDirMap : i18n_config_1.internalSrcDirMap; const promises = Object.values(dirMap) .flat() .map((srcPath) => { return new Promise((resolve) => { const moduleName = Object.keys(dirMap).find((key) => dirMap[key].includes(srcPath)); const [zhResource] = originalResource[moduleName]; (0, file_walker_1.walker)({ root: srcPath, excludePath: i18n_config_1.excludeSrcDirs, dealFile: (...args) => { exports.extractUntranslatedWords.apply(null, [ ...args, !isExternal ? (0, lodash_1.merge)(zhResource, originalResource.default[0]) : zhResource, translatedWords, untranslatedWords, resolve, ]); }, }); }); }); yield Promise.all(promises); if (untranslatedWords.size > 0) { const enMap = {}; untranslatedWords.forEach((word) => { enMap[word] = ''; }); fs_1.default.writeFileSync(exports.tempFilePath, JSON.stringify(enMap, null, 2), 'utf8'); (0, log_1.logSuccess)(`Finish writing to the temporary file ${chalk_1.default.green('[temp-zh-words.json]')}`); } if (Object.keys(translatedWords).length > 0) { fs_1.default.writeFileSync(exports.tempTranslatedWordPath, JSON.stringify(translatedWords, null, 2), 'utf8'); (0, log_1.logSuccess)(`Finish writing to the temporary file ${chalk_1.default.green('[temp-translated-words.json]')}`); } }); exports.extractAllI18nD = extractAllI18nD; const extractUntranslatedWords = (content, filePath, isEnd, zhResource, translatedWords, untranslatedWords, resolve) => { if (!['.tsx', '.ts', '.js', '.jsx'].includes(path_1.default.extname(filePath)) && !isEnd) { return; } let match = i18nDRegex.exec(content); const toTransEnglishWords = []; while (match) { if (match) { toTransEnglishWords.push(match[1]); } match = i18nDRegex.exec(content); } if (!isEnd && !toTransEnglishWords.length) { return; } (0, exports.filterTranslationGroup)(toTransEnglishWords.filter((enWord) => !untranslatedWords.has(enWord) && !translatedWords[enWord]), zhResource, untranslatedWords, translatedWords); if (isEnd) { resolve(); } }; exports.extractUntranslatedWords = extractUntranslatedWords; const writeI18nTToSourceFile = (isExternal, ns, translatedMap, reviewedZhMap) => __awaiter(void 0, void 0, void 0, function* () { const dirMap = isExternal ? i18n_config_1.externalSrcDirMap : i18n_config_1.internalSrcDirMap; const promises = Object.values(dirMap) .flat() .map((srcPath) => { let namespace = ns; if (isExternal) { const moduleName = Object.keys(dirMap).find((name) => dirMap[name].includes(srcPath)); namespace = i18n_config_1.externalModuleNamespace[moduleName]; } const generatePromise = new Promise((resolve) => { (0, file_walker_1.walker)({ root: srcPath, dealFile: (...args) => { exports.restoreSourceFile.apply(null, [...args, namespace, translatedMap, reviewedZhMap, resolve]); }, }); }); return generatePromise; }); yield Promise.all(promises); }); exports.writeI18nTToSourceFile = writeI18nTToSourceFile; const restoreSourceFile = (content, filePath, isEnd, ns, translatedMap, reviewedZhMap, resolve) => { if (!['.tsx', '.ts', '.js', '.jsx'].includes(path_1.default.extname(filePath)) && !isEnd) { return; } let match = i18nDRegex.exec(content); let newContent = content; let changed = false; while (match) { if (match) { const [fullMatch, enWord] = match; let replaceText; const convertedEnWord = enWord.replace(/:/g, ':'); if (reviewedZhMap === null || reviewedZhMap === void 0 ? void 0 : reviewedZhMap[enWord]) { const i18nContent = ns === 'default' ? `i18n.t('${convertedEnWord}')` : `i18n.t('${ns}:${convertedEnWord}')`; replaceText = i18nContent; } else if (translatedMap === null || translatedMap === void 0 ? void 0 : translatedMap[convertedEnWord]) { const nsArray = translatedMap === null || translatedMap === void 0 ? void 0 : translatedMap[convertedEnWord].split(':'); replaceText = nsArray.length === 2 ? `i18n.t('${nsArray[0]}:${convertedEnWord}')` : `i18n.t('${convertedEnWord}')`; } else { (0, log_1.logWarn)(convertedEnWord, 'not yet translated'); } if (replaceText) { newContent = newContent.replace(fullMatch, replaceText); changed = true; } } match = i18nDRegex.exec(content); } if (changed) { fs_1.default.writeFileSync(filePath, newContent, 'utf8'); } if (isEnd) { resolve(); } }; exports.restoreSourceFile = restoreSourceFile; const i18nRRegex = /i18n\.r\(\s*('|")([^'"]+)(?:'|")([^)\n]*)\s*\)/g; const extractPendingSwitchContent = (content, filePath, isEnd, ns, toSwitchWords, resolve) => { if (!['.tsx', '.ts', '.js', '.jsx'].includes(path_1.default.extname(filePath)) && !isEnd) { return; } let match = i18nRRegex.exec(content); let replacedText = content; let changed = false; while (match) { if (match) { const matchedText = match[2]; const quote = match[1]; toSwitchWords.add(matchedText); const wordArr = matchedText.split(':'); const enWord = wordArr.length === 2 ? wordArr[1] : matchedText; const newWordText = ns === 'default' ? enWord : `${ns}:${enWord}`; replacedText = replacedText.replace(match[0], `i18n.t(${quote}${newWordText}${quote}${match[3] || ''})`); changed = true; } match = i18nRRegex.exec(content); } if (changed) { fs_1.default.writeFileSync(filePath, replacedText, 'utf8'); } if (!isEnd && toSwitchWords.size === 0) { return; } if (isEnd) { resolve(); } }; exports.extractPendingSwitchContent = extractPendingSwitchContent; const switchSourceFileNs = (content, filePath, isEnd, ns, toSwitchWords, resolve) => { if (!['.tsx', '.ts', '.js', '.jsx'].includes(path_1.default.extname(filePath)) && !isEnd) { return; } let newContent = content; let changed = false; toSwitchWords.forEach((wordWithNs) => { const matchTextRegex = new RegExp(`i18n\\.t\\(\\s*('|")${wordWithNs}(?:'|")([^\\)\\n]*)\\s*\\)`, 'g'); let match = matchTextRegex.exec(content); while (match) { changed = true; const matchedText = match[0]; const quote = match[1]; const wordArr = wordWithNs.split(':'); const enWord = wordArr.length === 2 ? wordArr[1] : wordWithNs; const newWordText = ns === 'default' ? enWord : `${ns}:${enWord}`; newContent = newContent.replace(matchedText, `i18n.t(${quote}${newWordText}${quote}${match[2] || ''})`); match = matchTextRegex.exec(content); } }); if (changed) { fs_1.default.writeFileSync(filePath, newContent, 'utf8'); } if (isEnd) { resolve(); } }; exports.switchSourceFileNs = switchSourceFileNs; const getNamespaceModuleName = (originalResources, currentNs) => { let result = null; Object.entries(originalResources).some(([moduleName, content]) => { const [zhResource] = content; if (zhResource[currentNs]) { result = moduleName; return true; } return false; }); return result; }; const batchSwitchNamespace = (originalResources) => __awaiter(void 0, void 0, void 0, function* () { const toSwitchWords = new Set(); const nsList = Object.values(originalResources).reduce((acc, resource) => { const [zhResource] = resource; return acc.concat(Object.keys(zhResource)); }, []); const { targetNs } = yield inquirer_1.default.prompt({ name: 'targetNs', type: 'list', message: 'Please select the new namespace name', choices: nsList.map((ns) => ({ value: ns, name: ns })), }); const promises = Object.values(i18n_config_1.internalSrcDirMap) .flat() .map((srcDir) => { return new Promise((resolve) => { (0, file_walker_1.walker)({ root: srcDir, dealFile: (...args) => { exports.extractPendingSwitchContent.apply(null, [...args, targetNs, toSwitchWords, resolve]); }, }); }); }); yield Promise.all(promises); if (toSwitchWords.size) { const restorePromises = Object.values(i18n_config_1.internalSrcDirMap) .flat() .map((srcDir) => { return new Promise((resolve) => { (0, file_walker_1.walker)({ root: srcDir, dealFile: (...args) => { exports.switchSourceFileNs.apply(null, [...args, targetNs, toSwitchWords, resolve]); }, }); }); }); yield Promise.all(restorePromises); for (const wordWithNs of toSwitchWords) { const wordArr = wordWithNs.split(':'); const [currentNs, enWord] = wordArr.length === 2 ? wordArr : ['default', wordWithNs]; const currentModuleName = getNamespaceModuleName(originalResources, currentNs); const targetModuleName = getNamespaceModuleName(originalResources, targetNs); if (!currentModuleName || !targetModuleName) { (0, log_1.logError)(`${currentModuleName} or ${targetModuleName} does not exist in locale files`); return; } const targetNsContent = originalResources[targetModuleName][0][targetNs]; const currentNsContent = originalResources[currentModuleName][0][currentNs]; if (!targetNsContent[enWord] || targetNsContent[enWord] === currentNsContent[enWord]) { targetNsContent[enWord] = currentNsContent[enWord]; } else { const confirm = yield inquirer_1.default.prompt({ name: 'confirm', type: 'confirm', message: `${chalk_1.default.red(enWord)} has translation in target namespace ${targetNs} with value ${chalk_1.default.yellow(targetNsContent[enWord])}, Do you want to override it with ${chalk_1.default.yellow(currentNsContent[enWord])}?`, }); if (confirm) { targetNsContent[enWord] = currentNsContent[enWord]; } } currentNs !== targetNs && (0, lodash_1.unset)(currentNsContent, enWord); const targetNsEnContent = originalResources[targetModuleName][1][targetNs]; const currentNsEnContent = originalResources[currentModuleName][1][currentNs]; if (!targetNsEnContent[enWord]) { targetNsEnContent[enWord] = currentNsEnContent[enWord]; } currentNs !== targetNs && (0, lodash_1.unset)(currentNsEnContent, enWord); } for (const moduleName of Object.keys(originalResources)) { const [zhResource, enResource] = originalResources[moduleName]; const localePath = i18n_config_1.internalLocalePathMap[moduleName]; fs_1.default.writeFileSync(`${localePath}/zh.json`, JSON.stringify(zhResource, null, 2), 'utf8'); fs_1.default.writeFileSync(`${localePath}/en.json`, JSON.stringify(enResource, null, 2), 'utf8'); } (0, log_1.logInfo)('sort current locale files & remove unused translation'); yield (0, exports.writeLocaleFiles)(false); (0, log_1.logSuccess)('switch namespace done.'); } else { (0, log_1.logWarn)(`no ${chalk_1.default.red('i18n.r')} found in source code. program exit`); } }); exports.batchSwitchNamespace = batchSwitchNamespace;