@lingui/cli 4.0.0-next.4 → 4.0.0-next.5

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 (68) hide show
  1. package/dist/api/catalog/extractFromFiles.js +64 -0
  2. package/dist/api/catalog/getCatalogs.js +137 -0
  3. package/dist/api/catalog/getTranslationsForCatalog.js +68 -0
  4. package/dist/api/catalog/mergeCatalog.js +86 -0
  5. package/dist/api/catalog.js +286 -0
  6. package/dist/api/compile.js +115 -0
  7. package/dist/api/extractors/babel.js +158 -0
  8. package/dist/api/extractors/index.js +44 -0
  9. package/dist/api/extractors/typescript.js +15 -0
  10. package/dist/api/formats/formatterWrapper.js +48 -0
  11. package/dist/api/formats/index.js +95 -0
  12. package/dist/api/help.js +41 -0
  13. package/dist/api/index.js +31 -0
  14. package/dist/api/pseudoLocalize.js +60 -0
  15. package/dist/api/rethrownError.js +16 -0
  16. package/dist/api/stats.js +73 -0
  17. package/{build → dist}/api/types.js +2 -3
  18. package/dist/api/utils.js +117 -0
  19. package/dist/extract-experimental/buildExternalizeFilter.js +83 -0
  20. package/dist/extract-experimental/bundleSource.js +127 -0
  21. package/dist/extract-experimental/constants.js +16 -0
  22. package/dist/extract-experimental/getEntryPoints.js +20 -0
  23. package/dist/extract-experimental/getExperimentalCatalogs.js +30 -0
  24. package/dist/extract-experimental/resolveCatalogPath.js +34 -0
  25. package/dist/extract-experimental/resolveTemplatePath.js +19 -0
  26. package/dist/extract-experimental/writeCatalogs.js +54 -0
  27. package/dist/lingui-compile.js +158 -0
  28. package/dist/lingui-extract-experimental.js +113 -0
  29. package/dist/lingui-extract-template.js +52 -0
  30. package/dist/lingui-extract.js +192 -0
  31. package/dist/lingui.js +8 -0
  32. package/dist/services/translationIO.js +261 -0
  33. package/dist/tests.js +137 -0
  34. package/package.json +19 -13
  35. package/build/LICENSE +0 -21
  36. package/build/api/catalog/extractFromFiles.js +0 -45
  37. package/build/api/catalog/getCatalogs.js +0 -138
  38. package/build/api/catalog/getTranslationsForCatalog.js +0 -77
  39. package/build/api/catalog/mergeCatalog.js +0 -44
  40. package/build/api/catalog.js +0 -245
  41. package/build/api/compile.js +0 -72
  42. package/build/api/extractors/babel.js +0 -92
  43. package/build/api/extractors/index.js +0 -36
  44. package/build/api/extractors/typescript.js +0 -14
  45. package/build/api/formats/formatterWrapper.js +0 -45
  46. package/build/api/formats/index.js +0 -57
  47. package/build/api/generateMessageId.js +0 -12
  48. package/build/api/help.js +0 -42
  49. package/build/api/index.js +0 -58
  50. package/build/api/pseudoLocalize.js +0 -60
  51. package/build/api/rethrownError.js +0 -14
  52. package/build/api/stats.js +0 -40
  53. package/build/api/utils.js +0 -117
  54. package/build/extract-experimental/buildExternalizeFilter.js +0 -39
  55. package/build/extract-experimental/bundleSource.js +0 -69
  56. package/build/extract-experimental/constants.js +0 -10
  57. package/build/extract-experimental/getEntryPoints.js +0 -14
  58. package/build/extract-experimental/getExperimentalCatalogs.js +0 -28
  59. package/build/extract-experimental/resolveCatalogPath.js +0 -23
  60. package/build/extract-experimental/resolveTemplatePath.js +0 -17
  61. package/build/extract-experimental/writeCatalogs.js +0 -59
  62. package/build/lingui-compile.js +0 -156
  63. package/build/lingui-extract-experimental.js +0 -103
  64. package/build/lingui-extract-template.js +0 -46
  65. package/build/lingui-extract.js +0 -143
  66. package/build/lingui.js +0 -6
  67. package/build/services/translationIO.js +0 -266
  68. package/build/tests.js +0 -133
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "extractFromFiles", {
6
+ enumerable: true,
7
+ get: ()=>extractFromFiles
8
+ });
9
+ const _extractors = /*#__PURE__*/ _interopRequireDefault(require("../extractors"));
10
+ const _path = /*#__PURE__*/ _interopRequireDefault(require("path"));
11
+ const _chalk = /*#__PURE__*/ _interopRequireDefault(require("chalk"));
12
+ const _utils = require("../utils");
13
+ function _interopRequireDefault(obj) {
14
+ return obj && obj.__esModule ? obj : {
15
+ default: obj
16
+ };
17
+ }
18
+ async function extractFromFiles(paths, config) {
19
+ const messages = {};
20
+ let catalogSuccess = true;
21
+ for (let filename of paths){
22
+ const fileSuccess = await (0, _extractors.default)(filename, (next)=>{
23
+ if (!messages[next.id]) {
24
+ messages[next.id] = {
25
+ message: next.message,
26
+ context: next.context,
27
+ comments: [],
28
+ origin: []
29
+ };
30
+ }
31
+ const prev = messages[next.id];
32
+ // there might be a case when filename was not mapped from sourcemaps
33
+ const filename = next.origin[0] ? _path.default.relative(config.rootDir, next.origin[0]).replace(/\\/g, "/") : "";
34
+ const origin = [
35
+ filename,
36
+ next.origin[1]
37
+ ];
38
+ if (prev.message && next.message && prev.message !== next.message) {
39
+ throw new Error(`Encountered different default translations for message ${_chalk.default.yellow(next.id)}` + `\n${_chalk.default.yellow((0, _utils.prettyOrigin)(prev.origin))} ${prev.message}` + `\n${_chalk.default.yellow((0, _utils.prettyOrigin)([
40
+ origin
41
+ ]))} ${next.message}`);
42
+ }
43
+ messages[next.id] = {
44
+ ...prev,
45
+ comments: next.comment ? [
46
+ ...prev.comments,
47
+ next.comment
48
+ ] : prev.comments,
49
+ origin: [
50
+ ...prev.origin,
51
+ [
52
+ filename,
53
+ next.origin[1]
54
+ ]
55
+ ]
56
+ };
57
+ }, config, {
58
+ extractors: config.extractors
59
+ });
60
+ catalogSuccess &&= fileSuccess;
61
+ }
62
+ if (!catalogSuccess) return undefined;
63
+ return messages;
64
+ }
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ getCatalogs: ()=>getCatalogs,
13
+ getCatalogForMerge: ()=>getCatalogForMerge,
14
+ getCatalogForFile: ()=>getCatalogForFile
15
+ });
16
+ const _glob = /*#__PURE__*/ _interopRequireDefault(require("glob"));
17
+ const _path = /*#__PURE__*/ _interopRequireDefault(require("path"));
18
+ const _catalog = require("../catalog");
19
+ const _utils = require("../utils");
20
+ const _micromatch = /*#__PURE__*/ _interopRequireDefault(require("micromatch"));
21
+ const _formats = require("../formats");
22
+ const _getExperimentalCatalogs = require("../../extract-experimental/getExperimentalCatalogs");
23
+ function _interopRequireDefault(obj) {
24
+ return obj && obj.__esModule ? obj : {
25
+ default: obj
26
+ };
27
+ }
28
+ const NAME_PH = "{name}";
29
+ const LOCALE_PH = "{locale}";
30
+ async function getCatalogs(config) {
31
+ var _config_experimental, _config_experimental_extractor;
32
+ const catalogsConfig = config.catalogs;
33
+ const catalogs = [];
34
+ const format = await (0, _formats.getFormat)(config.format, config.formatOptions, config.sourceLocale);
35
+ catalogsConfig.forEach((catalog)=>{
36
+ validateCatalogPath(catalog.path, format.getCatalogExtension());
37
+ const include = ensureArray(catalog.include).map(_utils.normalizeRelativePath);
38
+ const exclude = ensureArray(catalog.exclude).map(_utils.normalizeRelativePath);
39
+ // catalog.path without {name} pattern -> always refers to a single catalog
40
+ if (!catalog.path.includes(NAME_PH)) {
41
+ // Validate that sourcePaths doesn't use {name} pattern either
42
+ const invalidSource = include.find((path)=>path.includes(NAME_PH));
43
+ if (invalidSource !== undefined) {
44
+ 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.`);
45
+ }
46
+ catalogs.push(new _catalog.Catalog({
47
+ name: getCatalogName(catalog.path),
48
+ path: (0, _utils.normalizeRelativePath)(catalog.path),
49
+ include,
50
+ exclude,
51
+ format
52
+ }, config));
53
+ return;
54
+ }
55
+ const patterns = include.map((path)=>(0, _utils.replacePlaceholders)(path, {
56
+ name: "*"
57
+ }));
58
+ const candidates = _glob.default.sync(patterns.length > 1 ? `{${patterns.join(",")}}` : patterns[0], {
59
+ ignore: exclude,
60
+ mark: true
61
+ });
62
+ candidates.forEach((catalogDir)=>{
63
+ const name = _path.default.basename(catalogDir);
64
+ catalogs.push(new _catalog.Catalog({
65
+ name,
66
+ path: (0, _utils.normalizeRelativePath)((0, _utils.replacePlaceholders)(catalog.path, {
67
+ name
68
+ })),
69
+ include: include.map((path)=>(0, _utils.replacePlaceholders)(path, {
70
+ name
71
+ })),
72
+ exclude: exclude.map((path)=>(0, _utils.replacePlaceholders)(path, {
73
+ name
74
+ })),
75
+ format
76
+ }, config));
77
+ });
78
+ });
79
+ if ((_config_experimental = config.experimental) === null || _config_experimental === void 0 ? void 0 : (_config_experimental_extractor = _config_experimental.extractor) === null || _config_experimental_extractor === void 0 ? void 0 : _config_experimental_extractor.entries.length) {
80
+ catalogs.push(...await (0, _getExperimentalCatalogs.getExperimentalCatalogs)(config));
81
+ }
82
+ return catalogs;
83
+ }
84
+ /**
85
+ * Ensure that value is always array. If not, turn it into an array of one element.
86
+ */ const ensureArray = (value)=>{
87
+ if (value == null) return [];
88
+ return Array.isArray(value) ? value : [
89
+ value
90
+ ];
91
+ };
92
+ async function getCatalogForMerge(config) {
93
+ const format = await (0, _formats.getFormat)(config.format, config.formatOptions, config.sourceLocale);
94
+ validateCatalogPath(config.catalogsMergePath, format.getCatalogExtension());
95
+ return new _catalog.Catalog({
96
+ name: getCatalogName(config.catalogsMergePath),
97
+ path: (0, _utils.normalizeRelativePath)(config.catalogsMergePath),
98
+ include: [],
99
+ exclude: [],
100
+ format
101
+ }, config);
102
+ }
103
+ function getCatalogForFile(file, catalogs) {
104
+ for (const catalog of catalogs){
105
+ const catalogFile = `${catalog.path}${catalog.format.getCatalogExtension()}`;
106
+ const catalogGlob = (0, _utils.replacePlaceholders)(catalogFile, {
107
+ locale: "*"
108
+ });
109
+ const match = _micromatch.default.capture((0, _utils.normalizeRelativePath)(_path.default.relative(catalog.config.rootDir, catalogGlob)), (0, _utils.normalizeRelativePath)(file));
110
+ if (match) {
111
+ return {
112
+ locale: match[0],
113
+ catalog
114
+ };
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+ /**
120
+ * Validate that `catalogPath` doesn't end with trailing slash
121
+ */ function validateCatalogPath(path, extension) {
122
+ if (!path.endsWith(_utils.PATHSEP)) {
123
+ return;
124
+ }
125
+ const correctPath = path.slice(0, -1);
126
+ const examplePath = (0, _utils.replacePlaceholders)(correctPath, {
127
+ locale: "en"
128
+ }) + extension;
129
+ throw new Error(// prettier-ignore
130
+ `Remove trailing slash from "${path}". Catalog path isn't a directory,` + ` but translation file without extension. For example, catalog path "${correctPath}"` + ` results in translation file "${examplePath}".`);
131
+ }
132
+ function getCatalogName(filePath) {
133
+ // catalog name is the last directory of catalogPath.
134
+ // If the last part is {locale}, then catalog doesn't have an explicit name
135
+ const _name = _path.default.basename((0, _utils.normalizeRelativePath)(filePath));
136
+ return _name !== LOCALE_PH ? _name : null;
137
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "getTranslationsForCatalog", {
6
+ enumerable: true,
7
+ get: ()=>getTranslationsForCatalog
8
+ });
9
+ async function getTranslationsForCatalog(catalog, locale, options) {
10
+ const catalogs = await catalog.readAll();
11
+ const template = await catalog.readTemplate() || {};
12
+ const sourceLocaleCatalog = catalogs[options.sourceLocale] || {};
13
+ const input = {
14
+ ...template,
15
+ ...sourceLocaleCatalog,
16
+ ...catalogs[locale]
17
+ };
18
+ return Object.keys(input).reduce((acc, key)=>{
19
+ acc[key] = getTranslation(catalogs, input[key], locale, key, options);
20
+ return acc;
21
+ }, {});
22
+ }
23
+ function sourceLocaleFallback(catalog, key) {
24
+ if (!(catalog === null || catalog === void 0 ? void 0 : catalog[key])) {
25
+ return null;
26
+ }
27
+ return catalog[key].translation || catalog[key].message;
28
+ }
29
+ function getTranslation(catalogs, msg, locale, key, options) {
30
+ const { fallbackLocales , sourceLocale , onMissing } = options;
31
+ const getTranslation = (_locale)=>{
32
+ var _localeCatalog_key;
33
+ const localeCatalog = catalogs[_locale];
34
+ return localeCatalog === null || localeCatalog === void 0 ? void 0 : (_localeCatalog_key = localeCatalog[key]) === null || _localeCatalog_key === void 0 ? void 0 : _localeCatalog_key.translation;
35
+ };
36
+ const getMultipleFallbacks = (_locale)=>{
37
+ const fL = fallbackLocales && (fallbackLocales === null || fallbackLocales === void 0 ? void 0 : fallbackLocales[_locale]);
38
+ // some probably the fallback will be undefined, so just search by locale
39
+ if (!fL) return null;
40
+ if (Array.isArray(fL)) {
41
+ for (const fallbackLocale of fL){
42
+ if (catalogs[fallbackLocale] && getTranslation(fallbackLocale)) {
43
+ return getTranslation(fallbackLocale);
44
+ }
45
+ }
46
+ } else {
47
+ return getTranslation(fL);
48
+ }
49
+ };
50
+ // target locale -> fallback locales -> fallback locales default ->
51
+ // ** (following fallbacks would emit `missing` warning) **
52
+ // -> source locale translation -> source locale message
53
+ // -> template message
54
+ // ** last resort **
55
+ // -> id
56
+ let translation = // Get translation in target locale
57
+ getTranslation(locale) || // We search in fallbackLocales as dependent of each locale
58
+ getMultipleFallbacks(locale) || // Get translation in fallbackLocales.default (if any)
59
+ (fallbackLocales === null || fallbackLocales === void 0 ? void 0 : fallbackLocales.default) && getTranslation(fallbackLocales.default) || sourceLocale && sourceLocale === locale && sourceLocaleFallback(catalogs[sourceLocale], key);
60
+ if (!translation) {
61
+ onMissing && onMissing({
62
+ id: key,
63
+ source: msg.message || sourceLocaleFallback(catalogs[sourceLocale], key)
64
+ });
65
+ }
66
+ return translation || sourceLocale && sourceLocaleFallback(catalogs[sourceLocale], key) || // take from template
67
+ msg.message || key;
68
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "mergeCatalog", {
6
+ enumerable: true,
7
+ get: ()=>mergeCatalog
8
+ });
9
+ const _ramda = /*#__PURE__*/ _interopRequireWildcard(require("ramda"));
10
+ function _getRequireWildcardCache(nodeInterop) {
11
+ if (typeof WeakMap !== "function") return null;
12
+ var cacheBabelInterop = new WeakMap();
13
+ var cacheNodeInterop = new WeakMap();
14
+ return (_getRequireWildcardCache = function(nodeInterop) {
15
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
16
+ })(nodeInterop);
17
+ }
18
+ function _interopRequireWildcard(obj, nodeInterop) {
19
+ if (!nodeInterop && obj && obj.__esModule) {
20
+ return obj;
21
+ }
22
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
23
+ return {
24
+ default: obj
25
+ };
26
+ }
27
+ var cache = _getRequireWildcardCache(nodeInterop);
28
+ if (cache && cache.has(obj)) {
29
+ return cache.get(obj);
30
+ }
31
+ var newObj = {};
32
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
33
+ for(var key in obj){
34
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
35
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
36
+ if (desc && (desc.get || desc.set)) {
37
+ Object.defineProperty(newObj, key, desc);
38
+ } else {
39
+ newObj[key] = obj[key];
40
+ }
41
+ }
42
+ }
43
+ newObj.default = obj;
44
+ if (cache) {
45
+ cache.set(obj, newObj);
46
+ }
47
+ return newObj;
48
+ }
49
+ function mergeCatalog(prevCatalog, nextCatalog, forSourceLocale, options) {
50
+ const nextKeys = Object.keys(nextCatalog);
51
+ const prevKeys = _ramda.keys(prevCatalog).map(String);
52
+ const newKeys = _ramda.difference(nextKeys, prevKeys);
53
+ const mergeKeys = _ramda.intersection(nextKeys, prevKeys);
54
+ const obsoleteKeys = _ramda.difference(prevKeys, nextKeys);
55
+ // Initialize new catalog with new keys
56
+ const newMessages = _ramda.mapObjIndexed((message, key)=>({
57
+ translation: forSourceLocale ? message.message || key : "",
58
+ ...message
59
+ }), _ramda.pick(newKeys, nextCatalog));
60
+ // Merge translations from previous catalog
61
+ const mergedMessages = mergeKeys.map((key)=>{
62
+ const updateFromDefaults = forSourceLocale && (prevCatalog[key].translation === prevCatalog[key].message || options.overwrite);
63
+ const translation = updateFromDefaults ? nextCatalog[key].message || key : prevCatalog[key].translation;
64
+ return {
65
+ [key]: {
66
+ translation,
67
+ ..._ramda.omit([
68
+ "obsolete, translation"
69
+ ], nextCatalog[key])
70
+ }
71
+ };
72
+ });
73
+ // Mark all remaining translations as obsolete
74
+ // Only if *options.files* is not provided
75
+ const obsoleteMessages = obsoleteKeys.map((key)=>({
76
+ [key]: {
77
+ ...prevCatalog[key],
78
+ obsolete: !options.files
79
+ }
80
+ }));
81
+ return _ramda.mergeAll([
82
+ newMessages,
83
+ ...mergedMessages,
84
+ ...obsoleteMessages
85
+ ]);
86
+ }
@@ -0,0 +1,286 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ Catalog: ()=>Catalog,
13
+ cleanObsolete: ()=>cleanObsolete,
14
+ order: ()=>order,
15
+ orderByMessage: ()=>orderByMessage
16
+ });
17
+ const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs"));
18
+ const _path = /*#__PURE__*/ _interopRequireDefault(require("path"));
19
+ const _ramda = /*#__PURE__*/ _interopRequireWildcard(require("ramda"));
20
+ const _glob = /*#__PURE__*/ _interopRequireDefault(require("glob"));
21
+ const _normalizePath = /*#__PURE__*/ _interopRequireDefault(require("normalize-path"));
22
+ const _getTranslationsForCatalog = require("./catalog/getTranslationsForCatalog");
23
+ const _mergeCatalog = require("./catalog/mergeCatalog");
24
+ const _extractFromFiles = require("./catalog/extractFromFiles");
25
+ const _utils = require("./utils");
26
+ function _interopRequireDefault(obj) {
27
+ return obj && obj.__esModule ? obj : {
28
+ default: obj
29
+ };
30
+ }
31
+ function _getRequireWildcardCache(nodeInterop) {
32
+ if (typeof WeakMap !== "function") return null;
33
+ var cacheBabelInterop = new WeakMap();
34
+ var cacheNodeInterop = new WeakMap();
35
+ return (_getRequireWildcardCache = function(nodeInterop) {
36
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
37
+ })(nodeInterop);
38
+ }
39
+ function _interopRequireWildcard(obj, nodeInterop) {
40
+ if (!nodeInterop && obj && obj.__esModule) {
41
+ return obj;
42
+ }
43
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
44
+ return {
45
+ default: obj
46
+ };
47
+ }
48
+ var cache = _getRequireWildcardCache(nodeInterop);
49
+ if (cache && cache.has(obj)) {
50
+ return cache.get(obj);
51
+ }
52
+ var newObj = {};
53
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
54
+ for(var key in obj){
55
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
56
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
57
+ if (desc && (desc.get || desc.set)) {
58
+ Object.defineProperty(newObj, key, desc);
59
+ } else {
60
+ newObj[key] = obj[key];
61
+ }
62
+ }
63
+ }
64
+ newObj.default = obj;
65
+ if (cache) {
66
+ cache.set(obj, newObj);
67
+ }
68
+ return newObj;
69
+ }
70
+ const LOCALE = "{locale}";
71
+ const LOCALE_SUFFIX_RE = /\{locale\}.*$/;
72
+ class Catalog {
73
+ config;
74
+ name;
75
+ path;
76
+ include;
77
+ exclude;
78
+ format;
79
+ templateFile;
80
+ constructor({ name , path , include , templatePath , format , exclude =[] }, config){
81
+ this.config = config;
82
+ this.name = name;
83
+ this.path = (0, _utils.normalizeRelativePath)(path);
84
+ this.include = include.map(_utils.normalizeRelativePath);
85
+ this.exclude = [
86
+ this.localeDir,
87
+ ...exclude.map(_utils.normalizeRelativePath)
88
+ ];
89
+ this.format = format;
90
+ this.templateFile = templatePath || getTemplatePath(this.format.getTemplateExtension(), this.path);
91
+ }
92
+ async make(options) {
93
+ const nextCatalog = await this.collect({
94
+ files: options.files
95
+ });
96
+ if (!nextCatalog) return false;
97
+ const prevCatalogs = await this.readAll();
98
+ const catalogs = this.merge(prevCatalogs, nextCatalog, {
99
+ overwrite: options.overwrite,
100
+ files: options.files
101
+ });
102
+ // Map over all locales and post-process each catalog
103
+ const cleanAndSort = _ramda.map(_ramda.pipe(// Clean obsolete messages
104
+ options.clean ? cleanObsolete : _ramda.identity, // Sort messages
105
+ order(options.orderBy)));
106
+ const sortedCatalogs = cleanAndSort(catalogs);
107
+ const locales = options.locale ? [
108
+ options.locale
109
+ ] : this.locales;
110
+ await Promise.all(locales.map((locale)=>this.write(locale, sortedCatalogs[locale])));
111
+ return sortedCatalogs;
112
+ }
113
+ async makeTemplate(options) {
114
+ const catalog = await this.collect({
115
+ files: options.files
116
+ });
117
+ if (!catalog) return false;
118
+ const sorted = order(options.orderBy)(catalog);
119
+ await this.writeTemplate(sorted);
120
+ return sorted;
121
+ }
122
+ /**
123
+ * Collect messages from source paths. Return a raw message catalog as JSON.
124
+ */ async collect(options = {}) {
125
+ let paths = this.sourcePaths;
126
+ if (options.files) {
127
+ options.files = options.files.map((p)=>(0, _normalizePath.default)(p, false));
128
+ const regex = new RegExp(options.files.join("|"), "i");
129
+ paths = paths.filter((path)=>regex.test(path));
130
+ }
131
+ return await (0, _extractFromFiles.extractFromFiles)(paths, this.config);
132
+ }
133
+ /*
134
+ *
135
+ * prevCatalogs - map of message catalogs in all available languages with translations
136
+ * nextCatalog - language-agnostic catalog with collected messages
137
+ *
138
+ * Note: if a catalog in prevCatalogs is null it means the language is available, but
139
+ * no previous catalog was generated (usually first run).
140
+ *
141
+ * Orthogonal use-cases
142
+ * --------------------
143
+ *
144
+ * Message IDs:
145
+ * - auto-generated IDs: message is used as a key, `defaults` is not set
146
+ * - custom IDs: message is used as `defaults`, custom ID as a key
147
+ *
148
+ * Source locale (defined by `sourceLocale` in config):
149
+ * - catalog for `sourceLocale`: initially, `translation` is prefilled with `defaults`
150
+ * (for custom IDs) or `key` (for auto-generated IDs)
151
+ * - all other languages: translation is kept empty
152
+ */ merge(prevCatalogs, nextCatalog, options) {
153
+ return _ramda.mapObjIndexed((prevCatalog, locale)=>{
154
+ return (0, _mergeCatalog.mergeCatalog)(prevCatalog, nextCatalog, this.config.sourceLocale === locale, options);
155
+ }, prevCatalogs);
156
+ }
157
+ async getTranslations(locale, options) {
158
+ return await (0, _getTranslationsForCatalog.getTranslationsForCatalog)(this, locale, options);
159
+ }
160
+ async write(locale, messages) {
161
+ const filename = (0, _utils.replacePlaceholders)(this.path, {
162
+ locale
163
+ }) + this.format.getCatalogExtension();
164
+ const created = !_fs.default.existsSync(filename);
165
+ await this.format.write(filename, messages, locale);
166
+ return [
167
+ created,
168
+ filename
169
+ ];
170
+ }
171
+ async writeTemplate(messages) {
172
+ const filename = this.templateFile;
173
+ await this.format.write(filename, messages, undefined);
174
+ }
175
+ async writeCompiled(locale, compiledCatalog, namespace) {
176
+ let ext;
177
+ if (namespace === "es") {
178
+ ext = "mjs";
179
+ } else if (namespace === "ts") {
180
+ ext = "ts";
181
+ } else {
182
+ ext = "js";
183
+ }
184
+ const filename = `${(0, _utils.replacePlaceholders)(this.path, {
185
+ locale
186
+ })}.${ext}`;
187
+ await (0, _utils.writeFile)(filename, compiledCatalog);
188
+ return filename;
189
+ }
190
+ async read(locale) {
191
+ const filename = (0, _utils.replacePlaceholders)(this.path, {
192
+ locale
193
+ }) + this.format.getCatalogExtension();
194
+ return await this.format.read(filename, locale);
195
+ }
196
+ async readAll() {
197
+ const res = {};
198
+ await Promise.all(this.locales.map(async (locale)=>res[locale] = await this.read(locale)));
199
+ // statement above will save locales in object in undetermined order
200
+ // resort here to have keys order the same as in locales definition
201
+ return this.locales.reduce((acc, locale)=>{
202
+ acc[locale] = res[locale];
203
+ return acc;
204
+ }, {});
205
+ }
206
+ async readTemplate() {
207
+ const filename = this.templateFile;
208
+ return await this.format.read(filename, undefined);
209
+ }
210
+ get sourcePaths() {
211
+ const includeGlobs = this.include.map((includePath)=>{
212
+ const isDir = (0, _utils.isDirectory)(includePath);
213
+ /**
214
+ * glob library results from absolute patterns such as /foo/* are mounted onto the root setting using path.join.
215
+ * On windows, this will by default result in /foo/* matching C:\foo\bar.txt.
216
+ */ return isDir ? (0, _normalizePath.default)(_path.default.resolve(process.cwd(), includePath === "/" ? "" : includePath, "**/*.*")) : includePath;
217
+ });
218
+ const patterns = includeGlobs.length > 1 ? `{${includeGlobs.join(",")}}` : includeGlobs[0];
219
+ return _glob.default.sync(patterns, {
220
+ ignore: this.exclude,
221
+ mark: true
222
+ });
223
+ }
224
+ get localeDir() {
225
+ const localePatternIndex = this.path.indexOf(LOCALE);
226
+ if (localePatternIndex === -1) {
227
+ throw Error(`Invalid catalog path: ${LOCALE} variable is missing`);
228
+ }
229
+ return this.path.substr(0, localePatternIndex);
230
+ }
231
+ get locales() {
232
+ return this.config.locales;
233
+ }
234
+ }
235
+ function getTemplatePath(ext, path) {
236
+ return path.replace(LOCALE_SUFFIX_RE, "messages" + ext);
237
+ }
238
+ const cleanObsolete = _ramda.filter((message)=>!message.obsolete);
239
+ function order(by) {
240
+ return ({
241
+ messageId: orderByMessageId,
242
+ message: orderByMessage,
243
+ origin: orderByOrigin
244
+ })[by];
245
+ }
246
+ /**
247
+ * Object keys are in the same order as they were created
248
+ * https://stackoverflow.com/a/31102605/1535540
249
+ */ function orderByMessageId(messages) {
250
+ return Object.keys(messages).sort().reduce((acc, key)=>{
251
+ acc[key] = messages[key];
252
+ return acc;
253
+ }, {});
254
+ }
255
+ function orderByOrigin(messages) {
256
+ function getFirstOrigin(messageKey) {
257
+ const sortedOrigins = messages[messageKey].origin.sort((a, b)=>{
258
+ if (a[0] < b[0]) return -1;
259
+ if (a[0] > b[0]) return 1;
260
+ return 0;
261
+ });
262
+ return sortedOrigins[0];
263
+ }
264
+ return Object.keys(messages).sort((a, b)=>{
265
+ const [aFile, aLineNumber] = getFirstOrigin(a);
266
+ const [bFile, bLineNumber] = getFirstOrigin(b);
267
+ if (aFile < bFile) return -1;
268
+ if (aFile > bFile) return 1;
269
+ if (aLineNumber < bLineNumber) return -1;
270
+ if (aLineNumber > bLineNumber) return 1;
271
+ return 0;
272
+ }).reduce((acc, key)=>{
273
+ acc[key] = messages[key];
274
+ return acc;
275
+ }, {});
276
+ }
277
+ function orderByMessage(messages) {
278
+ return Object.keys(messages).sort((a, b)=>{
279
+ const aMsg = messages[a].message || "";
280
+ const bMsg = messages[b].message || "";
281
+ return aMsg.localeCompare(bMsg);
282
+ }).reduce((acc, key)=>{
283
+ acc[key] = messages[key];
284
+ return acc;
285
+ }, {});
286
+ }