@lingui/cli 3.14.0 → 3.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +482 -0
  2. package/build/LICENSE +21 -0
  3. package/build/api/catalog.js +582 -0
  4. package/build/api/compile.js +89 -0
  5. package/{api → build/api}/detect.js +23 -9
  6. package/build/api/extract.js +78 -0
  7. package/build/api/extractors/babel.js +51 -0
  8. package/build/api/extractors/index.js +51 -0
  9. package/build/api/extractors/typescript.js +71 -0
  10. package/build/api/formats/csv.js +65 -0
  11. package/{api → build/api}/formats/index.js +8 -5
  12. package/build/api/formats/lingui.js +67 -0
  13. package/build/api/formats/minimal.js +63 -0
  14. package/build/api/formats/po-gettext.js +296 -0
  15. package/build/api/formats/po.js +122 -0
  16. package/{api → build/api}/help.js +6 -18
  17. package/{api → build/api}/index.js +7 -7
  18. package/build/api/locales.js +45 -0
  19. package/{api → build/api}/pseudoLocalize.js +13 -13
  20. package/build/api/stats.js +46 -0
  21. package/{api → build/api}/utils.js +21 -40
  22. package/build/lingui-add-locale.js +11 -0
  23. package/build/lingui-compile.js +192 -0
  24. package/build/lingui-extract-template.js +64 -0
  25. package/build/lingui-extract.js +181 -0
  26. package/{lingui.js → build/lingui.js} +2 -2
  27. package/{services → build/services}/translationIO.js +78 -94
  28. package/build/tests.js +78 -0
  29. package/package.json +19 -13
  30. package/api/catalog.js +0 -775
  31. package/api/compile.js +0 -169
  32. package/api/extract.js +0 -192
  33. package/api/extractors/babel.js +0 -61
  34. package/api/extractors/index.js +0 -130
  35. package/api/extractors/typescript.js +0 -77
  36. package/api/formats/csv.js +0 -71
  37. package/api/formats/lingui.js +0 -64
  38. package/api/formats/minimal.js +0 -50
  39. package/api/formats/po-gettext.js +0 -331
  40. package/api/formats/po.js +0 -130
  41. package/api/locales.js +0 -43
  42. package/api/stats.js +0 -51
  43. package/lingui-add-locale.js +0 -11
  44. package/lingui-compile.js +0 -199
  45. package/lingui-extract-template.js +0 -71
  46. package/lingui-extract.js +0 -286
