@lingui/cli 3.10.2 → 3.12.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.
- package/api/catalog.js +5 -6
- package/api/compile.js +4 -1
- package/api/extractors/babel.js +4 -2
- package/api/extractors/index.js +12 -1
- package/api/extractors/typescript.js +4 -2
- package/api/formats/po-gettext.js +8 -3
- package/lingui-compile.js +22 -7
- package/lingui-extract-template.js +3 -2
- package/lingui-extract.js +41 -7
- package/package.json +4 -3
- package/services/translationIO.js +304 -0
package/api/catalog.js
CHANGED
|
@@ -146,8 +146,8 @@ var Catalog = /*#__PURE__*/function () {
|
|
|
146
146
|
paths.forEach(function (filename) {
|
|
147
147
|
return (0, _extractors.default)(filename, tmpDir, {
|
|
148
148
|
verbose: options.verbose,
|
|
149
|
+
configPath: options.configPath,
|
|
149
150
|
babelOptions: _this.config.extractBabelOptions,
|
|
150
|
-
// @ts-ignore
|
|
151
151
|
extractors: options.extractors,
|
|
152
152
|
projectType: options.projectType
|
|
153
153
|
});
|
|
@@ -255,7 +255,7 @@ var Catalog = /*#__PURE__*/function () {
|
|
|
255
255
|
};
|
|
256
256
|
|
|
257
257
|
var getMultipleFallbacks = function getMultipleFallbacks(locale) {
|
|
258
|
-
var fL = fallbackLocales[locale]; // some probably the fallback will be undefined, so just search by locale
|
|
258
|
+
var fL = fallbackLocales && fallbackLocales[locale]; // some probably the fallback will be undefined, so just search by locale
|
|
259
259
|
|
|
260
260
|
if (!fL) return null;
|
|
261
261
|
|
|
@@ -284,7 +284,7 @@ var Catalog = /*#__PURE__*/function () {
|
|
|
284
284
|
return (// Get translation in target locale
|
|
285
285
|
getTranslation(locale) || // We search in fallbackLocales as dependent of each locale
|
|
286
286
|
getMultipleFallbacks(locale) || // Get translation in fallbackLocales.default (if any)
|
|
287
|
-
fallbackLocales.default && getTranslation(fallbackLocales.default) || // Get message default
|
|
287
|
+
fallbackLocales && fallbackLocales.default && getTranslation(fallbackLocales.default) || // Get message default
|
|
288
288
|
catalogs[locale][key].defaults || // If sourceLocale is either target locale of fallback one, use key
|
|
289
289
|
sourceLocale && sourceLocale === locale && key || sourceLocale && fallbackLocales.default && sourceLocale === fallbackLocales.default && key || // Otherwise no translation is available
|
|
290
290
|
undefined
|
|
@@ -333,8 +333,7 @@ var Catalog = /*#__PURE__*/function () {
|
|
|
333
333
|
locale: undefined
|
|
334
334
|
});
|
|
335
335
|
|
|
336
|
-
|
|
337
|
-
poFormat.write(filename, messages, options);
|
|
336
|
+
this.format.write(filename, messages, options);
|
|
338
337
|
}
|
|
339
338
|
}, {
|
|
340
339
|
key: "writeCompiled",
|
|
@@ -481,7 +480,7 @@ function getCatalogs(config) {
|
|
|
481
480
|
return path.replace(NAME, "*");
|
|
482
481
|
});
|
|
483
482
|
|
|
484
|
-
var candidates = _glob.default.sync(patterns.length > 1 ? "{".concat(patterns.join(",")) : patterns[0], {
|
|
483
|
+
var candidates = _glob.default.sync(patterns.length > 1 ? "{".concat(patterns.join(","), "}") : patterns[0], {
|
|
485
484
|
ignore: exclude,
|
|
486
485
|
mark: true
|
|
487
486
|
});
|
package/api/compile.js
CHANGED
|
@@ -26,6 +26,8 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
|
|
|
26
26
|
|
|
27
27
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
28
28
|
|
|
29
|
+
var INVALID_OBJECT_KEY_REGEX = /^(\d+[a-zA-Z]|[a-zA-Z]+\d)(\d|[a-zA-Z])*/;
|
|
30
|
+
|
|
29
31
|
function createCompiledCatalog(locale, messages, options) {
|
|
30
32
|
var _options$strict = options.strict,
|
|
31
33
|
strict = _options$strict === void 0 ? false : _options$strict,
|
|
@@ -133,7 +135,8 @@ function processTokens(tokens) {
|
|
|
133
135
|
|
|
134
136
|
token.cases.forEach(function (item) {
|
|
135
137
|
var inlineTokens = processTokens(item.tokens);
|
|
136
|
-
formatProps.push(t.objectProperty(
|
|
138
|
+
formatProps.push(t.objectProperty( // if starts with number must be wrapped with quotes
|
|
139
|
+
INVALID_OBJECT_KEY_REGEX.test(item.key) ? t.stringLiteral(item.key) : t.identifier(item.key), isString(inlineTokens) ? t.stringLiteral(inlineTokens) : inlineTokens));
|
|
137
140
|
});
|
|
138
141
|
var params = [t.stringLiteral(token.arg), t.stringLiteral(token.type), t.objectExpression(formatProps)];
|
|
139
142
|
return t.arrayExpression(params);
|
package/api/extractors/babel.js
CHANGED
|
@@ -34,7 +34,8 @@ var extractor = {
|
|
|
34
34
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
35
35
|
|
|
36
36
|
var _options$babelOptions = options.babelOptions,
|
|
37
|
-
_babelOptions = _options$babelOptions === void 0 ? {} : _options$babelOptions
|
|
37
|
+
_babelOptions = _options$babelOptions === void 0 ? {} : _options$babelOptions,
|
|
38
|
+
configPath = options.configPath;
|
|
38
39
|
|
|
39
40
|
var _babelOptions$plugins = _babelOptions.plugins,
|
|
40
41
|
plugins = _babelOptions$plugins === void 0 ? [] : _babelOptions$plugins,
|
|
@@ -50,7 +51,8 @@ var extractor = {
|
|
|
50
51
|
// https://github.com/lingui/js-lingui/issues/952
|
|
51
52
|
envName: "development",
|
|
52
53
|
plugins: ["macros", [_babelPluginExtractMessages.default, {
|
|
53
|
-
localeDir: localeDir
|
|
54
|
+
localeDir: localeDir,
|
|
55
|
+
configPath: configPath
|
|
54
56
|
}]].concat((0, _toConsumableArray2.default)(plugins))
|
|
55
57
|
}));
|
|
56
58
|
}
|
package/api/extractors/index.js
CHANGED
|
@@ -17,7 +17,18 @@ function extract(filename, targetPath, options) {
|
|
|
17
17
|
var _options$extractors;
|
|
18
18
|
|
|
19
19
|
var extractorsToExtract = (_options$extractors = options.extractors) !== null && _options$extractors !== void 0 ? _options$extractors : DEFAULT_EXTRACTORS;
|
|
20
|
-
return extractorsToExtract.some(function (
|
|
20
|
+
return extractorsToExtract.some(function (e) {
|
|
21
|
+
var ext = e;
|
|
22
|
+
|
|
23
|
+
if (typeof e === "string") {
|
|
24
|
+
// in case of the user using require.resolve in their extractors, we require that module
|
|
25
|
+
ext = require(e);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (ext.default) {
|
|
29
|
+
ext = ext.default;
|
|
30
|
+
}
|
|
31
|
+
|
|
21
32
|
if (!ext.match(filename)) return false;
|
|
22
33
|
var spinner;
|
|
23
34
|
if (options.verbose) spinner = (0, _ora.default)().start(filename);
|
|
@@ -56,9 +56,11 @@ var extractor = {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
var _options$babelOptions = options.babelOptions,
|
|
59
|
-
babelOptions = _options$babelOptions === void 0 ? {} : _options$babelOptions
|
|
59
|
+
babelOptions = _options$babelOptions === void 0 ? {} : _options$babelOptions,
|
|
60
|
+
configPath = options.configPath;
|
|
60
61
|
var plugins = ["macros", [_babelPluginExtractMessages.default, {
|
|
61
|
-
localeDir: localeDir
|
|
62
|
+
localeDir: localeDir,
|
|
63
|
+
configPath: configPath
|
|
62
64
|
}]].concat((0, _toConsumableArray2.default)(babelOptions.plugins || []));
|
|
63
65
|
|
|
64
66
|
if (isTsx) {
|
|
@@ -196,9 +196,14 @@ var deserialize = R.map(R.applySpec({
|
|
|
196
196
|
*/
|
|
197
197
|
|
|
198
198
|
var getPluralCases = function getPluralCases(lang) {
|
|
199
|
-
|
|
199
|
+
// If users uses locale with underscore or slash, es-ES, es_ES, gettextplural is "es" not es-ES.
|
|
200
|
+
var _lang$split = lang.split(/[-_]/g),
|
|
201
|
+
_lang$split2 = (0, _slicedToArray2.default)(_lang$split, 1),
|
|
202
|
+
correctLang = _lang$split2[0];
|
|
203
|
+
|
|
204
|
+
var gettextPluralsInfo = _plurals.default[correctLang];
|
|
200
205
|
return gettextPluralsInfo === null || gettextPluralsInfo === void 0 ? void 0 : gettextPluralsInfo.examples.map(function (pluralCase) {
|
|
201
|
-
return (0, _pluralsCldr.default)(
|
|
206
|
+
return (0, _pluralsCldr.default)(correctLang, pluralCase.sample);
|
|
202
207
|
});
|
|
203
208
|
};
|
|
204
209
|
|
|
@@ -213,7 +218,7 @@ var convertPluralsToICU = function convertPluralsToICU(items, lang) {
|
|
|
213
218
|
var translationCount = getTranslationCount(item);
|
|
214
219
|
var messageKey = getMessageKey(item); // Messages without multiple translations (= plural cases) need no further processing.
|
|
215
220
|
|
|
216
|
-
if (translationCount <= 1) {
|
|
221
|
+
if (translationCount <= 1 && !item.msgid_plural) {
|
|
217
222
|
return;
|
|
218
223
|
} // msgid_plural must be set, but its actual value is not important.
|
|
219
224
|
|
package/lingui-compile.js
CHANGED
|
@@ -28,6 +28,8 @@ var _compile = require("./api/compile");
|
|
|
28
28
|
|
|
29
29
|
var _help = require("./api/help");
|
|
30
30
|
|
|
31
|
+
var _api = require("./api");
|
|
32
|
+
|
|
31
33
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
32
34
|
|
|
33
35
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
@@ -110,7 +112,7 @@ function command(config, options) {
|
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
if (require.main === module) {
|
|
113
|
-
_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").on("--help", function () {
|
|
115
|
+
_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 () {
|
|
114
116
|
console.log("\n Examples:\n");
|
|
115
117
|
console.log(" # Compile translations and use defaults or message IDs for missing translations");
|
|
116
118
|
console.log(" $ ".concat((0, _help.helpRun)("compile")));
|
|
@@ -139,6 +141,18 @@ if (require.main === module) {
|
|
|
139
141
|
namespace: _commander.default.namespace // we want this to be undefined if user does not specify so default can be used
|
|
140
142
|
|
|
141
143
|
});
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
var debounceTimer;
|
|
147
|
+
|
|
148
|
+
var dispatchCompile = function dispatchCompile() {
|
|
149
|
+
// Skip debouncing if not enabled
|
|
150
|
+
if (!_commander.default.debounce) return compile(); // CLear the previous timer if there is any, and schedule the next
|
|
151
|
+
|
|
152
|
+
debounceTimer && clearTimeout(debounceTimer);
|
|
153
|
+
debounceTimer = setTimeout(function () {
|
|
154
|
+
return compile();
|
|
155
|
+
}, _commander.default.debounce);
|
|
142
156
|
}; // Check if Watch Mode is enabled
|
|
143
157
|
|
|
144
158
|
|
|
@@ -150,9 +164,10 @@ if (require.main === module) {
|
|
|
150
164
|
var _catalogs = (0, _catalog.getCatalogs)(config);
|
|
151
165
|
|
|
152
166
|
var paths = [];
|
|
167
|
+
var catalogExtension = (0, _api.getFormat)(config.format).catalogExtension;
|
|
153
168
|
config.locales.forEach(function (locale) {
|
|
154
169
|
_catalogs.forEach(function (catalog) {
|
|
155
|
-
paths.push("".concat(catalog.path.replace(LOCALE, locale).replace(NAME, "*")
|
|
170
|
+
paths.push("".concat(catalog.path.replace(LOCALE, locale).replace(NAME, "*")).concat(catalogExtension));
|
|
156
171
|
});
|
|
157
172
|
});
|
|
158
173
|
|
|
@@ -162,14 +177,14 @@ if (require.main === module) {
|
|
|
162
177
|
|
|
163
178
|
var onReady = function onReady() {
|
|
164
179
|
console.info(_chalk.default.green.bold("Watcher is ready!"));
|
|
165
|
-
watcher.on(
|
|
166
|
-
return
|
|
167
|
-
}).on(
|
|
168
|
-
return
|
|
180
|
+
watcher.on("add", function () {
|
|
181
|
+
return dispatchCompile();
|
|
182
|
+
}).on("change", function () {
|
|
183
|
+
return dispatchCompile();
|
|
169
184
|
});
|
|
170
185
|
};
|
|
171
186
|
|
|
172
|
-
watcher.on(
|
|
187
|
+
watcher.on("ready", function () {
|
|
173
188
|
return onReady();
|
|
174
189
|
});
|
|
175
190
|
} else {
|
|
@@ -61,10 +61,11 @@ if (require.main === module) {
|
|
|
61
61
|
_commander.default.option("--config <path>", "Path to the config file").option("--verbose", "Verbose output").parse(process.argv);
|
|
62
62
|
|
|
63
63
|
var config = (0, _conf.getConfig)({
|
|
64
|
-
configPath: _commander.default.config
|
|
64
|
+
configPath: _commander.default.config || process.env.LINGUI_CONFIG
|
|
65
65
|
});
|
|
66
66
|
var result = command(config, {
|
|
67
|
-
verbose: _commander.default.verbose || false
|
|
67
|
+
verbose: _commander.default.verbose || false,
|
|
68
|
+
configPath: _commander.default.config || process.env.LINGUI_CONFIG
|
|
68
69
|
});
|
|
69
70
|
if (!result) process.exit(1);
|
|
70
71
|
}
|
package/lingui-extract.js
CHANGED
|
@@ -9,6 +9,10 @@ exports.default = command;
|
|
|
9
9
|
|
|
10
10
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
11
11
|
|
|
12
|
+
var _interopRequireWildcard2 = _interopRequireDefault(require("@babel/runtime/helpers/interopRequireWildcard"));
|
|
13
|
+
|
|
14
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
15
|
+
|
|
12
16
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
13
17
|
|
|
14
18
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
@@ -68,13 +72,24 @@ function command(config, options) {
|
|
|
68
72
|
if (!options.watch) {
|
|
69
73
|
console.error("(use \"".concat(_chalk.default.yellow((0, _help.helpRun)("extract")), "\" to update catalogs with new messages)"));
|
|
70
74
|
console.error("(use \"".concat(_chalk.default.yellow((0, _help.helpRun)("compile")), "\" to compile catalogs for production)"));
|
|
75
|
+
} // If service key is present in configuration, synchronize with cloud translation platform
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if ((0, _typeof2.default)(config.service) === 'object' && config.service.name && config.service.name.length) {
|
|
79
|
+
Promise.resolve("./services/".concat(config.service.name)).then(function (s) {
|
|
80
|
+
return (0, _interopRequireWildcard2.default)(require(s));
|
|
81
|
+
}).then(function (module) {
|
|
82
|
+
return module.default(config, options);
|
|
83
|
+
}).catch(function (err) {
|
|
84
|
+
return console.error("Can't load service module ".concat(config.service.name), err);
|
|
85
|
+
});
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
return true;
|
|
74
89
|
}
|
|
75
90
|
|
|
76
91
|
if (require.main === module) {
|
|
77
|
-
_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("--verbose", "Verbose output").option("--convert-from <format>", "Convert from previous format of message catalogs").option("--watch", "Enables Watch Mode") // Obsolete options
|
|
92
|
+
_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
|
|
78
93
|
.option("--babelOptions", "Babel options passed to transform/extract plugins").option("--format <format>", "Format of message catalogs").parse(process.argv);
|
|
79
94
|
|
|
80
95
|
var config = (0, _conf.getConfig)({
|
|
@@ -124,10 +139,29 @@ if (require.main === module) {
|
|
|
124
139
|
clean: _commander.default.watch ? false : _commander.default.clean || false,
|
|
125
140
|
overwrite: _commander.default.watch || _commander.default.overwrite || false,
|
|
126
141
|
locale: _commander.default.locale,
|
|
142
|
+
configPath: _commander.default.config || process.env.LINGUI_CONFIG,
|
|
127
143
|
watch: _commander.default.watch || false,
|
|
128
144
|
files: (filePath === null || filePath === void 0 ? void 0 : filePath.length) ? filePath : undefined,
|
|
129
145
|
prevFormat: prevFormat
|
|
130
146
|
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
var changedPaths = new Set();
|
|
150
|
+
var debounceTimer;
|
|
151
|
+
|
|
152
|
+
var dispatchExtract = function dispatchExtract(filePath) {
|
|
153
|
+
// Skip debouncing if not enabled
|
|
154
|
+
if (!_commander.default.debounce) return extract(filePath);
|
|
155
|
+
filePath === null || filePath === void 0 ? void 0 : filePath.forEach(function (path) {
|
|
156
|
+
return changedPaths.add(path);
|
|
157
|
+
}); // CLear the previous timer if there is any, and schedule the next
|
|
158
|
+
|
|
159
|
+
debounceTimer && clearTimeout(debounceTimer);
|
|
160
|
+
debounceTimer = setTimeout(function () {
|
|
161
|
+
var filePath = (0, _toConsumableArray2.default)(changedPaths);
|
|
162
|
+
changedPaths.clear();
|
|
163
|
+
extract(filePath);
|
|
164
|
+
}, _commander.default.debounce);
|
|
131
165
|
}; // Check if Watch Mode is enabled
|
|
132
166
|
|
|
133
167
|
|
|
@@ -142,20 +176,20 @@ if (require.main === module) {
|
|
|
142
176
|
});
|
|
143
177
|
|
|
144
178
|
var watcher = _chokidar.default.watch(paths, {
|
|
145
|
-
ignored: [
|
|
179
|
+
ignored: ["/(^|[/\\])../"].concat(ignored),
|
|
146
180
|
persistent: true
|
|
147
181
|
});
|
|
148
182
|
|
|
149
183
|
var onReady = function onReady() {
|
|
150
184
|
console.info(_chalk.default.green.bold("Watcher is ready!"));
|
|
151
|
-
watcher.on(
|
|
152
|
-
return
|
|
153
|
-
}).on(
|
|
154
|
-
return
|
|
185
|
+
watcher.on("add", function (path) {
|
|
186
|
+
return dispatchExtract([path]);
|
|
187
|
+
}).on("change", function (path) {
|
|
188
|
+
return dispatchExtract([path]);
|
|
155
189
|
});
|
|
156
190
|
};
|
|
157
191
|
|
|
158
|
-
watcher.on(
|
|
192
|
+
watcher.on("ready", function () {
|
|
159
193
|
return onReady();
|
|
160
194
|
});
|
|
161
195
|
} else if (_commander.default.args) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingui/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.1",
|
|
4
4
|
"description": "CLI for working wit message catalogs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"LICENSE",
|
|
30
30
|
"README.md",
|
|
31
31
|
"api",
|
|
32
|
+
"services",
|
|
32
33
|
"lingui.js",
|
|
33
34
|
"lingui-*.js"
|
|
34
35
|
],
|
|
@@ -38,8 +39,8 @@
|
|
|
38
39
|
"@babel/plugin-syntax-jsx": "^7.10.4",
|
|
39
40
|
"@babel/runtime": "^7.11.2",
|
|
40
41
|
"@babel/types": "^7.11.5",
|
|
41
|
-
"@lingui/babel-plugin-extract-messages": "^3.
|
|
42
|
-
"@lingui/conf": "^3.
|
|
42
|
+
"@lingui/babel-plugin-extract-messages": "^3.12.1",
|
|
43
|
+
"@lingui/conf": "^3.12.1",
|
|
43
44
|
"babel-plugin-macros": "^3.0.1",
|
|
44
45
|
"bcp-47": "^1.0.7",
|
|
45
46
|
"chalk": "^4.1.0",
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = syncProcess;
|
|
9
|
+
|
|
10
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
11
|
+
|
|
12
|
+
var _path = require("path");
|
|
13
|
+
|
|
14
|
+
var _pofile = _interopRequireDefault(require("pofile"));
|
|
15
|
+
|
|
16
|
+
var _https = _interopRequireDefault(require("https"));
|
|
17
|
+
|
|
18
|
+
var _glob = _interopRequireDefault(require("glob"));
|
|
19
|
+
|
|
20
|
+
var _dateFns = require("date-fns");
|
|
21
|
+
|
|
22
|
+
var getCreateHeaders = function getCreateHeaders(language) {
|
|
23
|
+
return {
|
|
24
|
+
"POT-Creation-Date": (0, _dateFns.format)(new Date(), "yyyy-MM-dd HH:mmxxxx"),
|
|
25
|
+
"MIME-Version": "1.0",
|
|
26
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
27
|
+
"Content-Transfer-Encoding": "8bit",
|
|
28
|
+
"X-Generator": "@lingui/cli",
|
|
29
|
+
Language: language
|
|
30
|
+
};
|
|
31
|
+
}; // Main sync method, call "Init" or "Sync" depending on the project context
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
function syncProcess(config, options) {
|
|
35
|
+
if (config.format != 'po') {
|
|
36
|
+
console.error("\n----------\nTranslation.io service is only compatible with the \"po\" format. Please update your Lingui configuration accordingly.\n----------");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
var successCallback = function successCallback(project) {
|
|
41
|
+
console.log("\n----------\nProject successfully synchronized. Please use this URL to translate: ".concat(project.url, "\n----------"));
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
var failCallback = function failCallback(errors) {
|
|
45
|
+
console.error("\n----------\nSynchronization with Translation.io failed: ".concat(errors.join(', '), "\n----------"));
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
init(config, options, successCallback, function (errors) {
|
|
49
|
+
if (errors.length && errors[0] === 'This project has already been initialized.') {
|
|
50
|
+
sync(config, options, successCallback, failCallback);
|
|
51
|
+
} else {
|
|
52
|
+
failCallback(errors);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
} // Initialize project with source and existing translations (only first time!)
|
|
56
|
+
// Cf. https://translation.io/docs/create-library#initialization
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
function init(config, options, successCallback, failCallback) {
|
|
60
|
+
var sourceLocale = config.sourceLocale || 'en';
|
|
61
|
+
var targetLocales = config.locales.filter(function (value) {
|
|
62
|
+
return value != sourceLocale;
|
|
63
|
+
});
|
|
64
|
+
var paths = poPathsPerLocale(config);
|
|
65
|
+
var segments = {};
|
|
66
|
+
targetLocales.forEach(function (targetLocale) {
|
|
67
|
+
segments[targetLocale] = [];
|
|
68
|
+
}); // Create segments from source locale PO items
|
|
69
|
+
|
|
70
|
+
paths[sourceLocale].forEach(function (path) {
|
|
71
|
+
var raw = _fs.default.readFileSync(path).toString();
|
|
72
|
+
|
|
73
|
+
var po = _pofile.default.parse(raw);
|
|
74
|
+
|
|
75
|
+
po.items.filter(function (item) {
|
|
76
|
+
return !item['obsolete'];
|
|
77
|
+
}).forEach(function (item) {
|
|
78
|
+
targetLocales.forEach(function (targetLocale) {
|
|
79
|
+
var newSegment = createSegmentFromPoItem(item);
|
|
80
|
+
segments[targetLocale].push(newSegment);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}); // Add translations to segments from target locale PO items
|
|
84
|
+
|
|
85
|
+
targetLocales.forEach(function (targetLocale) {
|
|
86
|
+
paths[targetLocale].forEach(function (path) {
|
|
87
|
+
var raw = _fs.default.readFileSync(path).toString();
|
|
88
|
+
|
|
89
|
+
var po = _pofile.default.parse(raw);
|
|
90
|
+
|
|
91
|
+
po.items.filter(function (item) {
|
|
92
|
+
return !item['obsolete'];
|
|
93
|
+
}).forEach(function (item, index) {
|
|
94
|
+
segments[targetLocale][index].target = item.msgstr[0];
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
var request = {
|
|
99
|
+
"client": "lingui",
|
|
100
|
+
"version": require('@lingui/core/package.json').version,
|
|
101
|
+
"source_language": sourceLocale,
|
|
102
|
+
"target_languages": targetLocales,
|
|
103
|
+
"segments": segments
|
|
104
|
+
};
|
|
105
|
+
postTio("init", request, config.service.apiKey, function (response) {
|
|
106
|
+
if (response.errors) {
|
|
107
|
+
failCallback(response.errors);
|
|
108
|
+
} else {
|
|
109
|
+
saveSegmentsToTargetPos(config, paths, response.segments);
|
|
110
|
+
successCallback(response.project);
|
|
111
|
+
}
|
|
112
|
+
}, function (error) {
|
|
113
|
+
console.error("\n----------\nSynchronization with Translation.io failed: ".concat(error, "\n----------"));
|
|
114
|
+
});
|
|
115
|
+
} // Send all source text from PO to Translation.io and create new PO based on received translations
|
|
116
|
+
// Cf. https://translation.io/docs/create-library#synchronization
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
function sync(config, options, successCallback, failCallback) {
|
|
120
|
+
var sourceLocale = config.sourceLocale || 'en';
|
|
121
|
+
var targetLocales = config.locales.filter(function (value) {
|
|
122
|
+
return value != sourceLocale;
|
|
123
|
+
});
|
|
124
|
+
var paths = poPathsPerLocale(config);
|
|
125
|
+
var segments = []; // Create segments with correct source
|
|
126
|
+
|
|
127
|
+
paths[sourceLocale].forEach(function (path) {
|
|
128
|
+
var raw = _fs.default.readFileSync(path).toString();
|
|
129
|
+
|
|
130
|
+
var po = _pofile.default.parse(raw);
|
|
131
|
+
|
|
132
|
+
po.items.filter(function (item) {
|
|
133
|
+
return !item['obsolete'];
|
|
134
|
+
}).forEach(function (item) {
|
|
135
|
+
var newSegment = createSegmentFromPoItem(item);
|
|
136
|
+
segments.push(newSegment);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
var request = {
|
|
140
|
+
"client": "lingui",
|
|
141
|
+
"version": require('@lingui/core/package.json').version,
|
|
142
|
+
"source_language": sourceLocale,
|
|
143
|
+
"target_languages": targetLocales,
|
|
144
|
+
"segments": segments
|
|
145
|
+
}; // Sync and then remove unused segments (not present in the local application) from Translation.io
|
|
146
|
+
|
|
147
|
+
if (options.clean) {
|
|
148
|
+
request['purge'] = true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
postTio("sync", request, config.service.apiKey, function (response) {
|
|
152
|
+
if (response.errors) {
|
|
153
|
+
failCallback(response.errors);
|
|
154
|
+
} else {
|
|
155
|
+
saveSegmentsToTargetPos(config, paths, response.segments);
|
|
156
|
+
successCallback(response.project);
|
|
157
|
+
}
|
|
158
|
+
}, function (error) {
|
|
159
|
+
console.error("\n----------\nSynchronization with Translation.io failed: ".concat(error, "\n----------"));
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function createSegmentFromPoItem(item) {
|
|
164
|
+
var itemHasId = item.msgid != item.msgstr[0] && item.msgstr[0].length;
|
|
165
|
+
var segment = {
|
|
166
|
+
type: 'source',
|
|
167
|
+
// No way to edit text for source language (inside code), so not using "key" here
|
|
168
|
+
source: itemHasId ? item.msgstr[0] : item.msgid,
|
|
169
|
+
// msgstr may be empty if --overwrite is used and no ID is used
|
|
170
|
+
context: '',
|
|
171
|
+
references: [],
|
|
172
|
+
comment: ''
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
if (itemHasId) {
|
|
176
|
+
segment.context = item.msgid;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (item.references.length) {
|
|
180
|
+
segment.references = item.references;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (item.extractedComments.length) {
|
|
184
|
+
segment.comment = item.extractedComments.join(' | ');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return segment;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function createPoItemFromSegment(segment) {
|
|
191
|
+
var item = new _pofile.default.Item();
|
|
192
|
+
item.msgid = segment.context ? segment.context : segment.source;
|
|
193
|
+
item.msgstr = [segment.target];
|
|
194
|
+
item.references = segment.references && segment.references.length ? segment.references : [];
|
|
195
|
+
item.extractedComments = segment.comment ? segment.comment.split(' | ') : [];
|
|
196
|
+
return item;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function saveSegmentsToTargetPos(config, paths, segmentsPerLocale) {
|
|
200
|
+
var NAME = "{name}";
|
|
201
|
+
var LOCALE = "{locale}";
|
|
202
|
+
Object.keys(segmentsPerLocale).forEach(function (targetLocale) {
|
|
203
|
+
// Remove existing target POs and JS for this target locale
|
|
204
|
+
paths[targetLocale].forEach(function (path) {
|
|
205
|
+
var jsPath = path.replace(/\.po?$/, "") + ".js";
|
|
206
|
+
var dirPath = (0, _path.dirname)(path); // Remove PO, JS and empty dir
|
|
207
|
+
|
|
208
|
+
if (_fs.default.existsSync(path)) {
|
|
209
|
+
_fs.default.unlinkSync(path);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (_fs.default.existsSync(jsPath)) {
|
|
213
|
+
_fs.default.unlinkSync(jsPath);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (_fs.default.existsSync(dirPath) && _fs.default.readdirSync(dirPath).length === 0) {
|
|
217
|
+
_fs.default.rmdirSync(dirPath);
|
|
218
|
+
}
|
|
219
|
+
}); // Find target path (ignoring {name})
|
|
220
|
+
|
|
221
|
+
var localePath = "".concat(config.catalogs[0].path.replace(LOCALE, targetLocale).replace(NAME, ''), ".po");
|
|
222
|
+
var segments = segmentsPerLocale[targetLocale];
|
|
223
|
+
var po = new _pofile.default();
|
|
224
|
+
po.headers = getCreateHeaders(targetLocale);
|
|
225
|
+
var items = [];
|
|
226
|
+
segments.forEach(function (segment) {
|
|
227
|
+
var item = createPoItemFromSegment(segment);
|
|
228
|
+
items.push(item);
|
|
229
|
+
}); // Sort items by messageId
|
|
230
|
+
|
|
231
|
+
po.items = items.sort(function (a, b) {
|
|
232
|
+
if (a.msgid < b.msgid) {
|
|
233
|
+
return -1;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (a.msgid > b.msgid) {
|
|
237
|
+
return 1;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return 0;
|
|
241
|
+
}); // Check that localePath directory exists and save PO file
|
|
242
|
+
|
|
243
|
+
_fs.default.promises.mkdir((0, _path.dirname)(localePath), {
|
|
244
|
+
recursive: true
|
|
245
|
+
}).then(function () {
|
|
246
|
+
po.save(localePath, function (err) {
|
|
247
|
+
if (err) {
|
|
248
|
+
console.error('Error while saving target PO files:');
|
|
249
|
+
console.error(err);
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function poPathsPerLocale(config) {
|
|
258
|
+
var NAME = "{name}";
|
|
259
|
+
var LOCALE = "{locale}";
|
|
260
|
+
var paths = [];
|
|
261
|
+
config.locales.forEach(function (locale) {
|
|
262
|
+
paths[locale] = [];
|
|
263
|
+
config.catalogs.forEach(function (catalog) {
|
|
264
|
+
var path = "".concat(catalog.path.replace(LOCALE, locale).replace(NAME, "*"), ".po"); // If {name} is present (replaced by *), list all the existing POs
|
|
265
|
+
|
|
266
|
+
if (path.includes('*')) {
|
|
267
|
+
paths[locale] = paths[locale].concat(_glob.default.sync(path));
|
|
268
|
+
} else {
|
|
269
|
+
paths[locale].push(path);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
return paths;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function postTio(action, request, apiKey, successCallback, failCallback) {
|
|
277
|
+
var jsonRequest = JSON.stringify(request);
|
|
278
|
+
var options = {
|
|
279
|
+
hostname: 'translation.io',
|
|
280
|
+
path: '/api/v1/segments/' + action + '.json?api_key=' + apiKey,
|
|
281
|
+
method: 'POST',
|
|
282
|
+
headers: {
|
|
283
|
+
'Content-Type': 'application/json'
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
var req = _https.default.request(options, function (res) {
|
|
288
|
+
res.setEncoding('utf8');
|
|
289
|
+
var body = "";
|
|
290
|
+
res.on('data', function (chunk) {
|
|
291
|
+
body = body.concat(chunk);
|
|
292
|
+
});
|
|
293
|
+
res.on('end', function () {
|
|
294
|
+
var response = JSON.parse(body);
|
|
295
|
+
successCallback(response);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
req.on('error', function (e) {
|
|
300
|
+
failCallback(e);
|
|
301
|
+
});
|
|
302
|
+
req.write(jsonRequest);
|
|
303
|
+
req.end();
|
|
304
|
+
}
|