Socket
Socket
Sign inDemoInstall

@lingui/cli

Package Overview
Dependencies
Maintainers
3
Versions
149
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lingui/cli - npm Package Compare versions

Comparing version 3.17.2 to 4.0.0-next.0

./build/lingui.js

409

build/api/catalog.js

@@ -7,19 +7,14 @@ "use strict";

exports.cleanObsolete = exports.Catalog = void 0;
exports.getCatalogForFile = getCatalogForFile;
exports.getCatalogForMerge = getCatalogForMerge;
exports.getCatalogs = getCatalogs;
exports.normalizeRelativePath = normalizeRelativePath;
exports.order = order;
exports.orderByMessageId = orderByMessageId;
exports.orderByOrigin = orderByOrigin;
var _os = _interopRequireDefault(require("os"));
var _fsExtra = _interopRequireDefault(require("fs-extra"));
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var R = _interopRequireWildcard(require("ramda"));
var _chalk = _interopRequireDefault(require("chalk"));
var _glob = _interopRequireDefault(require("glob"));
var _micromatch = _interopRequireDefault(require("micromatch"));
var _normalizePath = _interopRequireDefault(require("normalize-path"));
var _formats = _interopRequireDefault(require("./formats"));
var _extractors = _interopRequireDefault(require("./extractors"));
var _formats = require("./formats");
var _getTranslationsForCatalog = require("./catalog/getTranslationsForCatalog");
var _mergeCatalog = require("./catalog/mergeCatalog");
var _extractFromFiles = require("./catalog/extractFromFiles");
var _utils = require("./utils");

@@ -29,9 +24,4 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const NAME = "{name}";
const NAME_REPLACE_RE = /{name}/g;
const LOCALE = "{locale}";
const LOCALE_REPLACE_RE = /{locale}/g;
const LOCALE_SUFFIX_RE = /\{locale\}.*$/;
const PATHSEP = "/"; // force posix everywhere
class Catalog {

@@ -42,13 +32,17 @@ constructor({

include,
templatePath,
exclude = []
}, config) {
this.config = config;
this.name = name;
this.path = normalizeRelativePath(path);
this.include = include.map(normalizeRelativePath);
this.exclude = [this.localeDir, ...exclude.map(normalizeRelativePath)];
this.config = config;
this.format = (0, _formats.default)(config.format);
this.path = (0, _utils.normalizeRelativePath)(path);
this.include = include.map(_utils.normalizeRelativePath);
this.exclude = [this.localeDir, ...exclude.map(_utils.normalizeRelativePath)];
this.format = (0, _formats.getFormat)(config.format);
this.templateFile = templatePath || getTemplatePath(this.format, this.path);
}
async make(options) {
const nextCatalog = await this.collect(options);
const nextCatalog = await this.collect({
files: options.files
});
if (!nextCatalog) return false;

@@ -73,10 +67,12 @@ const prevCatalogs = this.readAll();

}
return true;
return sortedCatalogs;
}
async makeTemplate(options) {
const catalog = await this.collect(options);
const catalog = await this.collect({
files: options.files
});
if (!catalog) return false;
const sort = order(options.orderBy);
this.writeTemplate(sort(catalog));
return true;
const sorted = order(options.orderBy)(catalog);
this.writeTemplate(sorted);
return sorted;
}

@@ -87,154 +83,45 @@

