@lingui/cli
Advanced tools
Comparing version 3.17.2 to 4.0.0-next.0
@@ -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" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
32
34
13
102163
8
2279
2
+ Added@babel/core@^7.20.12
+ Addedconvert-source-map@^2.0.0
+ Addedsource-map@^0.8.0-beta.0
+ Added@jest/schemas@29.6.3(transitive)
+ Added@jest/types@29.6.3(transitive)
+ Added@lingui/babel-plugin-extract-messages@4.12.0(transitive)
+ Added@lingui/conf@4.12.0(transitive)
+ Added@lingui/core@4.12.0(transitive)
+ Added@lingui/message-utils@4.12.0(transitive)
+ Added@sinclair/typebox@0.27.8(transitive)
+ Added@types/yargs@17.0.33(transitive)
+ Addedansi-styles@5.2.0(transitive)
+ Addedcommander@10.0.1(transitive)
+ Addedelectron-to-chromium@1.5.37(transitive)
+ Addedjest-get-type@29.6.3(transitive)
+ Addedjest-validate@29.7.0(transitive)
+ Addedjiti@1.21.6(transitive)
+ Addedjs-sha256@0.10.1(transitive)
+ Addedlodash.sortby@4.7.0(transitive)
+ Addedpretty-format@29.7.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedreact-is@18.3.1(transitive)
+ Addedsource-map@0.8.0-beta.0(transitive)
+ Addedtr46@1.0.1(transitive)
+ Addedunraw@3.0.0(transitive)
+ Addedwebidl-conversions@4.0.2(transitive)
+ Addedwhatwg-url@7.1.0(transitive)
- Removedfs-extra@^9.0.1
- Removedfuzzaldrin@^2.1.0
- Removedpkg-up@^3.1.0
- Removed@cspotcode/source-map-support@0.8.1(transitive)
- Removed@jest/types@26.6.2(transitive)
- Removed@jridgewell/trace-mapping@0.3.9(transitive)
- Removed@lingui/babel-plugin-extract-messages@3.17.2(transitive)
- Removed@lingui/conf@3.17.2(transitive)
- Removed@lingui/core@3.17.2(transitive)
- Removed@tsconfig/node10@1.0.11(transitive)
- Removed@tsconfig/node12@1.0.11(transitive)
- Removed@tsconfig/node14@1.0.3(transitive)
- Removed@tsconfig/node16@1.0.4(transitive)
- Removed@types/yargs@15.0.19(transitive)
- Removedacorn@8.12.1(transitive)
- Removedacorn-walk@8.3.4(transitive)
- Removedarg@4.1.3(transitive)
- Removedat-least-node@1.0.0(transitive)
- Removedcommander@6.2.1(transitive)
- Removedcosmiconfig-typescript-loader@4.4.0(transitive)
- Removedcreate-require@1.1.1(transitive)
- Removeddiff@4.0.2(transitive)
- Removedelectron-to-chromium@1.5.36(transitive)
- Removedfind-up@3.0.0(transitive)
- Removedfs-extra@9.1.0(transitive)
- Removedfuzzaldrin@2.1.0(transitive)
- Removedgraceful-fs@4.2.11(transitive)
- Removedjest-get-type@26.3.0(transitive)
- Removedjest-validate@26.6.2(transitive)
- Removedjsonfile@6.1.0(transitive)
- Removedlocate-path@3.0.0(transitive)
- Removedmake-error@1.3.6(transitive)
- Removedp-limit@2.3.0(transitive)
- Removedp-locate@3.0.0(transitive)
- Removedp-try@2.2.0(transitive)
- Removedpath-exists@3.0.0(transitive)
- Removedpkg-up@3.1.0(transitive)
- Removedpretty-format@26.6.2(transitive)
- Removedreact-is@17.0.2(transitive)
- Removedts-node@10.9.2(transitive)
- Removedtypescript@4.9.5(transitive)
- Removeduniversalify@2.0.1(transitive)
- Removedv8-compile-cache-lib@3.0.1(transitive)
- Removedyn@3.1.1(transitive)
Updated@lingui/conf@^4.0.0-next.0
Updated@lingui/core@^4.0.0-next.0
Updatedcommander@^10.0.0
Updatedpofile@^1.1.4