@lingui/cli 3.15.0 → 3.16.1

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 +495 -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 +24 -12
  30. package/api/catalog.js +0 -778
  31. package/api/compile.js +0 -172
  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 -63
  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 -198
  45. package/lingui-extract-template.js +0 -123
  46. package/lingui-extract.js +0 -286
@@ -0,0 +1,582 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getCatalogs = getCatalogs;
7
+ exports.getCatalogForFile = getCatalogForFile;
8
+ exports.getCatalogForMerge = getCatalogForMerge;
9
+ exports.normalizeRelativePath = normalizeRelativePath;
10
+ exports.order = order;
11
+ exports.orderByMessageId = orderByMessageId;
12
+ exports.orderByOrigin = orderByOrigin;
13
+ exports.cleanObsolete = exports.Catalog = void 0;
14
+
15
+ var _os = _interopRequireDefault(require("os"));
16
+
17
+ var _fsExtra = _interopRequireDefault(require("fs-extra"));
18
+
19
+ var _path = _interopRequireDefault(require("path"));
20
+
21
+ var R = _interopRequireWildcard(require("ramda"));
22
+
23
+ var _chalk = _interopRequireDefault(require("chalk"));
24
+
25
+ var _glob = _interopRequireDefault(require("glob"));
26
+
27
+ var _micromatch = _interopRequireDefault(require("micromatch"));
28
+
29
+ var _normalizePath = _interopRequireDefault(require("normalize-path"));
30
+
31
+ var _formats = _interopRequireDefault(require("./formats"));
32
+
33
+ var _extractors = _interopRequireDefault(require("./extractors"));
34
+
35
+ var _utils = require("./utils");
36
+
37
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
38
+
39
+ 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; }
40
+
41
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
42
+
43
+ const NAME = "{name}";
44
+ const NAME_REPLACE_RE = /{name}/g;
45
+ const LOCALE = "{locale}";
46
+ const LOCALE_REPLACE_RE = /{locale}/g;
47
+ const LOCALE_SUFFIX_RE = /\{locale\}.*$/;
48
+ const PATHSEP = "/"; // force posix everywhere
49
+
50
+ class Catalog {
51
+ constructor({
52
+ name,
53
+ path,
54
+ include,
55
+ exclude = []
56
+ }, config) {
57
+ this.name = name;
58
+ this.path = normalizeRelativePath(path);
59
+ this.include = include.map(normalizeRelativePath);
60
+ this.exclude = [this.localeDir, ...exclude.map(normalizeRelativePath)];
61
+ this.config = config;
62
+ this.format = (0, _formats.default)(config.format);
63
+ }
64
+
65
+ async make(options) {
66
+ const nextCatalog = await this.collect(options);
67
+ if (!nextCatalog) return false;
68
+ const prevCatalogs = this.readAll();
69
+ const catalogs = this.merge(prevCatalogs, nextCatalog, {
70
+ overwrite: options.overwrite,
71
+ files: options.files
72
+ }); // Map over all locales and post-process each catalog
73
+
74
+ const cleanAndSort = R.map(R.pipe( // Clean obsolete messages
75
+ options.clean ? cleanObsolete : R.identity, // Sort messages
76
+ order(options.orderBy)));
77
+ const sortedCatalogs = cleanAndSort(catalogs);
78
+
79
+ if (options.locale) {
80
+ this.write(options.locale, sortedCatalogs[options.locale]);
81
+ } else {
82
+ this.writeAll(sortedCatalogs);
83
+ }
84
+
85
+ return true;
86
+ }
87
+
88
+ async makeTemplate(options) {
89
+ const catalog = await this.collect(options);
90
+ if (!catalog) return false;
91
+ const sort = order(options.orderBy);
92
+ this.writeTemplate(sort(catalog));
93
+ return true;
94
+ }
95
+ /**
96
+ * Collect messages from source paths. Return a raw message catalog as JSON.
97
+ */
98
+
99
+
100
+ async collect(options) {
101
+ const tmpDir = _path.default.join(_os.default.tmpdir(), `lingui-${process.pid}`);
102
+
103
+ if (_fsExtra.default.existsSync(tmpDir)) {
104
+ (0, _utils.removeDirectory)(tmpDir, true);
105
+ } else {
106
+ _fsExtra.default.mkdirSync(tmpDir);
107
+ }
108
+
109
+ try {
110
+ let paths = this.sourcePaths;
111
+
112
+ if (options.files) {
113
+ options.files = options.files.map(p => (0, _normalizePath.default)(p, false));
114
+ const regex = new RegExp(options.files.join("|"), "i");
115
+ paths = paths.filter(path => regex.test(path));
116
+ }
117
+
118
+ let catalogSuccess = true;
119
+
120
+ for (let filename of paths) {
121
+ const fileSuccess = await (0, _extractors.default)(filename, tmpDir, {
122
+ verbose: options.verbose,
123
+ configPath: options.configPath,
124
+ babelOptions: this.config.extractBabelOptions,
125
+ extractors: options.extractors,
126
+ projectType: options.projectType
127
+ });
128
+ catalogSuccess && (catalogSuccess = fileSuccess);
129
+ }
130
+
131
+ if (!catalogSuccess) return undefined;
132
+ return function traverse(directory) {
133
+ return _fsExtra.default.readdirSync(directory).map(filename => {
134
+ const filepath = _path.default.join(directory, filename);
135
+
136
+ if (_fsExtra.default.lstatSync(filepath).isDirectory()) {
137
+ return traverse(filepath);
138
+ }
139
+
140
+ if (!filename.endsWith(".json")) return;
141
+
142
+ try {
143
+ return JSON.parse(_fsExtra.default.readFileSync(filepath).toString());
144
+ } catch (e) {}
145
+ }).filter(Boolean).reduce((catalog, messages) => R.mergeWithKey(mergeOriginsAndExtractedComments, catalog, messages), {});
146
+ }(tmpDir);
147
+ } catch (e) {
148
+ throw e;
149
+ } finally {
150
+ (0, _utils.removeDirectory)(tmpDir);
151
+ }
152
+ }
153
+
154
+ merge(prevCatalogs, nextCatalog, options) {
155
+ const nextKeys = R.keys(nextCatalog).map(String);
156
+ return R.mapObjIndexed((prevCatalog, locale) => {
157
+ const prevKeys = R.keys(prevCatalog).map(String);
158
+ const newKeys = R.difference(nextKeys, prevKeys);
159
+ const mergeKeys = R.intersection(nextKeys, prevKeys);
160
+ const obsoleteKeys = R.difference(prevKeys, nextKeys); // Initialize new catalog with new keys
161
+
162
+ const newMessages = R.mapObjIndexed((message, key) => ({
163
+ translation: this.config.sourceLocale === locale ? message.message || key : "",
164
+ ...message
165
+ }), R.pick(newKeys, nextCatalog)); // Merge translations from previous catalog
166
+
167
+ const mergedMessages = mergeKeys.map(key => {
168
+ const updateFromDefaults = this.config.sourceLocale === locale && (prevCatalog[key].translation === prevCatalog[key].message || options.overwrite);
169
+ const translation = updateFromDefaults ? nextCatalog[key].message || key : prevCatalog[key].translation;
170
+ return {
171
+ [key]: {
172
+ translation,
173
+ ...R.omit(["obsolete, translation"], nextCatalog[key])
174
+ }
175
+ };
176
+ }); // Mark all remaining translations as obsolete
177
+ // Only if *options.files* is not provided
178
+
179
+ const obsoleteMessages = obsoleteKeys.map(key => ({
180
+ [key]: { ...prevCatalog[key],
181
+ obsolete: options.files ? false : true
182
+ }
183
+ }));
184
+ return R.mergeAll([newMessages, ...mergedMessages, ...obsoleteMessages]);
185
+ }, prevCatalogs);
186
+ }
187
+
188
+ getTranslations(locale, options) {
189
+ const catalogs = this.readAll();
190
+ const template = this.readTemplate() || {};
191
+ return R.mapObjIndexed((_value, key) => this.getTranslation(catalogs, locale, key, options), { ...template,
192
+ ...catalogs[locale]
193
+ });
194
+ }
195
+
196
+ getTranslation(catalogs, locale, key, {
197
+ fallbackLocales,
198
+ sourceLocale
199
+ }) {
200
+ const catalog = catalogs[locale] || {};
201
+
202
+ if (!catalog.hasOwnProperty(key)) {
203
+ console.error(`Message with key ${key} is missing in locale ${locale}`);
204
+ }
205
+
206
+ const getTranslation = _locale => {
207
+ const configLocales = this.config.locales.join('", "');
208
+ const localeCatalog = catalogs[_locale] || {};
209
+
210
+ if (!localeCatalog) {
211
+ console.warn(`
212
+ Catalog "${_locale}" isn't present in locales config parameter
213
+ Add "${_locale}" to your lingui.config.js:
214
+ {
215
+ locales: ["${configLocales}", "${_locale}"]
216
+ }
217
+ `);
218
+ return null;
219
+ }
220
+
221
+ if (!localeCatalog.hasOwnProperty(key)) {
222
+ console.error(`Message with key ${key} is missing in locale ${_locale}`);
223
+ return null;
224
+ }
225
+
226
+ if (catalogs[_locale]) {
227
+ return catalogs[_locale][key].translation;
228
+ }
229
+
230
+ return null;
231
+ };
232
+
233
+ const getMultipleFallbacks = _locale => {
234
+ const fL = fallbackLocales && fallbackLocales[_locale]; // some probably the fallback will be undefined, so just search by locale
235
+
236
+ if (!fL) return null;
237
+
238
+ if (Array.isArray(fL)) {
239
+ for (const fallbackLocale of fL) {
240
+ if (catalogs[fallbackLocale]) {
241
+ return getTranslation(fallbackLocale);
242
+ }
243
+ }
244
+ } else {
245
+ return getTranslation(fL);
246
+ }
247
+ };
248
+
249
+ return (// Get translation in target locale
250
+ getTranslation(locale) || // We search in fallbackLocales as dependent of each locale
251
+ getMultipleFallbacks(locale) || // Get translation in fallbackLocales.default (if any)
252
+ fallbackLocales?.default && getTranslation(fallbackLocales.default) || // Get message default
253
+ catalog[key]?.defaults || // If sourceLocale is either target locale of fallback one, use key
254
+ sourceLocale && sourceLocale === locale && key || sourceLocale && fallbackLocales?.default && sourceLocale === fallbackLocales.default && key || // Otherwise no translation is available
255
+ undefined
256
+ );
257
+ }
258
+
259
+ write(locale, messages) {
260
+ const filename = this.path.replace(LOCALE_REPLACE_RE, locale) + this.format.catalogExtension;
261
+ const created = !_fsExtra.default.existsSync(filename);
262
+
263
+ const basedir = _path.default.dirname(filename);
264
+
265
+ if (!_fsExtra.default.existsSync(basedir)) {
266
+ _fsExtra.default.mkdirpSync(basedir);
267
+ }
268
+
269
+ const options = { ...this.config.formatOptions,
270
+ locale
271
+ };
272
+ this.format.write(filename, messages, options);
273
+ return [created, filename];
274
+ }
275
+
276
+ writeAll(catalogs) {
277
+ this.locales.forEach(locale => this.write(locale, catalogs[locale]));
278
+ }
279
+
280
+ writeTemplate(messages) {
281
+ const filename = this.templateFile;
282
+
283
+ const basedir = _path.default.dirname(filename);
284
+
285
+ if (!_fsExtra.default.existsSync(basedir)) {
286
+ _fsExtra.default.mkdirpSync(basedir);
287
+ }
288
+
289
+ const options = { ...this.config.formatOptions,
290
+ locale: undefined
291
+ };
292
+ this.format.write(filename, messages, options);
293
+ }
294
+
295
+ writeCompiled(locale, compiledCatalog, namespace) {
296
+ let ext;
297
+
298
+ if (namespace === "es") {
299
+ ext = "mjs";
300
+ } else if (namespace === "ts") {
301
+ ext = "ts";
302
+ } else {
303
+ ext = "js";
304
+ }
305
+
306
+ const filename = `${this.path.replace(LOCALE_REPLACE_RE, locale)}.${ext}`;
307
+
308
+ const basedir = _path.default.dirname(filename);
309
+
310
+ if (!_fsExtra.default.existsSync(basedir)) {
311
+ _fsExtra.default.mkdirpSync(basedir);
312
+ }
313
+
314
+ _fsExtra.default.writeFileSync(filename, compiledCatalog);
315
+
316
+ return filename;
317
+ }
318
+
319
+ read(locale) {
320
+ const filename = this.path.replace(LOCALE_REPLACE_RE, locale) + this.format.catalogExtension;
321
+ if (!_fsExtra.default.existsSync(filename)) return null;
322
+ return this.format.read(filename);
323
+ }
324
+
325
+ readAll() {
326
+ return R.mergeAll(this.locales.map(locale => ({
327
+ [locale]: this.read(locale)
328
+ })));
329
+ }
330
+
331
+ readTemplate() {
332
+ const filename = this.templateFile;
333
+ if (!_fsExtra.default.existsSync(filename)) return null;
334
+ return this.format.read(filename);
335
+ }
336
+
337
+ get sourcePaths() {
338
+ const includeGlobs = this.include.map(includePath => {
339
+ const isDir = _fsExtra.default.existsSync(includePath) && _fsExtra.default.lstatSync(includePath).isDirectory();
340
+ /**
341
+ * glob library results from absolute patterns such as /foo/* are mounted onto the root setting using path.join.
342
+ * On windows, this will by default result in /foo/* matching C:\foo\bar.txt.
343
+ */
344
+
345
+
346
+ return isDir ? (0, _normalizePath.default)(_path.default.resolve(process.cwd(), includePath === "/" ? "" : includePath, "**/*.*")) : includePath;
347
+ });
348
+ const patterns = includeGlobs.length > 1 ? `{${includeGlobs.join(",")}}` : includeGlobs[0];
349
+ return _glob.default.sync(patterns, {
350
+ ignore: this.exclude,
351
+ mark: true
352
+ });
353
+ }
354
+
355
+ get templateFile() {
356
+ return this.path.replace(LOCALE_SUFFIX_RE, "messages.pot");
357
+ }
358
+
359
+ get localeDir() {
360
+ const localePatternIndex = this.path.indexOf(LOCALE);
361
+
362
+ if (localePatternIndex === -1) {
363
+ throw Error(`Invalid catalog path: ${LOCALE} variable is missing`);
364
+ }
365
+
366
+ return this.path.substr(0, localePatternIndex);
367
+ }
368
+
369
+ get locales() {
370
+ return this.config.locales;
371
+ }
372
+
373
+ }
374
+ /**
375
+ * Parse `config.catalogs` and return a list of configured Catalog instances.
376
+ */
377
+
378
+
379
+ exports.Catalog = Catalog;
380
+
381
+ function getCatalogs(config) {
382
+ const catalogsConfig = config.catalogs;
383
+ const catalogs = [];
384
+ catalogsConfig.forEach(catalog => {
385
+ // Validate that `catalogPath` doesn't end with trailing slash
386
+ if (catalog.path.endsWith(PATHSEP)) {
387
+ const extension = (0, _formats.default)(config.format).catalogExtension;
388
+ const correctPath = catalog.path.slice(0, -1);
389
+ const examplePath = correctPath.replace(LOCALE_REPLACE_RE, // Show example using one of configured locales (if any)
390
+ (config.locales || [])[0] || "en") + extension;
391
+ throw new Error( // prettier-ignore
392
+ `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}".`);
393
+ }
394
+
395
+ const include = ensureArray(catalog.include).map(normalizeRelativePath);
396
+ const exclude = ensureArray(catalog.exclude).map(normalizeRelativePath); // catalog.path without {name} pattern -> always refers to a single catalog
397
+
398
+ if (!catalog.path.includes(NAME)) {
399
+ // Validate that sourcePaths doesn't use {name} pattern either
400
+ const invalidSource = include.find(path => path.includes(NAME));
401
+
402
+ if (invalidSource !== undefined) {
403
+ 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.`);
404
+ } // catalog name is the last directory of catalog.path.
405
+ // If the last part is {locale}, then catalog doesn't have an explicit name
406
+
407
+
408
+ const name = function () {
409
+ const _name = catalog.path.split(PATHSEP).slice(-1)[0];
410
+ return _name !== LOCALE ? _name : null;
411
+ }();
412
+
413
+ catalogs.push(new Catalog({
414
+ name,
415
+ path: normalizeRelativePath(catalog.path),
416
+ include,
417
+ exclude
418
+ }, config));
419
+ return;
420
+ }
421
+
422
+ const patterns = include.map(path => path.replace(NAME_REPLACE_RE, "*"));
423
+
424
+ const candidates = _glob.default.sync(patterns.length > 1 ? `{${patterns.join(",")}}` : patterns[0], {
425
+ ignore: exclude,
426
+ mark: true
427
+ });
428
+
429
+ candidates.forEach(catalogDir => {
430
+ const name = _path.default.basename(catalogDir);
431
+
432
+ catalogs.push(new Catalog({
433
+ name,
434
+ path: normalizeRelativePath(catalog.path.replace(NAME_REPLACE_RE, name)),
435
+ include: include.map(path => path.replace(NAME_REPLACE_RE, name)),
436
+ exclude: exclude.map(path => path.replace(NAME_REPLACE_RE, name))
437
+ }, config));
438
+ });
439
+ });
440
+ return catalogs;
441
+ }
442
+
443
+ function getCatalogForFile(file, catalogs) {
444
+ for (const catalog of catalogs) {
445
+ const catalogFile = `${catalog.path}${catalog.format.catalogExtension}`;
446
+ const catalogGlob = catalogFile.replace(LOCALE_REPLACE_RE, "*");
447
+
448
+ const match = _micromatch.default.capture(normalizeRelativePath(_path.default.relative(catalog.config.rootDir, catalogGlob)), normalizeRelativePath(file));
449
+
450
+ if (match) {
451
+ return {
452
+ locale: match[0],
453
+ catalog
454
+ };
455
+ }
456
+ }
457
+
458
+ return null;
459
+ }
460
+ /**
461
+ * Create catalog for merged messages.
462
+ */
463
+
464
+
465
+ function getCatalogForMerge(config) {
466
+ const catalogConfig = config;
467
+
468
+ if (catalogConfig.catalogsMergePath.endsWith(PATHSEP)) {
469
+ const extension = (0, _formats.default)(config.format).catalogExtension;
470
+ const correctPath = catalogConfig.catalogsMergePath.slice(0, -1);
471
+ const examplePath = correctPath.replace(LOCALE_REPLACE_RE, // Show example using one of configured locales (if any)
472
+ (config.locales || [])[0] || "en") + extension;
473
+ throw new Error( // prettier-ignore
474
+ `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}".`);
475
+ } // catalog name is the last directory of catalogPath.
476
+ // If the last part is {locale}, then catalog doesn't have an explicit name
477
+
478
+
479
+ const name = function () {
480
+ const _name = _path.default.basename(normalizeRelativePath(catalogConfig.catalogsMergePath));
481
+
482
+ return _name !== LOCALE ? _name : null;
483
+ }();
484
+
485
+ const catalog = new Catalog({
486
+ name,
487
+ path: normalizeRelativePath(catalogConfig.catalogsMergePath),
488
+ include: [],
489
+ exclude: []
490
+ }, config);
491
+ return catalog;
492
+ }
493
+ /**
494
+ * Merge origins and extractedComments for messages found in different places. All other attributes
495
+ * should be the same (raise an error if defaults are different).
496
+ */
497
+
498
+
499
+ function mergeOriginsAndExtractedComments(msgId, prev, next) {
500
+ if (prev.defaults !== next.defaults) {
501
+ 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}`);
502
+ }
503
+
504
+ return { ...next,
505
+ extractedComments: R.concat(prev.extractedComments, next.extractedComments),
506
+ origin: R.concat(prev.origin, next.origin)
507
+ };
508
+ }
509
+ /**
510
+ * Ensure that value is always array. If not, turn it into an array of one element.
511
+ */
512
+
513
+
514
+ const ensureArray = value => {
515
+ if (value == null) return [];
516
+ return Array.isArray(value) ? value : [value];
517
+ };
518
+ /**
519
+ * Remove ./ at the beginning: ./relative => relative
520
+ * relative => relative
521
+ * Preserve directories: ./relative/ => relative/
522
+ * Preserve absolute paths: /absolute/path => /absolute/path
523
+ */
524
+
525
+
526
+ function normalizeRelativePath(sourcePath) {
527
+ if (_path.default.isAbsolute(sourcePath)) {
528
+ // absolute path
529
+ return (0, _normalizePath.default)(sourcePath, false);
530
+ }
531
+
532
+ const isDir = _fsExtra.default.existsSync(sourcePath) && _fsExtra.default.lstatSync(sourcePath).isDirectory();
533
+
534
+ return (0, _normalizePath.default)(_path.default.relative(process.cwd(), sourcePath), false) + (isDir ? "/" : "");
535
+ }
536
+
537
+ const cleanObsolete = R.filter(message => !message.obsolete);
538
+ exports.cleanObsolete = cleanObsolete;
539
+
540
+ function order(by) {
541
+ return {
542
+ messageId: orderByMessageId,
543
+ origin: orderByOrigin
544
+ }[by];
545
+ }
546
+ /**
547
+ * Object keys are in the same order as they were created
548
+ * https://stackoverflow.com/a/31102605/1535540
549
+ */
550
+
551
+
552
+ function orderByMessageId(messages) {
553
+ const orderedMessages = {};
554
+ Object.keys(messages).sort().forEach(function (key) {
555
+ orderedMessages[key] = messages[key];
556
+ });
557
+ return orderedMessages;
558
+ }
559
+
560
+ function orderByOrigin(messages) {
561
+ function getFirstOrigin(messageKey) {
562
+ const sortedOrigins = messages[messageKey].origin.sort((a, b) => {
563
+ if (a[0] < b[0]) return -1;
564
+ if (a[0] > b[0]) return 1;
565
+ return 0;
566
+ });
567
+ return sortedOrigins[0];
568
+ }
569
+
570
+ return Object.keys(messages).sort(function (a, b) {
571
+ const [aFile, aLineNumber] = getFirstOrigin(a);
572
+ const [bFile, bLineNumber] = getFirstOrigin(b);
573
+ if (aFile < bFile) return -1;
574
+ if (aFile > bFile) return 1;
575
+ if (aLineNumber < bLineNumber) return -1;
576
+ if (aLineNumber > bLineNumber) return 1;
577
+ return 0;
578
+ }).reduce((acc, key) => {
579
+ acc[key] = messages[key];
580
+ return acc;
581
+ }, {});
582
+ }
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createCompiledCatalog = createCompiledCatalog;
7
+ exports.compile = compile;
8
+
9
+ var t = _interopRequireWildcard(require("@babel/types"));
10
+
11
+ var _generator = _interopRequireDefault(require("@babel/generator"));
12
+
13
+ var _compile = require("@lingui/core/compile");
14
+
15
+ var _pseudoLocalize = _interopRequireDefault(require("./pseudoLocalize"));
16
+
17
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
+
19
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
20
+
21
+ 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; }
22
+
23
+ function createCompiledCatalog(locale, messages, options) {
24
+ const {
25
+ strict = false,
26
+ namespace = "cjs",
27
+ pseudoLocale,
28
+ compilerBabelOptions = {}
29
+ } = options;
30
+ const shouldPseudolocalize = locale === pseudoLocale;
31
+ const compiledMessages = Object.keys(messages).reduce((obj, key) => {
32
+ const value = messages[key]; // If the current ID's value is a context object, create a nested
33
+ // expression, and assign the current ID to that expression
34
+
35
+ if (typeof value === "object") {
36
+ obj[key] = Object.keys(value).reduce((obj, contextKey) => {
37
+ obj[contextKey] = compile(value[contextKey], shouldPseudolocalize);
38
+ return obj;
39
+ }, {});
40
+ return obj;
41
+ } // Don't use `key` as a fallback translation in strict mode.
42
+
43
+
44
+ const translation = messages[key] || (!strict ? key : "");
45
+ obj[key] = compile(translation, shouldPseudolocalize);
46
+ return obj;
47
+ }, {});
48
+ const ast = buildExportStatement( //build JSON.parse(<compiledMessages>) statement
49
+ t.callExpression(t.memberExpression(t.identifier('JSON'), t.identifier('parse')), [t.stringLiteral(JSON.stringify(compiledMessages))]), namespace);
50
+ const code = (0, _generator.default)(ast, {
51
+ minified: true,
52
+ jsescOption: {
53
+ minimal: true
54
+ },
55
+ ...compilerBabelOptions
56
+ }).code;
57
+ return "/*eslint-disable*/" + code;
58
+ }
59
+
60
+ function buildExportStatement(expression, namespace) {
61
+ if (namespace === "es" || namespace === "ts") {
62
+ // export const messages = { message: "Translation" }
63
+ return t.exportNamedDeclaration(t.variableDeclaration("const", [t.variableDeclarator(t.identifier("messages"), expression)]));
64
+ } else {
65
+ let exportExpression = null;
66
+ const matches = namespace.match(/^(window|global)\.([^.\s]+)$/);
67
+
68
+ if (namespace === "cjs") {
69
+ // module.exports.messages = { message: "Translation" }
70
+ exportExpression = t.memberExpression(t.identifier("module"), t.identifier("exports"));
71
+ } else if (matches) {
72
+ // window.i18nMessages = { messages: { message: "Translation" }}
73
+ exportExpression = t.memberExpression(t.identifier(matches[1]), t.identifier(matches[2]));
74
+ } else {
75
+ throw new Error(`Invalid namespace param: "${namespace}"`);
76
+ }
77
+
78
+ return t.expressionStatement(t.assignmentExpression("=", exportExpression, t.objectExpression([t.objectProperty(t.identifier("messages"), expression)])));
79
+ }
80
+ }
81
+ /**
82
+ * Compile string message into AST tree. Message format is parsed/compiled into
83
+ * JS arrays, which are handled in client.
84
+ */
85
+
86
+
87
+ function compile(message, shouldPseudolocalize = false) {
88
+ return (0, _compile.compileMessage)(message, value => shouldPseudolocalize ? (0, _pseudoLocalize.default)(value) : value);
89
+ }