@erda-ui/cli
Version:
Command line interface for rapid Erda UI development
382 lines (381 loc) • 18.1 kB
JavaScript
;
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;