*/
async collect(options) {
const tmpDir = _path.default.join(_os.default.tmpdir(), `lingui-${process.pid}`);
if (_fsExtra.default.existsSync(tmpDir)) {
(0, _utils.removeDirectory)(tmpDir, true);
} else {
_fsExtra.default.mkdirSync(tmpDir);
async collect(options = {}) {
let paths = this.sourcePaths;
if (options.files) {
options.files = options.files.map(p => (0, _normalizePath.default)(p, false));
const regex = new RegExp(options.files.join("|"), "i");
paths = paths.filter(path => regex.test(path));
}
try {
let paths = this.sourcePaths;
if (options.files) {
options.files = options.files.map(p => (0, _normalizePath.default)(p, false));
const regex = new RegExp(options.files.join("|"), "i");
paths = paths.filter(path => regex.test(path));
}
let catalogSuccess = true;
for (let filename of paths) {
const fileSuccess = await (0, _extractors.default)(filename, tmpDir, {
verbose: options.verbose,
configPath: options.configPath,
babelOptions: this.config.extractBabelOptions,
extractors: options.extractors,
projectType: options.projectType
});
catalogSuccess && (catalogSuccess = fileSuccess);
}
if (!catalogSuccess) return undefined;
return function traverse(directory) {
return _fsExtra.default.readdirSync(directory).map(filename => {
const filepath = _path.default.join(directory, filename);
if (_fsExtra.default.lstatSync(filepath).isDirectory()) {
return traverse(filepath);
}
if (!filename.endsWith(".json")) return;
try {
return JSON.parse(_fsExtra.default.readFileSync(filepath).toString());
} catch (e) {}
}).filter(Boolean).reduce((catalog, messages) => R.mergeWithKey(mergeOriginsAndExtractedComments, catalog, messages), {});
}(tmpDir);
} catch (e) {
throw e;
} finally {
(0, _utils.removeDirectory)(tmpDir);
}
return await (0, _extractFromFiles.extractFromFiles)(paths, this.config);
}
/*
*
* prevCatalogs - map of message catalogs in all available languages with translations
* nextCatalog - language-agnostic catalog with collected messages
*
* Note: if a catalog in prevCatalogs is null it means the language is available, but
* no previous catalog was generated (usually first run).
*
* Orthogonal use-cases
* --------------------
*
* Message IDs:
* - auto-generated IDs: message is used as a key, `defaults` is not set
* - custom IDs: message is used as `defaults`, custom ID as a key
*
* Source locale (defined by `sourceLocale` in config):
* - catalog for `sourceLocale`: initially, `translation` is prefilled with `defaults`
* (for custom IDs) or `key` (for auto-generated IDs)
* - all other languages: translation is kept empty
*/
merge(prevCatalogs, nextCatalog, options) {
const nextKeys = R.keys(nextCatalog).map(String);
return R.mapObjIndexed((prevCatalog, locale) => {
const prevKeys = R.keys(prevCatalog).map(String);
const newKeys = R.difference(nextKeys, prevKeys);
const mergeKeys = R.intersection(nextKeys, prevKeys);
const obsoleteKeys = R.difference(prevKeys, nextKeys);
// Initialize new catalog with new keys
const newMessages = R.mapObjIndexed((message, key) => ({
translation: this.config.sourceLocale === locale ? message.message || key : "",
...message
}), R.pick(newKeys, nextCatalog));
// Merge translations from previous catalog
const mergedMessages = mergeKeys.map(key => {
const updateFromDefaults = this.config.sourceLocale === locale && (prevCatalog[key].translation === prevCatalog[key].message || options.overwrite);
const translation = updateFromDefaults ? nextCatalog[key].message || key : prevCatalog[key].translation;
return {
[key]: {
translation,
...R.omit(["obsolete, translation"], nextCatalog[key])
}
};
});
// Mark all remaining translations as obsolete
// Only if *options.files* is not provided
const obsoleteMessages = obsoleteKeys.map(key => ({
[key]: {
...prevCatalog[key],
obsolete: options.files ? false : true
}
}));
return R.mergeAll([newMessages, ...mergedMessages, ...obsoleteMessages]);
return (0, _mergeCatalog.mergeCatalog)(prevCatalog, nextCatalog, this.config.sourceLocale === locale, options);
}, prevCatalogs);
}
getTranslations(locale, options) {
const catalogs = this.readAll();
const template = this.readTemplate() || {};
return R.mapObjIndexed((_value, key) => this.getTranslation(catalogs, locale, key, options), {
...template,
...catalogs[locale]
});
return (0, _getTranslationsForCatalog.getTranslationsForCatalog)(this, locale, options);
}
getTranslation(catalogs, locale, key, {
fallbackLocales,
sourceLocale
}) {
var _catalog$key;
const catalog = catalogs[locale] || {};
const getTranslation = _locale => {
const configLocales = this.config.locales.join('", "');
const localeCatalog = catalogs[_locale] || {};
if (!localeCatalog) {
console.warn(`
Catalog "${_locale}" isn't present in locales config parameter
Add "${_locale}" to your lingui.config.js:
{
locales: ["${configLocales}", "${_locale}"]
}
`);
return null;
}
if (!localeCatalog.hasOwnProperty(key)) {
return null;
}
if (catalogs[_locale]) {
return catalogs[_locale][key].translation;
}
return null;
};
const getMultipleFallbacks = _locale => {
const fL = fallbackLocales && fallbackLocales[_locale];
// some probably the fallback will be undefined, so just search by locale
if (!fL) return null;
if (Array.isArray(fL)) {
for (const fallbackLocale of fL) {
if (catalogs[fallbackLocale]) {
return getTranslation(fallbackLocale);
}
}
} else {
return getTranslation(fL);
}
};
return (
// Get translation in target locale
getTranslation(locale) ||
// We search in fallbackLocales as dependent of each locale
getMultipleFallbacks(locale) ||
// Get translation in fallbackLocales.default (if any)
(fallbackLocales === null || fallbackLocales === void 0 ? void 0 : fallbackLocales.default) && getTranslation(fallbackLocales.default) || ( // Get message default
(_catalog$key = catalog[key]) === null || _catalog$key === void 0 ? void 0 : _catalog$key.defaults) ||
// If sourceLocale is either target locale of fallback one, use key
sourceLocale && sourceLocale === locale && key || sourceLocale && (fallbackLocales === null || fallbackLocales === void 0 ? void 0 : fallbackLocales.default) && sourceLocale === fallbackLocales.default && key ||
// Otherwise no translation is available
undefined
);
}
write(locale, messages) {
const filename = this.path.replace(LOCALE_REPLACE_RE, locale) + this.format.catalogExtension;
const created = !_fsExtra.default.existsSync(filename);
const basedir = _path.default.dirname(filename);
if (!_fsExtra.default.existsSync(basedir)) {
_fsExtra.default.mkdirpSync(basedir);
}
const filename = (0, _utils.replacePlaceholders)(this.path, {
locale
}) + this.format.catalogExtension;
const created = !_fs.default.existsSync(filename);
const options = {

@@ -252,6 +139,2 @@ ...this.config.formatOptions,

const filename = this.templateFile;
const basedir = _path.default.dirname(filename);
if (!_fsExtra.default.existsSync(basedir)) {
_fsExtra.default.mkdirpSync(basedir);
}
const options = {

@@ -272,13 +155,12 @@ ...this.config.formatOptions,

}
const filename = `${this.path.replace(LOCALE_REPLACE_RE, locale)}.${ext}`;
const basedir = _path.default.dirname(filename);
if (!_fsExtra.default.existsSync(basedir)) {
_fsExtra.default.mkdirpSync(basedir);
}
_fsExtra.default.writeFileSync(filename, compiledCatalog);
const filename = `${(0, _utils.replacePlaceholders)(this.path, {
locale
})}.${ext}`;
(0, _utils.writeFile)(filename, compiledCatalog);
return filename;
}
read(locale) {
const filename = this.path.replace(LOCALE_REPLACE_RE, locale) + this.format.catalogExtension;
if (!_fsExtra.default.existsSync(filename)) return null;
const filename = (0, _utils.replacePlaceholders)(this.path, {
locale
}) + this.format.catalogExtension;
return this.format.read(filename);

@@ -293,3 +175,2 @@ }

const filename = this.templateFile;
if (!_fsExtra.default.existsSync(filename)) return null;
return this.format.read(filename);

@@ -299,3 +180,3 @@ }

const includeGlobs = this.include.map(includePath => {
const isDir = _fsExtra.default.existsSync(includePath) && _fsExtra.default.lstatSync(includePath).isDirectory();
const isDir = (0, _utils.isDirectory)(includePath);
/**

@@ -313,5 +194,2 @@ * glob library results from absolute patterns such as /foo/* are mounted onto the root setting using path.join.

}
get templateFile() {
return this.path.replace(LOCALE_SUFFIX_RE, "messages.pot");
}
get localeDir() {

@@ -328,147 +206,7 @@ const localePatternIndex = this.path.indexOf(LOCALE);

}
/**
* Parse `config.catalogs` and return a list of configured Catalog instances.
*/
exports.Catalog = Catalog;
function getCatalogs(config) {
const catalogsConfig = config.catalogs;
const catalogs = [];
catalogsConfig.forEach(catalog => {
// Validate that `catalogPath` doesn't end with trailing slash
if (catalog.path.endsWith(PATHSEP)) {
const extension = (0, _formats.default)(config.format).catalogExtension;
const correctPath = catalog.path.slice(0, -1);
const examplePath = correctPath.replace(LOCALE_REPLACE_RE,
// Show example using one of configured locales (if any)
(config.locales || [])[0] || "en") + extension;
throw new Error(
// prettier-ignore
`Remove trailing slash from "${catalog.path}". Catalog path isn't a directory,` + ` but translation file without extension. For example, catalog path "${correctPath}"` + ` results in translation file "${examplePath}".`);
}
const include = ensureArray(catalog.include).map(normalizeRelativePath);
const exclude = ensureArray(catalog.exclude).map(normalizeRelativePath);
// catalog.path without {name} pattern -> always refers to a single catalog
if (!catalog.path.includes(NAME)) {
// Validate that sourcePaths doesn't use {name} pattern either
const invalidSource = include.find(path => path.includes(NAME));
if (invalidSource !== undefined) {
throw new Error(`Catalog with path "${catalog.path}" doesn't have a {name} pattern` + ` in it, but one of source directories uses it: "${invalidSource}".` + ` Either add {name} pattern to "${catalog.path}" or remove it` + ` from all source directories.`);
}
// catalog name is the last directory of catalog.path.
// If the last part is {locale}, then catalog doesn't have an explicit name
const name = function () {
const _name = catalog.path.split(PATHSEP).slice(-1)[0];
return _name !== LOCALE ? _name : null;
}();
catalogs.push(new Catalog({
name,
path: normalizeRelativePath(catalog.path),
include,
exclude
}, config));
return;
}
const patterns = include.map(path => path.replace(NAME_REPLACE_RE, "*"));
const candidates = _glob.default.sync(patterns.length > 1 ? `{${patterns.join(",")}}` : patterns[0], {
ignore: exclude,
mark: true
});
candidates.forEach(catalogDir => {
const name = _path.default.basename(catalogDir);
catalogs.push(new Catalog({
name,
path: normalizeRelativePath(catalog.path.replace(NAME_REPLACE_RE, name)),
include: include.map(path => path.replace(NAME_REPLACE_RE, name)),
exclude: exclude.map(path => path.replace(NAME_REPLACE_RE, name))
}, config));
});
});
return catalogs;
function getTemplatePath(format, path) {
const ext = format.templateExtension || format.catalogExtension;
return path.replace(LOCALE_SUFFIX_RE, "messages" + ext);
}
function getCatalogForFile(file, catalogs) {
for (const catalog of catalogs) {
const catalogFile = `${catalog.path}${catalog.format.catalogExtension}`;
const catalogGlob = catalogFile.replace(LOCALE_REPLACE_RE, "*");
const match = _micromatch.default.capture(normalizeRelativePath(_path.default.relative(catalog.config.rootDir, catalogGlob)), normalizeRelativePath(file));
if (match) {
return {
locale: match[0],
catalog
};
}
}
return null;
}
/**
* Create catalog for merged messages.
*/
function getCatalogForMerge(config) {
const catalogConfig = config;
if (catalogConfig.catalogsMergePath.endsWith(PATHSEP)) {
const extension = (0, _formats.default)(config.format).catalogExtension;
const correctPath = catalogConfig.catalogsMergePath.slice(0, -1);
const examplePath = correctPath.replace(LOCALE_REPLACE_RE,
// Show example using one of configured locales (if any)
(config.locales || [])[0] || "en") + extension;
throw new Error(
// prettier-ignore
`Remove trailing slash from "${catalogConfig.catalogsMergePath}". Catalog path isn't a directory,` + ` but translation file without extension. For example, catalog path "${correctPath}"` + ` results in translation file "${examplePath}".`);
}
// catalog name is the last directory of catalogPath.
// If the last part is {locale}, then catalog doesn't have an explicit name
const name = function () {
const _name = _path.default.basename(normalizeRelativePath(catalogConfig.catalogsMergePath));
return _name !== LOCALE ? _name : null;
}();
const catalog = new Catalog({
name,
path: normalizeRelativePath(catalogConfig.catalogsMergePath),
include: [],
exclude: []
}, config);
return catalog;
}
/**
* Merge origins and extractedComments for messages found in different places. All other attributes
* should be the same (raise an error if defaults are different).
*/
function mergeOriginsAndExtractedComments(msgId, prev, next) {
if (prev.defaults !== next.defaults) {
throw new Error(`Encountered different defaults for message ${_chalk.default.yellow(msgId)}` + `\n${_chalk.default.yellow((0, _utils.prettyOrigin)(prev.origin))} ${prev.defaults}` + `\n${_chalk.default.yellow((0, _utils.prettyOrigin)(next.origin))} ${next.defaults}`);
}
return {
...next,
extractedComments: R.concat(prev.extractedComments, next.extractedComments),
origin: R.concat(prev.origin, next.origin)
};
}
/**
* Ensure that value is always array. If not, turn it into an array of one element.
*/
const ensureArray = value => {
if (value == null) return [];
return Array.isArray(value) ? value : [value];
};
/**
* Remove ./ at the beginning: ./relative => relative
* relative => relative
* Preserve directories: ./relative/ => relative/
* Preserve absolute paths: /absolute/path => /absolute/path
*/
function normalizeRelativePath(sourcePath) {
if (_path.default.isAbsolute(sourcePath)) {
// absolute path
return (0, _normalizePath.default)(sourcePath, false);
}
const isDir = _fsExtra.default.existsSync(sourcePath) && _fsExtra.default.lstatSync(sourcePath).isDirectory();
return (0, _normalizePath.default)(_path.default.relative(process.cwd(), sourcePath), false) + (isDir ? "/" : "");
}
const cleanObsolete = R.filter(message => !message.obsolete);

@@ -488,7 +226,7 @@ exports.cleanObsolete = cleanObsolete;

function orderByMessageId(messages) {
const orderedMessages = {};
Object.keys(messages).sort().forEach(function (key) {
orderedMessages[key] = messages[key];
});
return orderedMessages;
return Object.keys(messages).sort().reduce((acc, key) => {
;
acc[key] = messages[key];
return acc;
}, {});
}

@@ -504,3 +242,3 @@ function orderByOrigin(messages) {

}
return Object.keys(messages).sort(function (a, b) {
return Object.keys(messages).sort((a, b) => {
const [aFile, aLineNumber] = getFirstOrigin(a);

@@ -514,2 +252,3 @@ const [bFile, bLineNumber] = getFirstOrigin(b);

}).reduce((acc, key) => {
;
acc[key] = messages[key];

@@ -516,0 +255,0 @@ return acc;

@@ -24,14 +24,2 @@ "use strict";

const compiledMessages = Object.keys(messages).reduce((obj, key) => {
const value = messages[key];
// If the current ID's value is a context object, create a nested
// expression, and assign the current ID to that expression
if (typeof value === "object") {
obj[key] = Object.keys(value).reduce((obj, contextKey) => {
obj[contextKey] = compile(value[contextKey], shouldPseudolocalize);
return obj;
}, {});
return obj;
}
// Don't use `key` as a fallback translation in strict mode.

@@ -38,0 +26,0 @@ const translation = messages[key] || (!strict ? key : "");

@@ -9,5 +9,8 @@ "use strict";

var _babelPluginExtractMessages = _interopRequireDefault(require("@lingui/babel-plugin-extract-messages"));
var _detect = require("../detect");
var _sourceMap = require("source-map");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const babelRe = new RegExp("\\.(" + [..._core.DEFAULT_EXTENSIONS, ".ts", ".tsx"].map(ext => ext.slice(1)).join("|") + ")$", "i");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const babelRe = new RegExp("\\.(" + [..._core.DEFAULT_EXTENSIONS, ".ts", ".mts", ".cts", ".tsx"].map(ext => ext.slice(1)).join("|") + ")$", "i");
const inlineSourceMapsRE = new RegExp(/\/[\/\*][#@]\s+sourceMappingURL=data:application\/json;(?:charset:utf-8;)?base64,/i);
const extractor = {

@@ -17,26 +20,66 @@ match(filename) {

},
extract(filename, localeDir, options = {}) {
const {
babelOptions: _babelOptions = {},
configPath
} = options;
const {
plugins = [],
...babelOptions
} = _babelOptions;
const frameworkOptions = {};
if (options.projectType === _detect.projectType.CRA) {
frameworkOptions.presets = ["react-app"];
async extract(filename, code, onMessageExtracted, linguiConfig, ctx) {
const parserOptions = linguiConfig.extractorParserOptions;
const parserPlugins = [
// https://babeljs.io/docs/en/babel-parser#latest-ecmascript-features
["decorators", {
decoratorsBeforeExport: (parserOptions === null || parserOptions === void 0 ? void 0 : parserOptions.decoratorsBeforeExport) || true
}]];
if ([/\.ts$/, /\.mts$/, /\.cts$/, /\.tsx$/].some(r => filename.match(r))) {
parserPlugins.push("typescript");
} else if (parserOptions !== null && parserOptions !== void 0 && parserOptions.flow) {
parserPlugins.push("flow");
}
(0, _core.transformFileSync)(filename, {
...babelOptions,
...frameworkOptions,
// we override envName to avoid issues with NODE_ENV=production
// https://github.com/lingui/js-lingui/issues/952
envName: "development",
plugins: ["macros", [_babelPluginExtractMessages.default, {
localeDir,
configPath
}], ...plugins]
if ([/\.jsx$/, /\.tsx$/].some(r => filename.match(r))) {
parserPlugins.push("jsx");
}
let sourceMapsConsumer;
if (ctx !== null && ctx !== void 0 && ctx.sourceMaps) {
sourceMapsConsumer = await new _sourceMap.SourceMapConsumer(ctx === null || ctx === void 0 ? void 0 : ctx.sourceMaps);
} else if (code.search(inlineSourceMapsRE) != -1) {
const {
fromSource
} = await Promise.resolve().then(() => _interopRequireWildcard(require("convert-source-map")));
sourceMapsConsumer = await new _sourceMap.SourceMapConsumer(fromSource(code).toObject());
}
await (0, _core.transformAsync)(code, {
// don't generate code
code: false,
babelrc: false,
configFile: false,
filename: filename,
inputSourceMap: ctx === null || ctx === void 0 ? void 0 : ctx.sourceMaps,
parserOpts: {
plugins: parserPlugins
},
plugins: [["macros", {
// macro plugin uses package `resolve` to find a path of macro file
// this will not follow jest pathMapping and will resolve path from ./build
// instead of ./src which makes testing & developing hard.
// here we override resolve and provide correct path for testing
resolvePath: source => require.resolve(source),
lingui: {
extract: true,
linguiConfig
}
}], [_babelPluginExtractMessages.default, {
onMessageExtracted: msg => {
if (!sourceMapsConsumer) {
return onMessageExtracted(msg);
}
const [_, line, column] = msg.origin;
const mappedPosition = sourceMapsConsumer.originalPositionFor({
line,
column
});
return onMessageExtracted({
...msg,
origin: [mappedPosition.source, mappedPosition.line, mappedPosition.column]
});
}
}]]
});
if (sourceMapsConsumer) {
sourceMapsConsumer.destroy();
}
}

@@ -43,0 +86,0 @@ };

@@ -7,7 +7,7 @@ "use strict";

exports.default = extract;
var _ora = _interopRequireDefault(require("ora"));
var _promises = _interopRequireDefault(require("fs/promises"));
var _babel = _interopRequireDefault(require("./babel"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const DEFAULT_EXTRACTORS = [_babel.default];
async function extract(filename, targetPath, options) {
async function extract(filename, onMessageExtracted, linguiConfig, options) {
const extractorsToExtract = options.extractors ?? DEFAULT_EXTRACTORS;

@@ -24,14 +24,9 @@ for (let e of extractorsToExtract) {

if (!ext.match(filename)) continue;
let spinner;
if (options.verbose) spinner = (0, _ora.default)().start(filename);
try {
await ext.extract(filename, targetPath, options);
if (options.verbose && spinner) spinner.succeed();
const file = await _promises.default.readFile(filename);
await ext.extract(filename, file.toString(), onMessageExtracted, linguiConfig);
return true;
} catch (e) {
if (options.verbose && spinner) {
spinner.fail(e.message);
} else {
console.error(`Cannot process file ${e.message}`);
}
console.error(`Cannot process file ${filename} ${e.message}`);
console.error(e.stack);
return false;

@@ -38,0 +33,0 @@ }

@@ -7,53 +7,9 @@ "use strict";

exports.default = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _core = require("@babel/core");
var _babelPluginExtractMessages = _interopRequireDefault(require("@lingui/babel-plugin-extract-messages"));
var _detect = require("../detect");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const typescriptRe = /(^.?|\.[^d]|[^.]d|[^.][^d])\.tsx?$/i;
const extractor = {
match(filename) {
return typescriptRe.test(filename);
throw new Error("Typescript extractor was removed. " + "Lingui CLI can parse typescript out of the box. " + "Please remove it from your lingui.config.js");
},
extract(filename, localeDir, options = {}) {
const ts = require("typescript");
const content = _fs.default.readFileSync(filename, "utf8");
const isTsx = filename.endsWith(".tsx");
// pass jsx to babel untouched
const jsx = isTsx ? ts.JsxEmit.Preserve : ts.JsxEmit.None;
const stripped = ts.transpileModule(content, {
compilerOptions: {
filename,
jsx,
module: ts.ModuleKind.ESNext,
target: ts.ScriptTarget.ES2016,
// use ES2015 or ES2016 to preserve tagged template literal
allowSyntheticDefaultImports: true,
moduleResolution: ts.ModuleResolutionKind.NodeJs
}
});
const frameworkOptions = {};
if (options.projectType === _detect.projectType.CRA) {
frameworkOptions.presets = ["react-app"];
}
const {
babelOptions = {},
configPath
} = options;
const plugins = ["macros", [_babelPluginExtractMessages.default, {
localeDir,
configPath
}], ...(babelOptions.plugins || [])];
if (isTsx) {
plugins.unshift(require.resolve("@babel/plugin-syntax-jsx"));
}
(0, _core.transform)(stripped.outputText, {
...babelOptions,
...frameworkOptions,
filename,
plugins
});
}
extract() {}
};
var _default = extractor;
exports.default = _default;

@@ -7,3 +7,2 @@ "use strict";

exports.default = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _papaparse = _interopRequireDefault(require("papaparse"));

@@ -39,3 +38,6 @@ var _utils = require("../utils");

read(filename) {
const raw = _fs.default.readFileSync(filename).toString();
const raw = (0, _utils.readFile)(filename);
if (!raw) {
return null;
}
try {

@@ -42,0 +44,0 @@ return deserialize(raw);

@@ -6,3 +6,3 @@ "use strict";

});
exports.default = getFormat;
exports.getFormat = getFormat;
var _csv = _interopRequireDefault(require("./csv"));

@@ -9,0 +9,0 @@ var _lingui = _interopRequireDefault(require("./lingui"));

@@ -7,3 +7,2 @@ "use strict";

exports.default = void 0;
var _fs = _interopRequireDefault(require("fs"));
var R = _interopRequireWildcard(require("ramda"));

@@ -13,3 +12,2 @@ var _utils = require("../utils");

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const removeOrigins = R.map(({

@@ -41,3 +39,6 @@ origin,

read(filename) {
const raw = _fs.default.readFileSync(filename).toString();
const raw = (0, _utils.readFile)(filename);
if (!raw) {
return null;
}
try {

@@ -44,0 +45,0 @@ return JSON.parse(raw);

@@ -7,7 +7,6 @@ "use strict";

exports.default = void 0;
var _fs = _interopRequireDefault(require("fs"));
var R = _interopRequireWildcard(require("ramda"));
var _utils = require("../utils");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const serialize = R.map(message => message.translation || "");

@@ -23,18 +22,13 @@ const deserialize = R.map(translation => ({

write(filename, catalog) {
var _file;
const messages = serialize(catalog);
let file = null;
try {
file = _fs.default.readFileSync(filename, "utf8");
} catch (error) {
if (error.code !== "ENOENT") {
throw error;
}
}
const shouldUseTrailingNewline = file === null || ((_file = file) === null || _file === void 0 ? void 0 : _file.endsWith("\n"));
let file = (0, _utils.readFile)(filename);
const shouldUseTrailingNewline = file === null || (file === null || file === void 0 ? void 0 : file.endsWith("\n"));
const trailingNewLine = shouldUseTrailingNewline ? "\n" : "";
_fs.default.writeFileSync(filename, `${JSON.stringify(messages, null, 2)}${trailingNewLine}`);
(0, _utils.writeFile)(filename, `${JSON.stringify(messages, null, 2)}${trailingNewLine}`);
},
read(filename) {
const raw = _fs.default.readFileSync(filename).toString();
const raw = (0, _utils.readFile)(filename);
if (!raw) {
return null;
}
try {

@@ -41,0 +35,0 @@ const rawCatalog = JSON.parse(raw);

@@ -6,14 +6,13 @@ "use strict";

});
exports.default = void 0;
exports.serialize = exports.default = void 0;
var _dateFns = require("date-fns");
var _fs = _interopRequireDefault(require("fs"));
var _parser = require("@messageformat/parser");
var _pluralsCldr = _interopRequireDefault(require("plurals-cldr"));
var _pofile = _interopRequireDefault(require("pofile"));
var R = _interopRequireWildcard(require("ramda"));
var _plurals = _interopRequireDefault(require("node-gettext/lib/plurals"));
var _utils = require("../utils");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
var _po = require("./po");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// @ts-ignore
function getCreateHeaders(language = "no") {

@@ -51,28 +50,9 @@ return {

const CTX_PREFIX = "js-lingui:";
const serialize = (items, options) => R.compose(R.values, R.mapObjIndexed((message, key) => {
const item = new _pofile.default.Item();
item.msgid = key;
item.comments = message.comments || [];
// The extractedComments array may be modified in this method, so create a new array with the message's elements.
// Destructuring `undefined` is forbidden, so fallback to `[]` if the message has no extracted comments.
item.extractedComments = [...(message.extractedComments ?? [])];
if (message.context) {
item.msgctxt = message.context;
}
if (options.origins !== false) {
if (message.origin && options.lineNumbers === false) {
item.references = message.origin.map(([path]) => path);
} else {
item.references = message.origin ? message.origin.map(_utils.joinOrigin) : [];
}
}
// @ts-ignore: Figure out how to set this flag
item.obsolete = message.obsolete;
item.flags = message.flags ? R.fromPairs(message.flags.map(flag => [flag, true])) : {};
function serializePlurals(item, message, id, isGeneratedId, options) {
// Depending on whether custom ids are used by the developer, the (potential plural) "original", untranslated ICU
// message can be found in `message.message` or in the item's `key` itself.
const icuMessage = message.message || key;
const icuMessage = message.message;
if (!icuMessage) {
return;
}
const _simplifiedMessage = icuMessage.replace(LINE_ENDINGS, " ");

@@ -88,3 +68,3 @@

if (messageAst.cases.some(icuCase => icuCase.tokens.some(token => token.type === "plural"))) {
console.warn(`Nested plurals cannot be expressed with gettext plurals. ` + `Message with key "%s" will not be saved correctly.`, key);
console.warn(`Nested plurals cannot be expressed with gettext plurals. ` + `Message with key "%s" will not be saved correctly.`, id);
}

@@ -96,3 +76,3 @@

});
if (message.message == null) {
if (isGeneratedId) {
// For messages without developer-set ID, use first case as `msgid` and the last case as `msgid_plural`.

@@ -105,6 +85,6 @@ // This does not necessarily make sense for development languages with more than two numbers, but gettext

// Since the original msgid is overwritten, store ICU message to allow restoring that ID later.
ctx.set("icu", key);
ctx.set("icu", icuMessage);
} else {
// For messages with developer-set ID, append `_plural` to the key to generate `msgid_plural`.
item.msgid_plural = key + "_plural";
item.msgid_plural = id + "_plural";
}

@@ -118,20 +98,16 @@ ctx.sort();

if (((_message$translation = message.translation) === null || _message$translation === void 0 ? void 0 : _message$translation.length) > 0) {
try {
const ast = (0, _parser.parse)(message.translation)[0];
if (ast.cases == null) {
console.warn(`Found translation without plural cases for key "${key}". ` + `This likely means that a translated .po file misses multiple msgstr[] entries for the key. ` + `Translation found: "${message.translation}"`);
item.msgstr = [message.translation];
} else {
item.msgstr = ast.cases.map(stringifyICUCase);
}
} catch (e) {
console.error(`Error parsing translation ICU for key "${key}"`, e);
const ast = (0, _parser.parse)(message.translation)[0];
if (ast.cases == null) {
console.warn(`Found translation without plural cases for key "${id}". ` + `This likely means that a translated .po file misses multiple msgstr[] entries for the key. ` + `Translation found: "${message.translation}"`);
item.msgstr = [message.translation];
} else {
item.msgstr = ast.cases.map(stringifyICUCase);
}
}
} catch (e) {
console.error(`Error parsing message ICU for key "${key}":`, e);
console.error(`Error parsing message ICU for key "${id}":`, e);
}
} else {
if (!options.disableSelectWarning && ICU_SELECT_REGEX.test(_simplifiedMessage)) {
console.warn(`ICU 'select' and 'selectOrdinal' formats cannot be expressed natively in gettext format. ` + `Item with key "%s" will be included in the catalog as raw ICU message. ` + `To disable this warning, include '{ disableSelectWarning: true }' in the config's 'formatOptions'`, key);
console.warn(`ICU 'select' and 'selectOrdinal' formats cannot be expressed natively in gettext format. ` + `Item with key "%s" will be included in the catalog as raw ICU message. ` + `To disable this warning, include '{ disableSelectWarning: true }' in the config's 'formatOptions'`, id);
}

@@ -141,23 +117,6 @@ item.msgstr = [message.translation];

return item;
}))(items);
const getMessageKey = R.prop("msgid");
const getTranslations = R.prop("msgstr");
const getExtractedComments = R.prop("extractedComments");
const getTranslatorComments = R.prop("comments");
const getMessageContext = R.prop("msgctxt");
const getOrigins = R.prop("references");
const getFlags = R.compose(R.map(R.trim), R.keys, R.dissoc("obsolete"),
// backward-compatibility, remove in 3.x
R.prop("flags"));
const isObsolete = R.either(R.path(["flags", "obsolete"]), R.prop("obsolete"));
const getTranslationCount = R.compose(R.length, getTranslations);
const deserialize = R.map(R.applySpec({
translation: R.compose(R.head, R.defaultTo([]), getTranslations),
extractedComments: R.compose(R.defaultTo([]), getExtractedComments),
comments: R.compose(R.defaultTo([]), getTranslatorComments),
context: R.compose(R.defaultTo(null), getMessageContext),
obsolete: isObsolete,
origin: R.compose(R.map(_utils.splitOrigin), R.defaultTo([]), getOrigins),
flags: getFlags
}));
}
const serialize = (catalog, options) => {
return (0, _po.serialize)(catalog, options, (item, message, id, isGeneratedId) => serializePlurals(item, message, id, isGeneratedId, options));
};

@@ -174,2 +133,3 @@ /**

*/
exports.serialize = serialize;
const getPluralCases = lang => {

@@ -181,66 +141,60 @@ // If users uses locale with underscore or slash, es-ES, es_ES, gettextplural is "es" not es-ES.

};
const convertPluralsToICU = (items, lang) => {
// .po plurals are numbered 0-N and need to be mapped to ICU plural classes ("one", "few", "many"...). Different
// languages can have different plural classes (some start with "zero", some with "one"), so read that data from CLDR.
// `pluralForms` may be `null` if lang is not found. As long as no plural is used, don't report an error.
let pluralForms = getPluralCases(lang);
items.forEach(item => {
var _item$extractedCommen;
const translationCount = getTranslationCount(item);
const messageKey = getMessageKey(item);
const convertPluralsToICU = (item, pluralForms, lang) => {
var _item$extractedCommen;
const translationCount = item.msgstr.length;
const messageKey = item.msgid;
// Messages without multiple translations (= plural cases) need no further processing.
if (translationCount <= 1 && !item.msgid_plural) {
return;
}
// Messages without multiple translations (= plural cases) need no further processing.
if (translationCount <= 1 && !item.msgid_plural) {
return;
}
// msgid_plural must be set, but its actual value is not important.
if (!item.msgid_plural) {
console.warn(`Multiple translations for item with key "%s" but missing 'msgid_plural' in catalog "${lang}". This is not supported and the plural cases will be ignored.`, messageKey);
return;
}
const contextComment = (_item$extractedCommen = item.extractedComments.find(comment => comment.startsWith(CTX_PREFIX))) === null || _item$extractedCommen === void 0 ? void 0 : _item$extractedCommen.substr(CTX_PREFIX.length);
const ctx = new URLSearchParams(contextComment);
if (contextComment != null) {
item.extractedComments = item.extractedComments.filter(comment => !comment.startsWith(CTX_PREFIX));
}
// msgid_plural must be set, but its actual value is not important.
if (!item.msgid_plural) {
console.warn(`Multiple translations for item with key "%s" but missing 'msgid_plural' in catalog "${lang}". This is not supported and the plural cases will be ignored.`, messageKey);
return;
}
const contextComment = (_item$extractedCommen = item.extractedComments.find(comment => comment.startsWith(CTX_PREFIX))) === null || _item$extractedCommen === void 0 ? void 0 : _item$extractedCommen.substr(CTX_PREFIX.length);
const ctx = new URLSearchParams(contextComment);
if (contextComment != null) {
item.extractedComments = item.extractedComments.filter(comment => !comment.startsWith(CTX_PREFIX));
}
// If an original ICU was stored, use that as `msgid` to match the catalog that was originally exported.
const storedICU = ctx.get("icu");
if (storedICU != null) {
item.msgid = storedICU;
}
// If an original ICU was stored, use that as `msgid` to match the catalog that was originally exported.
const storedICU = ctx.get("icu");
if (storedICU != null) {
item.msgid = storedICU;
}
// If all translations are empty, ignore item.
if (item.msgstr.every(str => str.length === 0)) {
return;
}
if (pluralForms == null) {
console.warn(`Multiple translations for item with key "%s" in language "${lang}", but no plural cases were found. ` + `This prohibits the translation of .po plurals into ICU plurals. Pluralization will not work for this key.`, messageKey);
return;
}
const pluralCount = pluralForms.length;
if (translationCount > pluralCount) {
console.warn(`More translations provided (${translationCount}) for item with key "%s" in language "${lang}" than there are plural cases available (${pluralCount}). ` + `This will result in not all translations getting picked up.`, messageKey);
}
// If all translations are empty, ignore item.
if (item.msgstr.every(str => str.length === 0)) {
return;
}
if (pluralForms == null) {
console.warn(`Multiple translations for item with key "%s" in language "${lang}", but no plural cases were found. ` + `This prohibits the translation of .po plurals into ICU plurals. Pluralization will not work for this key.`, messageKey);
return;
}
const pluralCount = pluralForms.length;
if (translationCount > pluralCount) {
console.warn(`More translations provided (${translationCount}) for item with key "%s" in language "${lang}" than there are plural cases available (${pluralCount}). ` + `This will result in not all translations getting picked up.`, messageKey);
}
// Map each msgstr to a "<pluralform> {<translated_string>}" entry, joined by one space.
const pluralClauses = item.msgstr.map((str, index) => pluralForms[index] + " {" + str + "}").join(" ");
// Map each msgstr to a "<pluralform> {<translated_string>}" entry, joined by one space.
const pluralClauses = item.msgstr.map((str, index) => pluralForms[index] + " {" + str + "}").join(" ");
// Find out placeholder name from item's message context, defaulting to "count".
let pluralizeOn = ctx.get("pluralize_on");
if (!pluralizeOn) {
console.warn(`Unable to determine plural placeholder name for item with key "%s" in language "${lang}" (should be stored in a comment starting with "#. ${CTX_PREFIX}"), assuming "count".`, messageKey);
pluralizeOn = "count";
}
item.msgstr = ["{" + pluralizeOn + ", plural, " + pluralClauses + "}"];
});
// Find out placeholder name from item's message context, defaulting to "count".
let pluralizeOn = ctx.get("pluralize_on");
if (!pluralizeOn) {
console.warn(`Unable to determine plural placeholder name for item with key "%s" in language "${lang}" (should be stored in a comment starting with "#. ${CTX_PREFIX}"), assuming "count".`, messageKey);
pluralizeOn = "count";
}
item.msgstr = ["{" + pluralizeOn + ", plural, " + pluralClauses + "}"];
};
const indexItems = R.indexBy(getMessageKey);
const poGettext = {
catalogExtension: ".po",
templateExtension: ".pot",
write(filename, catalog, options) {
let po;
if (_fs.default.existsSync(filename)) {
const raw = _fs.default.readFileSync(filename).toString();
const raw = (0, _utils.readFile)(filename);
if (raw) {
po = _pofile.default.parse(raw);

@@ -253,11 +207,14 @@ } else {

}
// accessing private property
;
po.headerOrder = Object.keys(po.headers);
}
po.items = this.serialize(catalog, options);
po.items = serialize(catalog, options);
(0, _utils.writeFileIfChanged)(filename, po.toString());
},
// Mainly exported for easier testing
serialize,
read(filename) {
const raw = _fs.default.readFileSync(filename).toString();
const raw = (0, _utils.readFile)(filename);
if (!raw) {
return null;
}
return this.parse(raw);

@@ -267,4 +224,10 @@ },

const po = _pofile.default.parse(raw);
convertPluralsToICU(po.items, po.headers.Language);
return deserialize(indexItems(po.items));
// .po plurals are numbered 0-N and need to be mapped to ICU plural classes ("one", "few", "many"...). Different
// languages can have different plural classes (some start with "zero", some with "one"), so read that data from CLDR.
// `pluralForms` may be `null` if lang is not found. As long as no plural is used, don't report an error.
let pluralForms = getPluralCases(po.headers.Language);
return (0, _po.deserialize)(po.items, item => {
convertPluralsToICU(item, pluralForms, po.headers.Language);
});
}

@@ -271,0 +234,0 @@ };

@@ -7,70 +7,97 @@ "use strict";

exports.default = void 0;
var _fs = _interopRequireDefault(require("fs"));
var R = _interopRequireWildcard(require("ramda"));
exports.deserialize = deserialize;
exports.serialize = void 0;
var _dateFns = require("date-fns");
var _pofile = _interopRequireDefault(require("pofile"));
var _utils = require("../utils");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
var _generateMessageId = require("../generateMessageId");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const getCreateHeaders = (language = "no") => ({
"POT-Creation-Date": (0, _dateFns.format)(new Date(), "yyyy-MM-dd HH:mmxxxx"),
"MIME-Version": "1.0",
"Content-Type": "text/plain; charset=utf-8",
"Content-Transfer-Encoding": "8bit",
"X-Generator": "@lingui/cli",
Language: language
});
const serialize = (items, options) => R.compose(R.values, R.mapObjIndexed((message, key) => {
const item = new _pofile.default.Item();
item.msgid = key;
item.msgstr = [message.translation];
item.comments = message.comments || [];
item.extractedComments = message.extractedComments || [];
if (message.context) {
item.msgctxt = message.context;
}
if (options.origins !== false) {
if (message.origin && options.lineNumbers === false) {
item.references = message.origin.map(([path]) => path);
function isGeneratedId(id, message) {
return id === (0, _generateMessageId.generateMessageId)(message.message, message.context);
}
function getCreateHeaders(language = "no") {
return {
"POT-Creation-Date": (0, _dateFns.format)(new Date(), "yyyy-MM-dd HH:mmxxxx"),
"MIME-Version": "1.0",
"Content-Type": "text/plain; charset=utf-8",
"Content-Transfer-Encoding": "8bit",
"X-Generator": "@lingui/cli",
Language: language
};
}
const EXPLICIT_ID_FLAG = "explicit-id";
const serialize = (catalog, options, postProcessItem) => {
return Object.keys(catalog).map(id => {
const message = catalog[id];
const item = new _pofile.default.Item();
// The extractedComments array may be modified in this method,
// so create a new array with the message's elements.
item.extractedComments = [...(message.extractedComments || [])];
item.flags = (message.flags || []).reduce((acc, flag) => {
acc[flag] = true;
return acc;
}, {});
const _isGeneratedId = isGeneratedId(id, message);
if (_isGeneratedId) {
item.msgid = message.message;
if (!item.extractedComments.find(c => c.includes("js-lingui-id"))) {
item.extractedComments.push(`js-lingui-id: ${id}`);
}
} else {
item.references = message.origin ? message.origin.map(_utils.joinOrigin) : [];
item.flags[EXPLICIT_ID_FLAG] = true;
item.msgid = id;
}
if (message.context) {
item.msgctxt = message.context;
}
item.msgstr = [message.translation];
item.comments = message.comments || [];
if (options.origins !== false) {
if (message.origin && options.lineNumbers === false) {
item.references = message.origin.map(([path]) => path);
} else {
item.references = message.origin ? message.origin.map(_utils.joinOrigin) : [];
}
}
item.obsolete = message.obsolete;
return postProcessItem ? postProcessItem(item, message, id, _isGeneratedId) : item;
});
};
exports.serialize = serialize;
function deserialize(items, onItem) {
return items.reduce((catalog, item) => {
onItem(item);
const message = {
translation: item.msgstr[0],
extractedComments: item.extractedComments || [],
comments: item.comments || [],
context: item.msgctxt ?? null,
obsolete: item.flags.obsolete || item.obsolete,
origin: (item.references || []).map(ref => (0, _utils.splitOrigin)(ref)),
flags: Object.keys(item.flags).map(flag => flag.trim())
};
let id = item.msgid;
// if generated id, recreate it
if (!item.flags[EXPLICIT_ID_FLAG]) {
id = (0, _generateMessageId.generateMessageId)(item.msgid, item.msgctxt);
message.message = item.msgid;
}
catalog[id] = message;
return catalog;
}, {});
}
function validateItem(item) {
if (item.msgstr.length > 1) {
console.warn(`Multiple translations for item with key ${item.msgid} is not supported and it will be ignored.`);
}
// @ts-ignore: Figure out how to set this flag
item.obsolete = message.obsolete;
item.flags = message.flags ? R.fromPairs(message.flags.map(flag => [flag, true])) : {};
return item;
}))(items);
const getMessageKey = R.prop("msgid");
const getTranslations = R.prop("msgstr");
const getExtractedComments = R.prop("extractedComments");
const getTranslatorComments = R.prop("comments");
const getMessageContext = R.prop("msgctxt");
const getOrigins = R.prop("references");
const getFlags = R.compose(R.map(R.trim), R.keys, R.dissoc("obsolete"),
// backward-compatibility, remove in 3.x
R.prop("flags"));
const isObsolete = R.either(R.path(["flags", "obsolete"]), R.prop("obsolete"));
const deserialize = R.map(R.applySpec({
translation: R.compose(R.head, R.defaultTo([]), getTranslations),
extractedComments: R.compose(R.defaultTo([]), getExtractedComments),
comments: R.compose(R.defaultTo([]), getTranslatorComments),
context: R.compose(R.defaultTo(null), getMessageContext),
obsolete: isObsolete,
origin: R.compose(R.map(_utils.splitOrigin), R.defaultTo([]), getOrigins),
flags: getFlags
}));
const validateItems = R.forEach(item => {
if (R.length(getTranslations(item)) > 1) {
console.warn("Multiple translations for item with key %s is not supported and it will be ignored.", getMessageKey(item));
}
});
const indexItems = R.indexBy(getMessageKey);
}
const po = {
catalogExtension: ".po",
templateExtension: ".pot",
write(filename, catalog, options) {
let po;
if (_fs.default.existsSync(filename)) {
const raw = _fs.default.readFileSync(filename).toString();
const raw = (0, _utils.readFile)(filename);
if (raw) {
po = _pofile.default.parse(raw);

@@ -83,3 +110,5 @@ } else {

}
po.headerOrder = R.keys(po.headers);
// accessing private property
;
po.headerOrder = Object.keys(po.headers);
}

@@ -90,3 +119,6 @@ po.items = serialize(catalog, options);

read(filename) {
const raw = _fs.default.readFileSync(filename).toString();
const raw = (0, _utils.readFile)(filename);
if (!raw) {
return null;
}
return this.parse(raw);

@@ -96,4 +128,3 @@ },

const po = _pofile.default.parse(raw);
validateItems(po.items);
return deserialize(indexItems(po.items));
return deserialize(po.items, validateItem);
}

@@ -100,0 +131,0 @@ };

@@ -39,5 +39,5 @@ "use strict";

}
const isYarn = process.env.npm_config_user_agent && process.env.npm_config_user_agent.includes("yarn");
const runCommand = isYarn ? "yarn" : "npm run";
return `${runCommand} ${command}`;
}
const isYarn = process.env.npm_config_user_agent && process.env.npm_config_user_agent.includes("yarn");
const runCommand = isYarn ? "yarn" : "npm run";
}

@@ -6,2 +6,9 @@ "use strict";

});
var _exportNames = {
getFormat: true,
getCatalogForFile: true,
getCatalogs: true,
createCompiledCatalog: true,
generateMessageId: true
};
Object.defineProperty(exports, "createCompiledCatalog", {

@@ -13,6 +20,12 @@ enumerable: true,

});
Object.defineProperty(exports, "generateMessageId", {
enumerable: true,
get: function () {
return _generateMessageId.generateMessageId;
}
});
Object.defineProperty(exports, "getCatalogForFile", {
enumerable: true,
get: function () {
return _catalog.getCatalogForFile;
return _getCatalogs.getCatalogForFile;
}

@@ -23,3 +36,3 @@ });

get: function () {
return _catalog.getCatalogs;
return _getCatalogs.getCatalogs;
}

@@ -30,8 +43,20 @@ });

get: function () {
return _formats.default;
return _formats.getFormat;
}
});
var _formats = _interopRequireDefault(require("./formats"));
var _catalog = require("./catalog");
var _formats = require("./formats");
var _getCatalogs = require("./catalog/getCatalogs");
var _compile = require("./compile");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _generateMessageId = require("./generateMessageId");
var _types = require("./types");
Object.keys(_types).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
if (key in exports && exports[key] === _types[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _types[key];
}
});
});

@@ -6,34 +6,21 @@ "use strict";

});
exports.PATHSEP = void 0;
exports.hasYarn = hasYarn;
exports.helpMisspelledCommand = helpMisspelledCommand;
exports.isDirectory = isDirectory;
exports.joinOrigin = void 0;
exports.makeInstall = makeInstall;
exports.normalizeRelativePath = normalizeRelativePath;
exports.normalizeSlashes = normalizeSlashes;
exports.prettyOrigin = prettyOrigin;
exports.removeDirectory = removeDirectory;
exports.readFile = readFile;
exports.replacePlaceholders = replacePlaceholders;
exports.splitOrigin = void 0;
exports.writeFile = writeFile;
exports.writeFileIfChanged = writeFileIfChanged;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _chalk = _interopRequireDefault(require("chalk"));
var _fuzzaldrin = require("fuzzaldrin");
var _normalizePath = _interopRequireDefault(require("normalize-path"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function removeDirectory(dir, onlyContent = false) {
if (!_fs.default.existsSync(dir)) return;
const list = _fs.default.readdirSync(dir);
for (let i = 0; i < list.length; i++) {
const filename = _path.default.join(dir, list[i]);
const stat = _fs.default.statSync(filename);
if (filename === "." || filename === "..") {
// pass these files
} else if (stat.isDirectory()) {
// rmdir recursively
removeDirectory(filename);
} else {
_fs.default.unlinkSync(filename);
}
}
if (!onlyContent) {
_fs.default.rmdirSync(dir);
}
}
const PATHSEP = "/"; // force posix everywhere
exports.PATHSEP = PATHSEP;
function prettyOrigin(origins) {

@@ -46,40 +33,55 @@ try {

}
/**
* .. js:function:: helpMisspelledCommand(command [, availableCommands = []])
* :param: command - command passed to CLI
* :param: availableCommands - all commands defined in commander.js
*
* If unknown commands is passed to CLI, check it agains all available commands
* for possible misspelled letter. Output help with suggestions to console.
*/
function helpMisspelledCommand(command, availableCommands = []) {
const commandNames = availableCommands.map(command => command.name());
// if no command is supplied, then commander.js shows help automatically
if (!command || commandNames.includes(command)) {
return;
}
const suggestions = commandNames.map(name => ({
name,
score: (0, _fuzzaldrin.score)(name, command.slice(0, name.length))
})).filter(nameScore => nameScore.score > 0).slice(0, 3).map(commandScore => _chalk.default.inverse(commandScore.name)).join(", ");
console.log(`lingui: command ${command} is not a lingui command. ` + `See 'lingui --help' for the list of available commands.`);
if (suggestions) {
console.log();
console.log(`Did you mean: ${suggestions}?`);
}
function replacePlaceholders(input, values) {
return input.replace(/\{([^}]+)}/g, (m, placeholder) => {
return values[placeholder] || m;
});
}
const splitOrigin = origin => origin.split(":");
const splitOrigin = origin => {
const [file, line] = origin.split(":");
return [file, line ? Number(line) : null];
};
exports.splitOrigin = splitOrigin;
const joinOrigin = origin => origin.join(":");
exports.joinOrigin = joinOrigin;
function readFile(fileName) {
try {
return _fs.default.readFileSync(fileName).toString();
} catch (err) {
if (err.code != "ENOENT") {
throw err;
}
}
}
function mkdirp(dir) {
try {
_fs.default.mkdirSync(dir, {
recursive: true
});
} catch (err) {
if (err.code != "EEXIST") {
throw err;
}
}
}
function isDirectory(filePath) {
try {
return _fs.default.lstatSync(filePath).isDirectory();
} catch (err) {
if (err.code != "ENOENT") {
throw err;
}
}
}
function writeFile(fileName, content) {
mkdirp(_path.default.dirname(fileName));
_fs.default.writeFileSync(fileName, content);
}
function writeFileIfChanged(filename, newContent) {
if (_fs.default.existsSync(filename)) {
const raw = _fs.default.readFileSync(filename).toString();
const raw = readFile(filename);
if (raw) {
if (newContent !== raw) {
_fs.default.writeFileSync(filename, newContent);
writeFile(filename, newContent);
}
} else {
_fs.default.writeFileSync(filename, newContent);
writeFile(filename, newContent);
}

@@ -93,2 +95,24 @@ }

return (packageName, dev = false) => withYarn ? `yarn add ${dev ? "--dev " : ""}${packageName}` : `npm install ${dev ? "--save-dev" : "--save"} ${packageName}`;
}
/**
* Normalize Windows backslashes in path so they look always as posix
*/
function normalizeSlashes(path) {
return path.replace("\\", "/");
}
/**
* Remove ./ at the beginning: ./relative => relative
* relative => relative
* Preserve directories: ./relative/ => relative/
* Preserve absolute paths: /absolute/path => /absolute/path
*/
function normalizeRelativePath(sourcePath) {
if (_path.default.isAbsolute(sourcePath)) {
// absolute path
return (0, _normalizePath.default)(sourcePath, false);
}
const isDir = isDirectory(sourcePath);
return (0, _normalizePath.default)(_path.default.relative(process.cwd(), sourcePath), false) + (isDir ? "/" : "");
}

@@ -10,24 +10,15 @@ "use strict";

var _fs = _interopRequireDefault(require("fs"));
var R = _interopRequireWildcard(require("ramda"));
var _commander = _interopRequireDefault(require("commander"));
var _commander = require("commander");
var plurals = _interopRequireWildcard(require("make-plural"));
var _conf = require("@lingui/conf");
var _catalog = require("./api/catalog");
var _compile = require("./api/compile");
var _help = require("./api/help");
var _api = require("./api");
var _getCatalogs = require("./api/catalog/getCatalogs");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const noMessages = R.pipe(R.map(R.isEmpty), R.values, R.all(R.equals(true)));
function command(config, options) {
const catalogs = (0, _catalog.getCatalogs)(config);
const catalogs = (0, _api.getCatalogs)(config);
// fixme: this is definitely doesn't work
if (noMessages(catalogs)) {
console.error("Nothing to compile, message catalogs are empty!\n");
console.error(`(use "${_chalk.default.yellow((0, _help.helpRun)("extract"))}" to extract messages from source files)`);
return false;
}
// Check config.compile.merge if catalogs for current locale are to be merged into a single compiled file

@@ -40,2 +31,3 @@ const doMerge = !!config.catalogsMergePath;

// todo: this validation should be in @lingui/conf
// todo: validate locales according bcp47, instead of plurals
if (locale !== config.pseudoLocale && !plurals[language]) {

@@ -46,19 +38,23 @@ console.error(_chalk.default.red(`Error: Invalid locale ${_chalk.default.bold(locale)} (missing plural rules)!`));

for (const catalog of catalogs) {
const missingMessages = [];
const messages = catalog.getTranslations(locale, {
fallbackLocales: config.fallbackLocales,
sourceLocale: config.sourceLocale
sourceLocale: config.sourceLocale,
onMissing: missing => {
missingMessages.push(missing);
}
});
if (!options.allowEmpty) {
const missingMsgIds = R.pipe(R.pickBy(R.isNil), R.keys)(messages);
if (missingMsgIds.length > 0) {
console.error(_chalk.default.red(`Error: Failed to compile catalog for locale ${_chalk.default.bold(locale)}!`));
if (options.verbose) {
console.error(_chalk.default.red("Missing translations:"));
missingMsgIds.forEach(msgId => console.error(msgId));
} else {
console.error(_chalk.default.red(`Missing ${missingMsgIds.length} translation(s)`));
}
console.error();
return false;
if (!options.allowEmpty && missingMessages.length > 0) {
console.error(_chalk.default.red(`Error: Failed to compile catalog for locale ${_chalk.default.bold(locale)}!`));
if (options.verbose) {
console.error(_chalk.default.red("Missing translations:"));
missingMessages.forEach(missing => {
const source = missing.source || missing.source === missing.id ? `: (${missing.source})` : "";
console.error(`${missing.id}${source}`);
});
} else {
console.error(_chalk.default.red(`Missing ${missingMessages.length} translation(s)`));
}
console.error();
return false;
}

@@ -90,3 +86,3 @@ if (doMerge) {

if (doMerge) {
const compileCatalog = (0, _catalog.getCatalogForMerge)(config);
const compileCatalog = (0, _getCatalogs.getCatalogForMerge)(config);
const namespace = options.namespace || config.compileNamespace;

@@ -106,3 +102,3 @@ const compiledCatalog = (0, _compile.createCompiledCatalog)(locale, mergedCatalogs, {

if (require.main === module) {
_commander.default.description("Add compile message catalogs and add language data (plurals) to compiled bundle.").option("--config <path>", "Path to the config file").option("--strict", "Disable defaults for missing translations").option("--verbose", "Verbose output").option("--format <format>", "Format of message catalog").option("--typescript", "Create Typescript definition for compiled bundle").option("--namespace <namespace>", "Specify namespace for compiled bundle. Ex: cjs(default) -> module.exports, es -> export, window.test -> window.test").option("--watch", "Enables Watch Mode").option("--debounce <delay>", "Debounces compilation for given amount of milliseconds").on("--help", function () {
_commander.program.description("Add compile message catalogs and add language data (plurals) to compiled bundle.").option("--config <path>", "Path to the config file").option("--strict", "Disable defaults for missing translations").option("--verbose", "Verbose output").option("--typescript", "Create Typescript definition for compiled bundle").option("--namespace <namespace>", "Specify namespace for compiled bundle. Ex: cjs(default) -> module.exports, es -> export, window.test -> window.test").option("--watch", "Enables Watch Mode").option("--debounce <delay>", "Debounces compilation for given amount of milliseconds").on("--help", function () {
console.log("\n Examples:\n");

@@ -117,15 +113,11 @@ console.log(" # Compile translations and use defaults or message IDs for missing translations");

}).parse(process.argv);
const options = _commander.program.opts();
const config = (0, _conf.getConfig)({
configPath: _commander.default.config
configPath: options.config
});
if (_commander.default.format) {
const msg = "--format option is deprecated and will be removed in @lingui/cli@3.0.0." + " Please set format in configuration https://lingui.dev/ref/conf#format";
console.warn(msg);
config.format = _commander.default.format;
}
const compile = () => command(config, {
verbose: _commander.default.watch || _commander.default.verbose || false,
allowEmpty: !_commander.default.strict,
typescript: _commander.default.typescript || config.compileNamespace === "ts" || false,
namespace: _commander.default.namespace // we want this to be undefined if user does not specify so default can be used
verbose: options.watch || options.verbose || false,
allowEmpty: !options.strict,
typescript: options.typescript || config.compileNamespace === "ts" || false,
namespace: options.namespace // we want this to be undefined if user does not specify so default can be used
});

@@ -136,13 +128,13 @@

// Skip debouncing if not enabled
if (!_commander.default.debounce) return compile();
if (!options.debounce) return compile();
// CLear the previous timer if there is any, and schedule the next
debounceTimer && clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => compile(), _commander.default.debounce);
debounceTimer = setTimeout(() => compile(), options.debounce);
};
// Check if Watch Mode is enabled
if (_commander.default.watch) {
if (options.watch) {
console.info(_chalk.default.bold("Initializing Watch Mode..."));
const catalogs = (0, _catalog.getCatalogs)(config);
const catalogs = (0, _api.getCatalogs)(config);
let paths = [];

@@ -149,0 +141,0 @@ const catalogExtension = (0, _api.getFormat)(config.format).catalogExtension;

@@ -8,31 +8,22 @@ "use strict";

var _chalk = _interopRequireDefault(require("chalk"));
var _commander = _interopRequireDefault(require("commander"));
var _commander = require("commander");
var _conf = require("@lingui/conf");
var _catalog = require("./api/catalog");
var _detect = require("./api/detect");
var _api = require("./api");
var _path = _interopRequireDefault(require("path"));
var _utils = require("./api/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
async function command(config, options) {
// `react-app` babel plugin used by CRA requires either BABEL_ENV or NODE_ENV to be
// set. We're setting it here, because lingui macros are going to use them as well.
if (!process.env.BABEL_ENV && !process.env.NODE_ENV) {
process.env.BABEL_ENV = "development";
}
// We need macros to keep imports, so extract-messages plugin know what componets
// to collect. Users usually use both BABEN_ENV and NODE_ENV, so it's probably
// safer to introduce a new env variable. LINGUI_EXTRACT=1 during `lingui extract`
process.env.LINGUI_EXTRACT = "1";
options.verbose && console.error("Extracting messages from source files…");
const catalogs = (0, _catalog.getCatalogs)(config);
options.verbose && console.log("Extracting messages from source files…");
const catalogs = (0, _api.getCatalogs)(config);
const catalogStats = {};
let commandSuccess = true;
await Promise.all(catalogs.map(async catalog => {
await catalog.makeTemplate({
const result = await catalog.makeTemplate({
...options,
orderBy: config.orderBy,
projectType: (0, _detect.detect)()
orderBy: config.orderBy
});
const catalogTemplate = catalog.readTemplate();
if (catalogTemplate !== null && catalogTemplate !== undefined) {
catalogStats[catalog.templateFile] = Object.keys(catalogTemplate).length;
if (result) {
catalogStats[(0, _utils.normalizeSlashes)(_path.default.relative(config.rootDir, catalog.templateFile))] = Object.keys(result).length;
}
commandSuccess && (commandSuccess = Boolean(result));
}));

@@ -43,12 +34,12 @@ Object.entries(catalogStats).forEach(([key, value]) => {

});
return true;
return commandSuccess;
}
if (require.main === module) {
_commander.default.option("--config <path>", "Path to the config file").option("--verbose", "Verbose output").parse(process.argv);
_commander.program.option("--config <path>", "Path to the config file").option("--verbose", "Verbose output").parse(process.argv);
const options = _commander.program.opts();
const config = (0, _conf.getConfig)({
configPath: _commander.default.config || process.env.LINGUI_CONFIG
configPath: options.config
});
const result = command(config, {
verbose: _commander.default.verbose || false,
configPath: _commander.default.config || process.env.LINGUI_CONFIG
verbose: options.verbose || false
}).then(() => {

@@ -55,0 +46,0 @@ if (!result) process.exit(1);

@@ -9,8 +9,10 @@ "use strict";

var _chokidar = _interopRequireDefault(require("chokidar"));
var _commander = _interopRequireDefault(require("commander"));
var _commander = require("commander");
var _path = _interopRequireDefault(require("path"));
var _conf = require("@lingui/conf");
var _catalog = require("./api/catalog");
var _api = require("./api");
var _stats = require("./api/stats");
var _detect = require("./api/detect");
var _help = require("./api/help");
var _ora = _interopRequireDefault(require("ora"));
var _utils = require("./api/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -20,26 +22,20 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

async function command(config, options) {
// `react-app` babel plugin used by CRA requires either BABEL_ENV or NODE_ENV to be
// set. We're setting it here, because lingui macros are going to use them as well.
if (!process.env.BABEL_ENV && !process.env.NODE_ENV) {
process.env.BABEL_ENV = "development";
}
// We need macros to keep imports, so extract-messages plugin know what componets
// to collect. Users usually use both BABEN_ENV and NODE_ENV, so it's probably
// safer to introduce a new env variable. LINGUI_EXTRACT=1 during `lingui extract`
process.env.LINGUI_EXTRACT = "1";
options.verbose && console.error("Extracting messages from source files…");
const catalogs = (0, _catalog.getCatalogs)(config);
options.verbose && console.log("Extracting messages from source files…");
const catalogs = (0, _api.getCatalogs)(config);
const catalogStats = {};
let commandSuccess = true;
const spinner = (0, _ora.default)().start();
for (let catalog of catalogs) {
const catalogSuccess = await catalog.make({
const result = await catalog.make({
...options,
orderBy: config.orderBy,
extractors: config.extractors,
projectType: (0, _detect.detect)()
orderBy: config.orderBy
});
catalogStats[catalog.path] = catalog.readAll();
commandSuccess && (commandSuccess = catalogSuccess);
catalogStats[(0, _utils.normalizeSlashes)(_path.default.relative(config.rootDir, catalog.path))] = result || {};
commandSuccess && (commandSuccess = Boolean(result));
}
if (commandSuccess) {
spinner.succeed();
} else {
spinner.fail();
}
Object.entries(catalogStats).forEach(([key, value]) => {

@@ -51,4 +47,4 @@ console.log(`Catalog statistics for ${key}: `);

if (!options.watch) {
console.error(`(use "${_chalk.default.yellow((0, _help.helpRun)("extract"))}" to update catalogs with new messages)`);
console.error(`(use "${_chalk.default.yellow((0, _help.helpRun)("compile"))}" to compile catalogs for production)`);
console.log(`(use "${_chalk.default.yellow((0, _help.helpRun)("extract"))}" to update catalogs with new messages)`);
console.log(`(use "${_chalk.default.yellow((0, _help.helpRun)("compile"))}" to compile catalogs for production)`);
}

@@ -64,22 +60,9 @@

if (require.main === module) {
_commander.default.option("--config <path>", "Path to the config file").option("--locale <locale>", "Only extract the specified locale").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")
// Obsolete options
.option("--babelOptions", "Babel options passed to transform/extract plugins").option("--format <format>", "Format of message catalogs").parse(process.argv);
_commander.program.option("--config <path>", "Path to the config file").option("--locale <locale>", "Only extract the specified locale").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.program.opts();
const config = (0, _conf.getConfig)({
configPath: _commander.default.config || process.env.LINGUI_CONFIG
configPath: options.config
});
let hasErrors = false;
if (_commander.default.format) {
hasErrors = true;
const msg = "--format option is deprecated." + " Please set format in configuration https://lingui.dev/ref/conf#format";
console.error(msg);
console.error();
}
if (_commander.default.babelOptions) {
hasErrors = true;
const msg = "--babelOptions option is deprecated." + " Please set extractBabelOptions in configuration https://lingui.dev/ref/conf#extractbabeloptions";
console.error(msg);
console.error();
}
const prevFormat = _commander.default.convertFrom;
const prevFormat = options.convertFrom;
if (prevFormat && config.format === prevFormat) {

@@ -94,5 +77,5 @@ hasErrors = true;

}
if (_commander.default.locale && !config.locales.includes(_commander.default.locale)) {
if (options.locale && !config.locales.includes(options.locale)) {
hasErrors = true;
console.error(`Locale ${_chalk.default.bold(_commander.default.locale)} does not exist.`);
console.error(`Locale ${_chalk.default.bold(options.locale)} does not exist.`);
console.error();

@@ -103,8 +86,7 @@ }

return command(config, {
verbose: _commander.default.watch || _commander.default.verbose || false,
clean: _commander.default.watch ? false : _commander.default.clean || false,
overwrite: _commander.default.watch || _commander.default.overwrite || false,
locale: _commander.default.locale,
configPath: _commander.default.config || process.env.LINGUI_CONFIG,
watch: _commander.default.watch || false,
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 && filePath.length ? filePath : undefined,

@@ -120,3 +102,3 @@ prevFormat

// on deleting the tmp folder.
if (!_commander.default.debounce) {
if (!options.debounce) {
previousExtract = previousExtract.then(() => extract(filePath));

@@ -133,9 +115,9 @@ return previousExtract;

await extract(filePath);
}, _commander.default.debounce);
}, options.debounce);
};
// Check if Watch Mode is enabled
if (_commander.default.watch) {
if (options.watch) {
console.info(_chalk.default.bold("Initializing Watch Mode..."));
const catalogs = (0, _catalog.getCatalogs)(config);
const catalogs = (0, _api.getCatalogs)(config);
let paths = [];

@@ -156,6 +138,6 @@ let ignored = [];

watcher.on("ready", () => onReady());
} else if (_commander.default.args) {
} else if (_commander.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.default.args).then(result => {
extract(_commander.program.args).then(result => {
if (!result) process.exit(1);

@@ -162,0 +144,0 @@ });

#!/usr/bin/env node
"use strict";
var _utils = require("./api/utils");
var _commander = _interopRequireDefault(require("commander"));
var _commander = require("commander");
var _package = require("../package.json");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
_commander.default.version(_package.version).command("add-locale", "Deprecated, run it for instructions").command("extract [files...]", "Extracts messages from source files").command("extract-template", "Extracts messages from source files to a .pot template").command("compile", "Compile message catalogs").parse(process.argv);
(0, _utils.helpMisspelledCommand)(process.argv[2], _commander.default.commands);
_commander.program.version(_package.version).command("extract [files...]", "Extracts messages from source files").command("extract-template", "Extracts messages from source files to a .pot template").command("compile", "Compile message catalogs").parse(process.argv);

@@ -22,2 +22,7 @@ "use strict";

});
const getTargetLocales = config => {
const sourceLocale = config.sourceLocale || "en";
const pseudoLocale = config.pseudoLocale || "pseudo";
return config.locales.filter(value => value != sourceLocale && value != pseudoLocale);
};

@@ -49,4 +54,3 @@ // Main sync method, call "Init" or "Sync" depending on the project context

const sourceLocale = config.sourceLocale || "en";
const pseudoLocale = config.pseudoLocale || "pseudo";
const targetLocales = config.locales.filter(value => value != sourceLocale && value != pseudoLocale);
const targetLocales = getTargetLocales(config);
const paths = poPathsPerLocale(config);

@@ -103,3 +107,3 @@ let segments = {};

const sourceLocale = config.sourceLocale || "en";
const targetLocales = config.locales.filter(value => value != sourceLocale);
const targetLocales = getTargetLocales(config);
const paths = poPathsPerLocale(config);

@@ -106,0 +110,0 @@ let segments = [];

@@ -7,15 +7,25 @@ "use strict";

exports.copyFixture = copyFixture;
exports.makeCatalog = exports.defaultMergeOptions = exports.defaultMakeTemplateOptions = exports.defaultMakeOptions = void 0;
exports.defaultMergeOptions = exports.defaultMakeTemplateOptions = exports.defaultMakeOptions = void 0;
exports.listingToHumanReadable = listingToHumanReadable;
exports.makeCatalog = void 0;
exports.makeNextMessage = makeNextMessage;
exports.makePrevMessage = makePrevMessage;
exports.normalizeLineEndings = void 0;
exports.readFsToJson = readFsToJson;
var _os = _interopRequireDefault(require("os"));
var _fsExtra = _interopRequireDefault(require("fs-extra"));
var _path = _interopRequireDefault(require("path"));
var _jestMocks = require("@lingui/jest-mocks");
var _fs = _interopRequireDefault(require("fs"));
var _catalog = require("./api/catalog");
var _conf = require("@lingui/conf");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function copyFixture(fixtureDir) {
const tmpDir = _fsExtra.default.mkdtempSync(_path.default.join(_os.default.tmpdir(), `lingui-test-${process.pid}`));
if (_fsExtra.default.existsSync(fixtureDir)) {
_fsExtra.default.copySync(fixtureDir, tmpDir);
async function copyFixture(fixtureDir) {
const tmpDir = await _fs.default.promises.mkdtemp(_path.default.join(_os.default.tmpdir(), `lingui-test-${process.pid}`));
try {
await _fs.default.promises.cp(fixtureDir, tmpDir, {
recursive: true
});
} catch (err) {
if (err.code != "ENOENT") {
throw err;
}
}

@@ -30,3 +40,2 @@ return tmpDir;

prevFormat: null,
configPath: null,
orderBy: "messageId"

@@ -37,3 +46,2 @@ };

verbose: false,
configPath: null,
orderBy: "messageId"

@@ -45,3 +53,8 @@ };

};
// on windows line endings are different,
// so direct comparison to snapshot would file if not normalized
exports.defaultMergeOptions = defaultMergeOptions;
const normalizeLineEndings = str => str.replace(/\r?\n/g, "\r\n");
exports.normalizeLineEndings = normalizeLineEndings;
const makeCatalog = (config = {}) => {

@@ -53,3 +66,5 @@ return new _catalog.Catalog({

exclude: []
}, (0, _jestMocks.mockConfig)(config));
}, (0, _conf.makeConfig)(config, {
skipValidation: true
}));
};

@@ -69,2 +84,32 @@ exports.makeCatalog = makeCatalog;

};
}
function listingToHumanReadable(listing) {
const output = [];
Object.entries(listing).forEach(([filename, value]) => {
if (typeof value === "string") {
output.push("#######################");
output.push(`Filename: ${filename}`);
output.push("#######################");
output.push("");
output.push(normalizeLineEndings(value));
output.push("");
} else {
output.push(...listingToHumanReadable(value));
}
});
return output.join("\n");
}
function readFsToJson(directory, filter) {
const out = {};
_fs.default.readdirSync(directory).map(filename => {
const filepath = _path.default.join(directory, filename);
if (_fs.default.lstatSync(filepath).isDirectory()) {
out[filename] = readFsToJson(filepath);
return out;
}
if (!filter || filter(filename)) {
out[filename] = _fs.default.readFileSync(filepath).toString();
}
});
return out;
}
{
"name": "@lingui/cli",
"version": "3.17.2",
"version": "4.0.0-next.0",
"description": "CLI for working wit message catalogs",

@@ -40,3 +40,3 @@ "keywords": [

"engines": {
"node": ">=14.0.0"
"node": ">=16.0.0"
},

@@ -49,2 +49,3 @@ "files": [

"dependencies": {
"@babel/core": "^7.20.12",
"@babel/generator": "^7.20.14",

@@ -55,5 +56,5 @@ "@babel/parser": "^7.20.15",

"@babel/types": "^7.20.7",
"@lingui/babel-plugin-extract-messages": "3.17.2",
"@lingui/conf": "3.17.2",
"@lingui/core": "3.17.2",
"@lingui/babel-plugin-extract-messages": "^4.0.0-next.0",
"@lingui/conf": "^4.0.0-next.0",
"@lingui/core": "^4.0.0-next.0",
"@messageformat/parser": "^5.0.0",

@@ -65,6 +66,5 @@ "babel-plugin-macros": "^3.0.1",

"cli-table": "0.3.6",
"commander": "^6.1.0",
"commander": "^10.0.0",
"convert-source-map": "^2.0.0",
"date-fns": "^2.16.1",
"fs-extra": "^9.0.1",
"fuzzaldrin": "^2.1.0",
"glob": "^7.1.4",

@@ -79,9 +79,11 @@ "inquirer": "^7.3.3",

"papaparse": "^5.3.0",
"pkg-up": "^3.1.0",
"plurals-cldr": "^1.0.4",
"pofile": "^1.1.0",
"pofile": "^1.1.4",
"pseudolocale": "^1.1.0",
"ramda": "^0.27.1"
"ramda": "^0.27.1",
"source-map": "^0.8.0-beta.0"
},
"devDependencies": {
"@lingui/jest-mocks": "^3.0.3",
"@types/convert-source-map": "^2.0.0",
"@types/micromatch": "^4.0.1",

@@ -91,11 +93,6 @@ "@types/normalize-path": "^3.0.0",

"@types/plurals-cldr": "^1.0.1",
"mockdate": "^3.0.2",
"typescript": "^4.9.5"
"mock-fs": "^5.2.0",
"mockdate": "^3.0.2"
},
"peerDependencies": {
"@babel/core": "^7.0.0",
"babel-plugin-macros": "2 || 3",
"typescript": "2 || 3 || 4"
},
"gitHead": "31dcab5a9a8f88bfa8b3a2c7cd12aa2d908a1d80"
"gitHead": "637f5cf6beda9d4ebce4e15cd9fdaa23e404b660"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc