UNPKG

@lingui/cli

Version:

CLI for working wit message catalogs

172 lines (171 loc) 7.55 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = command; const picocolors_1 = __importDefault(require("picocolors")); const chokidar_1 = __importDefault(require("chokidar")); const commander_1 = require("commander"); const path_1 = __importDefault(require("path")); const conf_1 = require("@lingui/conf"); const api_1 = require("./api"); const stats_1 = require("./api/stats"); const help_1 = require("./api/help"); const ora_1 = __importDefault(require("ora")); const normalize_path_1 = __importDefault(require("normalize-path")); async function command(config, options) { options.verbose && console.log("Extracting messages from source files…"); const catalogs = await (0, api_1.getCatalogs)(config); const catalogStats = {}; let commandSuccess = true; const spinner = (0, ora_1.default)().start(); await Promise.all(catalogs.map(async (catalog) => { const result = await catalog.make(Object.assign(Object.assign({}, options), { orderBy: config.orderBy })); catalogStats[(0, normalize_path_1.default)(path_1.default.relative(config.rootDir, catalog.path))] = result || {}; commandSuccess && (commandSuccess = Boolean(result)); })); if (commandSuccess) { spinner.succeed(); } else { spinner.fail(); } Object.entries(catalogStats).forEach(([key, value]) => { console.log(`Catalog statistics for ${key}: `); console.log((0, stats_1.printStats)(config, value).toString()); console.log(); }); if (!options.watch) { console.log(`(Use "${picocolors_1.default.yellow((0, help_1.helpRun)("extract"))}" to update catalogs with new messages.)`); console.log(`(Use "${picocolors_1.default.yellow((0, help_1.helpRun)("compile"))}" to compile catalogs for production. Alternatively, use bundler plugins: https://lingui.dev/ref/cli#compiling-catalogs-in-ci)`); } // If service key is present in configuration, synchronize with cloud translation platform if (typeof config.service === "object" && config.service.name && config.service.name.length) { const moduleName = config.service.name.charAt(0).toLowerCase() + config.service.name.slice(1); try { const module = require(`./services/${moduleName}`); await module .default(config, options) .then(console.log) .catch(console.error); } catch (err) { console.error(`Can't load service module ${moduleName}`, err); } } return commandSuccess; } if (require.main === module) { commander_1.program .option("--config <path>", "Path to the config file") .option("--locale <locale, [...]>", "Only extract the specified locales", (value) => { return value .split(",") .map((s) => s.trim()) .filter(Boolean); }) .option("--overwrite", "Overwrite translations for source locale") .option("--clean", "Remove obsolete translations") .option("--debounce <delay>", "Debounces extraction for given amount of milliseconds") .option("--verbose", "Verbose output") .option("--convert-from <format>", "Convert from previous format of message catalogs") .option("--watch", "Enables Watch Mode") .parse(process.argv); const options = commander_1.program.opts(); const config = (0, conf_1.getConfig)({ configPath: options.config, }); let hasErrors = false; const prevFormat = options.convertFrom; if (prevFormat && config.format === prevFormat) { hasErrors = true; console.error("Trying to migrate message catalog to the same format"); console.error(`Set ${picocolors_1.default.bold("new")} format in LinguiJS configuration\n` + ` and ${picocolors_1.default.bold("previous")} format using --convert-from option.`); console.log(); console.log(`Example: Convert from lingui format to minimal`); console.log(picocolors_1.default.yellow((0, help_1.helpRun)(`extract --convert-from lingui`))); process.exit(1); } if (options.locale) { const missingLocale = options.locale.find((l) => !config.locales.includes(l)); if (missingLocale) { hasErrors = true; console.error(`Locale ${picocolors_1.default.bold(missingLocale)} does not exist.`); console.error(); } } if (hasErrors) process.exit(1); const extract = (filePath) => { return command(config, { verbose: options.watch || options.verbose || false, clean: options.watch ? false : options.clean || false, overwrite: options.watch || options.overwrite || false, locale: options.locale, watch: options.watch || false, files: (filePath === null || filePath === void 0 ? void 0 : filePath.length) ? filePath : undefined, prevFormat, }); }; const changedPaths = new Set(); let debounceTimer; let previousExtract = Promise.resolve(true); const dispatchExtract = (filePath) => { // Skip debouncing if not enabled but still chain them so no racing issue // on deleting the tmp folder. if (!options.debounce) { previousExtract = previousExtract.then(() => extract(filePath)); return previousExtract; } filePath === null || filePath === void 0 ? void 0 : filePath.forEach((path) => changedPaths.add(path)); // CLear the previous timer if there is any, and schedule the next debounceTimer && clearTimeout(debounceTimer); debounceTimer = setTimeout(async () => { const filePath = [...changedPaths]; changedPaths.clear(); await extract(filePath); }, options.debounce); }; // Check if Watch Mode is enabled if (options.watch) { console.info(picocolors_1.default.bold("Initializing Watch Mode...")); (async function initWatch() { const catalogs = await (0, api_1.getCatalogs)(config); const paths = []; const ignored = []; catalogs.forEach((catalog) => { paths.push(...catalog.include); ignored.push(...catalog.exclude); }); const watcher = chokidar_1.default.watch(paths, { ignored: ["/(^|[/\\])../", ...ignored], persistent: true, }); const onReady = () => { console.info(picocolors_1.default.green(picocolors_1.default.bold("Watcher is ready!"))); watcher .on("add", (path) => dispatchExtract([path])) .on("change", (path) => dispatchExtract([path])); }; watcher.on("ready", () => onReady()); })(); } else if (commander_1.program.args) { // this behaviour occurs when we extract files by his name // for ex: lingui extract src/app, this will extract only files included in src/app extract(commander_1.program.args).then((result) => { if (!result) process.exit(1); }); } else { extract().then((result) => { if (!result) process.exit(1); }); } }