@@ -0,0 +1,296 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _dateFns = require("date-fns");
9
+
10
+ var _fs = _interopRequireDefault(require("fs"));
11
+
12
+ var _parser = require("@messageformat/parser");
13
+
14
+ var _pluralsCldr = _interopRequireDefault(require("plurals-cldr"));
15
+
16
+ var _pofile = _interopRequireDefault(require("pofile"));
17
+
18
+ var R = _interopRequireWildcard(require("ramda"));
19
+
20
+ var _plurals = _interopRequireDefault(require("node-gettext/lib/plurals"));
21
+
22
+ var _utils = require("../utils");
23
+
24
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
25
+
26
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (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; }
27
+
28
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
+
30
+ function getCreateHeaders(language = "no") {
31
+ return {
32
+ "POT-Creation-Date": (0, _dateFns.format)(new Date(), "yyyy-MM-dd HH:mmxxxx"),
33
+ "MIME-Version": "1.0",
34
+ "Content-Type": "text/plain; charset=utf-8",
35
+ "Content-Transfer-Encoding": "8bit",
36
+ "X-Generator": "@lingui/cli",
37
+ Language: language
38
+ };
39
+ } // Attempts to turn a single tokenized ICU plural case back into a string.
40
+
41
+
42
+ function stringifyICUCase(icuCase) {
43
+ return icuCase.tokens.map(token => {
44
+ if (token.type === "content") {
45
+ return token.value;
46
+ } else if (token.type === "octothorpe") {
47
+ return "#";
48
+ } else if (token.type === "argument") {
49
+ return "{" + token.arg + "}";
50
+ } else {
51
+ console.warn(`Unexpected token "${token}" while stringifying plural case "${icuCase}". Token will be ignored.`);
52
+ return "";
53
+ }
54
+ }).join("");
55
+ }
56
+
57
+ const ICU_PLURAL_REGEX = /^{.*, plural, .*}$/;
58
+ const ICU_SELECT_REGEX = /^{.*, select(Ordinal)?, .*}$/;
59
+ const LINE_ENDINGS = /\r?\n/g; // Prefix that is used to identitify context information used by this module in PO's "extracted comments".
60
+
61
+ const CTX_PREFIX = "js-lingui:";
62
+
63
+ const serialize = (items, options) => R.compose(R.values, R.mapObjIndexed((message, key) => {
64
+ const item = new _pofile.default.Item();
65
+ item.msgid = key;
66
+ item.comments = message.comments || []; // The extractedComments array may be modified in this method, so create a new array with the message's elements.
67
+ // Destructuring `undefined` is forbidden, so fallback to `[]` if the message has no extracted comments.
68
+
69
+ item.extractedComments = [...(message.extractedComments ?? [])];
70
+
71
+ if (message.context) {
72
+ item.msgctxt = message.context;
73
+ }
74
+
75
+ if (options.origins !== false) {
76
+ if (message.origin && options.lineNumbers === false) {
77
+ item.references = message.origin.map(([path]) => path);
78
+ } else {
79
+ item.references = message.origin ? message.origin.map(_utils.joinOrigin) : [];
80
+ }
81
+ } // @ts-ignore: Figure out how to set this flag
82
+
83
+
84
+ item.obsolete = message.obsolete;
85
+ item.flags = message.flags ? R.fromPairs(message.flags.map(flag => [flag, true])) : {}; // Depending on whether custom ids are used by the developer, the (potential plural) "original", untranslated ICU
86
+ // message can be found in `message.message` or in the item's `key` itself.
87
+
88
+ const icuMessage = message.message || key;
89
+
90
+ const _simplifiedMessage = icuMessage.replace(LINE_ENDINGS, " "); // Quick check to see if original message is a plural localization.
91
+
92
+
93
+ if (ICU_PLURAL_REGEX.test(_simplifiedMessage)) {
94
+ try {
95
+ const messageAst = (0, _parser.parse)(icuMessage)[0]; // Check if any of the plural cases contain plurals themselves.
96
+
97
+ if (messageAst.cases.some(icuCase => icuCase.tokens.some(token => token.type === "plural"))) {
98
+ console.warn(`Nested plurals cannot be expressed with gettext plurals. ` + `Message with key "%s" will not be saved correctly.`, key);
99
+ } // Store placeholder that is pluralized upon to allow restoring ICU format later.
100
+
101
+
102
+ const ctx = new URLSearchParams({
103
+ pluralize_on: messageAst.arg
104
+ });
105
+
106
+ if (message.message == null) {
107
+ // For messages without developer-set ID, use first case as `msgid` and the last case as `msgid_plural`.
108
+ // This does not necessarily make sense for development languages with more than two numbers, but gettext
109
+ // only supports exactly two plural forms.
110
+ item.msgid = stringifyICUCase(messageAst.cases[0]);
111
+ item.msgid_plural = stringifyICUCase(messageAst.cases[messageAst.cases.length - 1]); // Since the original msgid is overwritten, store ICU message to allow restoring that ID later.
112
+
113
+ ctx.set("icu", key);
114
+ } else {
115
+ // For messages with developer-set ID, append `_plural` to the key to generate `msgid_plural`.
116
+ item.msgid_plural = key + "_plural";
117
+ }
118
+
119
+ ctx.sort();
120
+ item.extractedComments.push(CTX_PREFIX + ctx.toString()); // If there is a translated value, parse that instead of the original message to prevent overriding localized
121
+ // content with the original message. If there is no translated value, don't touch msgstr, since marking item as
122
+ // plural (above) already causes `pofile` to automatically generate `msgstr[0]` and `msgstr[1]`.
123
+
124
+ if (message.translation?.length > 0) {
125
+ try {
126
+ const ast = (0, _parser.parse)(message.translation)[0];
127
+
128
+ if (ast.cases == null) {
129
+ 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}"`);
130
+ item.msgstr = [message.translation];
131
+ } else {
132
+ item.msgstr = ast.cases.map(stringifyICUCase);
133
+ }
134
+ } catch (e) {
135
+ console.error(`Error parsing translation ICU for key "${key}"`, e);
136
+ }
137
+ }
138
+ } catch (e) {
139
+ console.error(`Error parsing message ICU for key "${key}":`, e);
140
+ }
141
+ } else {
142
+ if (!options.disableSelectWarning && ICU_SELECT_REGEX.test(_simplifiedMessage)) {
143
+ 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);
144
+ }
145
+
146
+ item.msgstr = [message.translation];
147
+ }
148
+
149
+ return item;
150
+ }))(items);
151
+
152
+ const getMessageKey = R.prop("msgid");
153
+ const getTranslations = R.prop("msgstr");
154
+ const getExtractedComments = R.prop("extractedComments");
155
+ const getTranslatorComments = R.prop("comments");
156
+ const getMessageContext = R.prop("msgctxt");
157
+ const getOrigins = R.prop("references");
158
+ const getFlags = R.compose(R.map(R.trim), R.keys, R.dissoc("obsolete"), // backward-compatibility, remove in 3.x
159
+ R.prop("flags"));
160
+ const isObsolete = R.either(R.path(["flags", "obsolete"]), R.prop("obsolete"));
161
+ const getTranslationCount = R.compose(R.length, getTranslations);
162
+ const deserialize = R.map(R.applySpec({
163
+ translation: R.compose(R.head, R.defaultTo([]), getTranslations),
164
+ extractedComments: R.compose(R.defaultTo([]), getExtractedComments),
165
+ comments: R.compose(R.defaultTo([]), getTranslatorComments),
166
+ context: R.compose(R.defaultTo(null), getMessageContext),
167
+ obsolete: isObsolete,
168
+ origin: R.compose(R.map(_utils.splitOrigin), R.defaultTo([]), getOrigins),
169
+ flags: getFlags
170
+ }));
171
+ /**
172
+ * Returns ICU case labels in the order that gettext lists localized messages, e.g. 0,1,2 => `["one", "two", "other"]`.
173
+ *
174
+ * Obtaining the ICU case labels for gettext-supported inputs (gettext doesn't support fractions, even though some
175
+ * languages have a separate case for fractional numbers) works by applying the CLDR selector to the example values
176
+ * listed in the node-gettext plurals module.
177
+ *
178
+ * This approach is heavily influenced by
179
+ * https://github.com/LLK/po2icu/blob/9eb97f81f72b2fee02b77f1424702e019647e9b9/lib/po2icu.js#L148.
180
+ */
181
+
182
+ const getPluralCases = lang => {
183
+ // If users uses locale with underscore or slash, es-ES, es_ES, gettextplural is "es" not es-ES.
184
+ const [correctLang] = lang.split(/[-_]/g);
185
+ const gettextPluralsInfo = _plurals.default[correctLang];
186
+ return gettextPluralsInfo?.examples.map(pluralCase => (0, _pluralsCldr.default)(correctLang, pluralCase.sample));
187
+ };
188
+
189
+ const convertPluralsToICU = (items, lang) => {
190
+ // .po plurals are numbered 0-N and need to be mapped to ICU plural classes ("one", "few", "many"...). Different
191
+ // languages can have different plural classes (some start with "zero", some with "one"), so read that data from CLDR.
192
+ // `pluralForms` may be `null` if lang is not found. As long as no plural is used, don't report an error.
193
+ let pluralForms = getPluralCases(lang);
194
+ items.forEach(item => {
195
+ const translationCount = getTranslationCount(item);
196
+ const messageKey = getMessageKey(item); // Messages without multiple translations (= plural cases) need no further processing.
197
+
198
+ if (translationCount <= 1 && !item.msgid_plural) {
199
+ return;
200
+ } // msgid_plural must be set, but its actual value is not important.
201
+
202
+
203
+ if (!item.msgid_plural) {
204
+ 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);
205
+ return;
206
+ }
207
+
208
+ const contextComment = item.extractedComments.find(comment => comment.startsWith(CTX_PREFIX))?.substr(CTX_PREFIX.length);
209
+ const ctx = new URLSearchParams(contextComment);
210
+
211
+ if (contextComment != null) {
212
+ item.extractedComments = item.extractedComments.filter(comment => !comment.startsWith(CTX_PREFIX));
213
+ } // If an original ICU was stored, use that as `msgid` to match the catalog that was originally exported.
214
+
215
+
216
+ const storedICU = ctx.get("icu");
217
+
218
+ if (storedICU != null) {
219
+ item.msgid = storedICU;
220
+ } // If all translations are empty, ignore item.
221
+
222
+
223
+ if (item.msgstr.every(str => str.length === 0)) {
224
+ return;
225
+ }
226
+
227
+ if (pluralForms == null) {
228
+ 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);
229
+ return;
230
+ }
231
+
232
+ const pluralCount = pluralForms.length;
233
+
234
+ if (translationCount > pluralCount) {
235
+ 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);
236
+ } // Map each msgstr to a "<pluralform> {<translated_string>}" entry, joined by one space.
237
+
238
+
239
+ const pluralClauses = item.msgstr.map((str, index) => pluralForms[index] + " {" + str + "}").join(" "); // Find out placeholder name from item's message context, defaulting to "count".
240
+
241
+ let pluralizeOn = ctx.get("pluralize_on");
242
+
243
+ if (!pluralizeOn) {
244
+ 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);
245
+ pluralizeOn = "count";
246
+ }
247
+
248
+ item.msgstr = ["{" + pluralizeOn + ", plural, " + pluralClauses + "}"];
249
+ });
250
+ };
251
+
252
+ const indexItems = R.indexBy(getMessageKey);
253
+ const poGettext = {
254
+ catalogExtension: ".po",
255
+
256
+ write(filename, catalog, options) {
257
+ let po;
258
+
259
+ if (_fs.default.existsSync(filename)) {
260
+ const raw = _fs.default.readFileSync(filename).toString();
261
+
262
+ po = _pofile.default.parse(raw);
263
+ } else {
264
+ po = new _pofile.default();
265
+ po.headers = getCreateHeaders(options.locale);
266
+
267
+ if (options.locale === undefined) {
268
+ delete po.headers.Language;
269
+ }
270
+
271
+ po.headerOrder = Object.keys(po.headers);
272
+ }
273
+
274
+ po.items = this.serialize(catalog, options);
275
+ (0, _utils.writeFileIfChanged)(filename, po.toString());
276
+ },
277
+
278
+ // Mainly exported for easier testing
279
+ serialize,
280
+
281
+ read(filename) {
282
+ const raw = _fs.default.readFileSync(filename).toString();
283
+
284
+ return this.parse(raw);
285
+ },
286
+
287
+ parse(raw) {
288
+ const po = _pofile.default.parse(raw);
289
+
290
+ convertPluralsToICU(po.items, po.headers.Language);
291
+ return deserialize(indexItems(po.items));
292
+ }
293
+
294
+ };
295
+ var _default = poGettext;
296
+ exports.default = _default;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _fs = _interopRequireDefault(require("fs"));
9
+
10
+ var R = _interopRequireWildcard(require("ramda"));
11
+
12
+ var _dateFns = require("date-fns");
13
+
14
+ var _pofile = _interopRequireDefault(require("pofile"));
15
+
16
+ var _utils = require("../utils");
17
+
18
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
19
+
20
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (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; }
21
+
22
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
+
24
+ const getCreateHeaders = (language = "no") => ({
25
+ "POT-Creation-Date": (0, _dateFns.format)(new Date(), "yyyy-MM-dd HH:mmxxxx"),
26
+ "MIME-Version": "1.0",
27
+ "Content-Type": "text/plain; charset=utf-8",
28
+ "Content-Transfer-Encoding": "8bit",
29
+ "X-Generator": "@lingui/cli",
30
+ Language: language
31
+ });
32
+
33
+ const serialize = (items, options) => R.compose(R.values, R.mapObjIndexed((message, key) => {
34
+ const item = new _pofile.default.Item();
35
+ item.msgid = key;
36
+ item.msgstr = [message.translation];
37
+ item.comments = message.comments || [];
38
+ item.extractedComments = message.extractedComments || [];
39
+
40
+ if (message.context) {
41
+ item.msgctxt = message.context;
42
+ }
43
+
44
+ if (options.origins !== false) {
45
+ if (message.origin && options.lineNumbers === false) {
46
+ item.references = message.origin.map(([path]) => path);
47
+ } else {
48
+ item.references = message.origin ? message.origin.map(_utils.joinOrigin) : [];
49
+ }
50
+ } // @ts-ignore: Figure out how to set this flag
51
+
52
+
53
+ item.obsolete = message.obsolete;
54
+ item.flags = message.flags ? R.fromPairs(message.flags.map(flag => [flag, true])) : {};
55
+ return item;
56
+ }))(items);
57
+
58
+ const getMessageKey = R.prop("msgid");
59
+ const getTranslations = R.prop("msgstr");
60
+ const getExtractedComments = R.prop("extractedComments");
61
+ const getTranslatorComments = R.prop("comments");
62
+ const getMessageContext = R.prop("msgctxt");
63
+ const getOrigins = R.prop("references");
64
+ const getFlags = R.compose(R.map(R.trim), R.keys, R.dissoc("obsolete"), // backward-compatibility, remove in 3.x
65
+ R.prop("flags"));
66
+ const isObsolete = R.either(R.path(["flags", "obsolete"]), R.prop("obsolete"));
67
+ const deserialize = R.map(R.applySpec({
68
+ translation: R.compose(R.head, R.defaultTo([]), getTranslations),
69
+ extractedComments: R.compose(R.defaultTo([]), getExtractedComments),
70
+ comments: R.compose(R.defaultTo([]), getTranslatorComments),
71
+ context: R.compose(R.defaultTo(null), getMessageContext),
72
+ obsolete: isObsolete,
73
+ origin: R.compose(R.map(_utils.splitOrigin), R.defaultTo([]), getOrigins),
74
+ flags: getFlags
75
+ }));
76
+ const validateItems = R.forEach(item => {
77
+ if (R.length(getTranslations(item)) > 1) {
78
+ console.warn("Multiple translations for item with key %s is not supported and it will be ignored.", getMessageKey(item));
79
+ }
80
+ });
81
+ const indexItems = R.indexBy(getMessageKey);
82
+ const po = {
83
+ catalogExtension: ".po",
84
+
85
+ write(filename, catalog, options) {
86
+ let po;
87
+
88
+ if (_fs.default.existsSync(filename)) {
89
+ const raw = _fs.default.readFileSync(filename).toString();
90
+
91
+ po = _pofile.default.parse(raw);
92
+ } else {
93
+ po = new _pofile.default();
94
+ po.headers = getCreateHeaders(options.locale);
95
+
96
+ if (options.locale === undefined) {
97
+ delete po.headers.Language;
98
+ }
99
+
100
+ po.headerOrder = R.keys(po.headers);
101
+ }
102
+
103
+ po.items = serialize(catalog, options);
104
+ (0, _utils.writeFileIfChanged)(filename, po.toString());
105
+ },
106
+
107
+ read(filename) {
108
+ const raw = _fs.default.readFileSync(filename).toString();
109
+
110
+ return this.parse(raw);
111
+ },
112
+
113
+ parse(raw) {
114
+ const po = _pofile.default.parse(raw);
115
+
116
+ validateItems(po.items);
117
+ return deserialize(indexItems(po.items));
118
+ }
119
+
120
+ };
121
+ var _default = po;
122
+ exports.default = _default;
@@ -1,14 +1,10 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
3
  Object.defineProperty(exports, "__esModule", {
6
4
  value: true
7
5
  });
8
6
  exports.helpRun = helpRun;
9
7
 
10
- var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
11
-
12
8
  var _path = require("path");
13
9
 
14
10
  /**
@@ -30,30 +26,22 @@ var _path = require("path");
30
26
  * (use "npm run compile" to compile catalogs for production)
31
27
  */
32
28
  function helpRun(command) {
33
- var _findRootPkgJson;
34
-
35
- var findRootPkgJson;
29
+ let findRootPkgJson;
36
30
 
37
31
  try {
38
32
  findRootPkgJson = require((0, _path.resolve)((0, _path.join)(process.cwd(), "package.json")));
39
33
  } catch (error) {}
40
34
 
41
- if ((_findRootPkgJson = findRootPkgJson) === null || _findRootPkgJson === void 0 ? void 0 : _findRootPkgJson.scripts) {
42
- var res = Object.entries(findRootPkgJson.scripts).find(function (_ref) {
43
- var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
44
- _ = _ref2[0],
45
- value = _ref2[1];
46
-
47
- return value.includes("lingui ".concat(command));
48
- });
35
+ if (findRootPkgJson?.scripts) {
36
+ const res = Object.entries(findRootPkgJson.scripts).find(([_, value]) => value.includes(`lingui ${command}`));
49
37
 
50
38
  if (res) {
51
39
  command = res[0];
52
40
  }
53
41
  }
54
42
 
55
- return "".concat(runCommand, " ").concat(command);
43
+ return `${runCommand} ${command}`;
56
44
  }
57
45
 
58
- var isYarn = process.env.npm_config_user_agent && process.env.npm_config_user_agent.includes("yarn");
59
- var runCommand = isYarn ? "yarn" : "npm run";
46
+ const isYarn = process.env.npm_config_user_agent && process.env.npm_config_user_agent.includes("yarn");
47
+ const runCommand = isYarn ? "yarn" : "npm run";
@@ -1,31 +1,29 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
3
  Object.defineProperty(exports, "__esModule", {
6
4
  value: true
7
5
  });
8
6
  Object.defineProperty(exports, "getFormat", {
9
7
  enumerable: true,
10
- get: function get() {
8
+ get: function () {
11
9
  return _formats.default;
12
10
  }
13
11
  });
14
12
  Object.defineProperty(exports, "getCatalogs", {
15
13
  enumerable: true,
16
- get: function get() {
14
+ get: function () {
17
15
  return _catalog.getCatalogs;
18
16
  }
19
17
  });
20
18
  Object.defineProperty(exports, "getCatalogForFile", {
21
19
  enumerable: true,
22
- get: function get() {
20
+ get: function () {
23
21
  return _catalog.getCatalogForFile;
24
22
  }
25
23
  });
26
24
  Object.defineProperty(exports, "createCompiledCatalog", {
27
25
  enumerable: true,
28
- get: function get() {
26
+ get: function () {
29
27
  return _compile.createCompiledCatalog;
30
28
  }
31
29
  });
@@ -34,4 +32,6 @@ var _formats = _interopRequireDefault(require("./formats"));
34
32
 
35
33
  var _catalog = require("./catalog");
36
34
 
37
- var _compile = require("./compile");
35
+ var _compile = require("./compile");
36
+
37
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isValid = isValid;
7
+ exports.parse = parse;
8
+
9
+ var plurals = _interopRequireWildcard(require("make-plural/plurals"));
10
+
11
+ var _bcp = _interopRequireDefault(require("bcp-47"));
12
+
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
+
15
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
16
+
17
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (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; }
18
+
19
+ /**
20
+ * Check that locale is valid according to BCP47 and we have plurals for it
21
+ * @param locale: string - Locale in BCP47 format
22
+ * @return {boolean}
23
+ */
24
+ function isValid(locale) {
25
+ const localeData = parse(locale);
26
+ return localeData !== null && localeData !== undefined && localeData.language in plurals;
27
+ }
28
+ /**
29
+ * Parse locale in BCP47 format and
30
+ * @param locale - Locale in BCP47 format
31
+ * @return {LocaleInfo}
32
+ */
33
+
34
+
35
+ function parse(locale) {
36
+ if (typeof locale !== "string") return null;
37
+
38
+ const schema = _bcp.default.parse(locale.replace("_", "-"));
39
+
40
+ if (!schema.language) return null;
41
+ return {
42
+ locale: _bcp.default.stringify(schema),
43
+ language: schema.language
44
+ };
45
+ }
@@ -1,7 +1,5 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
3
  Object.defineProperty(exports, "__esModule", {
6
4
  value: true
7
5
  });
@@ -11,7 +9,9 @@ var _ramda = _interopRequireDefault(require("ramda"));
11
9
 
12
10
  var _pseudolocale = _interopRequireDefault(require("pseudolocale"));
13
11
 
14
- var delimiter = "%&&&%";
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ const delimiter = "%&&&%";
15
15
  _pseudolocale.default.option.delimiter = delimiter; // We do not want prepending and appending because of Plurals structure
16
16
 
17
17
  _pseudolocale.default.option.prepend = "";
@@ -22,7 +22,7 @@ _pseudolocale.default.option.append = "";
22
22
  * Example: https://regex101.com/r/bDHD9z/3
23
23
  */
24
24
 
25
- var HTMLRegex = /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)\/?>/g;
25
+ const HTMLRegex = /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)\/?>/g;
26
26
  /**
27
27
  * Regex should match js-lingui Plurals, Select and SelectOrdinal components
28
28
  * Example:
@@ -31,33 +31,33 @@ var HTMLRegex = /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)\/?
31
31
  * Select https://regex101.com/r/9JnqB9/1
32
32
  */
33
33
 
34
- var MacroRegex = /({\w*,\s*(plural|selectordinal|select),(.|\n)*?{)|(}\s*\w*\s*{)/gi;
34
+ const MacroRegex = /({\w*,\s*(plural|selectordinal|select),(.|\n)*?{)|(}\s*\w*\s*{)/gi;
35
35
  /**
36
36
  * Regex should match js-lingui variables
37
37
  * Example: https://regex101.com/r/dw1QHb/2
38
38
  */
39
39
 
40
- var VariableRegex = /({\s*[a-zA-Z_$][a-zA-Z_$0-9]*\s*})/g;
40
+ const VariableRegex = /({\s*[a-zA-Z_$][a-zA-Z_$0-9]*\s*})/g;
41
41
 
42
42
  function addDelimitersHTMLTags(message) {
43
- return message.replace(HTMLRegex, function (matchedString) {
44
- return "".concat(delimiter).concat(matchedString).concat(delimiter);
43
+ return message.replace(HTMLRegex, matchedString => {
44
+ return `${delimiter}${matchedString}${delimiter}`;
45
45
  });
46
46
  }
47
47
 
48
48
  function addDelimitersMacro(message) {
49
- return message.replace(MacroRegex, function (matchedString) {
50
- return "".concat(delimiter).concat(matchedString).concat(delimiter);
49
+ return message.replace(MacroRegex, matchedString => {
50
+ return `${delimiter}${matchedString}${delimiter}`;
51
51
  });
52
52
  }
53
53
 
54
54
  function addDelimitersVariables(message) {
55
- return message.replace(VariableRegex, function (matchedString) {
56
- return "".concat(delimiter).concat(matchedString).concat(delimiter);
55
+ return message.replace(VariableRegex, matchedString => {
56
+ return `${delimiter}${matchedString}${delimiter}`;
57
57
  });
58
58
  }
59
59
 
60
- var addDelimiters = _ramda.default.compose(addDelimitersVariables, addDelimitersMacro, addDelimitersHTMLTags);
60
+ const addDelimiters = _ramda.default.compose(addDelimitersVariables, addDelimitersMacro, addDelimitersHTMLTags);
61
61
 
62
62
  function removeDelimiters(message) {
63
63
  return message.replace(new RegExp(delimiter, "g"), "");
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getStats = getStats;
7
+ exports.printStats = printStats;
8
+
9
+ var _cliTable = _interopRequireDefault(require("cli-table"));
10
+
11
+ var _chalk = _interopRequireDefault(require("chalk"));
12
+
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
+
15
+ function getStats(catalog) {
16
+ return [Object.keys(catalog).length, Object.keys(catalog).filter(key => !catalog[key].translation).length];
17
+ }
18
+
19
+ function printStats(config, catalogs) {
20
+ const table = new _cliTable.default({
21
+ head: ["Language", "Total count", "Missing"],
22
+ colAligns: ["left", "middle", "middle"],
23
+ style: {
24
+ head: ["green"],
25
+ border: [],
26
+ compact: true
27
+ }
28
+ });
29
+ Object.keys(catalogs).forEach(locale => {
30
+ const catalog = catalogs[locale]; // catalog is null if no catalog exists on disk and the locale
31
+ // was not extracted due to a `--locale` filter
32
+
33
+ const [all, translated] = catalog ? getStats(catalog) : ["-", "-"];
34
+
35
+ if (config.sourceLocale === locale) {
36
+ table.push({
37
+ [`${_chalk.default.bold(locale)} (source)`]: [all, "-"]
38
+ });
39
+ } else {
40
+ table.push({
41
+ [locale]: [all, translated]
42
+ });
43
+ }
44
+ });
45
+ return table;
46
+ }