locize-cli 7.11.0 → 7.12.2
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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/bin/locize +9 -2
- package/download.js +108 -22
- package/getProjectStats.js +40 -0
- package/getRemoteNamespace.js +2 -2
- package/package.json +1 -1
- package/sync.js +78 -30
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
Project versioning adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
7
7
|
|
|
8
|
+
## [7.12.2](https://github.com/locize/locize-cli/compare/v7.12.1...v7.12.2) - 2022-07-12
|
|
9
|
+
|
|
10
|
+
- limit parallel downloads
|
|
11
|
+
|
|
12
|
+
## [7.12.1](https://github.com/locize/locize-cli/compare/v7.12.0...v7.12.1) - 2022-07-12
|
|
13
|
+
|
|
14
|
+
- limit parallel downloads
|
|
15
|
+
|
|
16
|
+
## [7.12.0](https://github.com/locize/locize-cli/compare/v7.11.0...v7.12.0) - 2022-06-16
|
|
17
|
+
|
|
18
|
+
- sync and download: introduce --unpublished flag
|
|
19
|
+
|
|
8
20
|
## [7.11.0](https://github.com/locize/locize-cli/compare/v7.10.1...v7.11.0) - 2022-06-13
|
|
9
21
|
|
|
10
22
|
- alpine build
|
package/README.md
CHANGED
|
@@ -91,7 +91,7 @@ locize download --project-id my-project-id-93e1-442a-ab35-24331fa294ba --ver lat
|
|
|
91
91
|
By using the sync command, you can keep your existing code setup and synchronize the translations with locize.
|
|
92
92
|
An example on how this could look like can be seen in [this tutorial](https://github.com/locize/react-tutorial#step-1---keep-existing-code-setup-but-synchronize-with-locize).
|
|
93
93
|
|
|
94
|
-
**⚠️ Since the remote source are the published translations, make sure the desired version is set to
|
|
94
|
+
**⚠️ Since the remote source are the published translations, make sure the desired version is set to auto publish mode. Alternatively use the `--unpublished true` argument (this will generate [private downloads costs](https://docs.locize.com/integration/api#fetch-filter-the-unpublished-namespace-resources)). ⚠️**
|
|
95
95
|
|
|
96
96
|
### Step 1: Go near to your translation files
|
|
97
97
|
|
package/bin/locize
CHANGED
|
@@ -238,6 +238,7 @@ program
|
|
|
238
238
|
.option('-P, --language-folder-prefix <prefix>', 'This will be added as a local folder name prefix in front of the language.', '')
|
|
239
239
|
.option('-m, --path-mask <mask>', 'This will define the folder and file structure; do not add a file extension (default: {{language}}/{{namespace}})', `{{language}}${path.sep}{{namespace}}`)
|
|
240
240
|
.option('-c, --clean <true|false>', 'Removes all local files by removing the whole folder (default: false)', 'false')
|
|
241
|
+
.option('-up, --unpublished <true|false>', 'Downloads the current (unpublished) translations. This will generate private download costs (default: false)', 'false')
|
|
241
242
|
.option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${workingDirectory} or ${home})`)
|
|
242
243
|
.action((options) => {
|
|
243
244
|
try {
|
|
@@ -271,6 +272,8 @@ program
|
|
|
271
272
|
|
|
272
273
|
const clean = options.clean === 'true';
|
|
273
274
|
|
|
275
|
+
const unpublished = options.unpublished === 'true';
|
|
276
|
+
|
|
274
277
|
const languageFolderPrefix = options.languageFolderPrefix || '';
|
|
275
278
|
|
|
276
279
|
const pathMask = options.pathMask;
|
|
@@ -287,7 +290,8 @@ program
|
|
|
287
290
|
skipEmpty: skipEmpty,
|
|
288
291
|
clean: clean,
|
|
289
292
|
languageFolderPrefix: languageFolderPrefix,
|
|
290
|
-
pathMask: pathMask
|
|
293
|
+
pathMask: pathMask,
|
|
294
|
+
unpublished: unpublished
|
|
291
295
|
});
|
|
292
296
|
})
|
|
293
297
|
.on('--help', () => {
|
|
@@ -377,6 +381,7 @@ program
|
|
|
377
381
|
.option('-l, --language <lng>', 'The language that should be targeted')
|
|
378
382
|
.option('-n, --namespace <ns>', 'The namespace that should be targeted')
|
|
379
383
|
.option('-g, --get-path <url>', `Specify the get-path url that should be used (default: ${getPathUrl})`)
|
|
384
|
+
.option('-up, --unpublished <true|false>', 'Downloads the current (unpublished) translations. This will generate private download costs (default: false)', 'false')
|
|
380
385
|
.option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${workingDirectory} or ${home})`)
|
|
381
386
|
.action((options) => {
|
|
382
387
|
try {
|
|
@@ -424,6 +429,7 @@ program
|
|
|
424
429
|
const referenceLanguageOnly = options.referenceLanguageOnly === 'false' ? false : true;
|
|
425
430
|
const compareModificationTime = options.compareModificationTime === 'true';
|
|
426
431
|
const pathMask = options.pathMask;
|
|
432
|
+
const unpublished = options.unpublished === 'true';
|
|
427
433
|
|
|
428
434
|
sync({
|
|
429
435
|
apiPath: url.parse(getPath).protocol + '//' + url.parse(getPath).host,
|
|
@@ -444,7 +450,8 @@ program
|
|
|
444
450
|
language: language,
|
|
445
451
|
namespace: namespace,
|
|
446
452
|
dry: dry,
|
|
447
|
-
pathMask: pathMask
|
|
453
|
+
pathMask: pathMask,
|
|
454
|
+
unpublished: unpublished
|
|
448
455
|
});
|
|
449
456
|
})
|
|
450
457
|
.on('--help', () => {
|
package/download.js
CHANGED
|
@@ -10,6 +10,7 @@ const getRemoteNamespace = require('./getRemoteNamespace');
|
|
|
10
10
|
const getRemoteLanguages = require('./getRemoteLanguages');
|
|
11
11
|
const convertToDesiredFormat = require('./convertToDesiredFormat');
|
|
12
12
|
const formats = require('./formats');
|
|
13
|
+
const getProjectStats = require('./getProjectStats');
|
|
13
14
|
const reversedFileExtensionsMap = formats.reversedFileExtensionsMap;
|
|
14
15
|
|
|
15
16
|
function handleDownload(opt, url, err, res, downloads, cb) {
|
|
@@ -33,7 +34,7 @@ function handleDownload(opt, url, err, res, downloads, cb) {
|
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
async.
|
|
37
|
+
async.eachLimit(downloads, 20, (download, clb) => {
|
|
37
38
|
const splitted = download.key.split('/');
|
|
38
39
|
const version = splitted[download.isPrivate ? 2 : 1];
|
|
39
40
|
const lng = splitted[download.isPrivate ? 3 : 2];
|
|
@@ -92,6 +93,56 @@ function handleDownload(opt, url, err, res, downloads, cb) {
|
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
function handlePull(opt, toDownload, cb) {
|
|
97
|
+
const url = opt.apiPath + '/pull/' + opt.projectId + '/' + opt.version;
|
|
98
|
+
async.eachLimit(toDownload, 20, (download, clb) => {
|
|
99
|
+
const lng = download.language;
|
|
100
|
+
const namespace = download.namespace;
|
|
101
|
+
|
|
102
|
+
getRemoteNamespace(opt, lng, namespace, (err, ns, lastModified) => {
|
|
103
|
+
if (err) return clb(err);
|
|
104
|
+
|
|
105
|
+
if (opt.skipEmpty && Object.keys(flatten(ns)).length === 0) {
|
|
106
|
+
return clb(null);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
convertToDesiredFormat(opt, namespace, lng, ns, lastModified, (err, converted) => {
|
|
110
|
+
if (err) {
|
|
111
|
+
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '');
|
|
112
|
+
return clb(err);
|
|
113
|
+
}
|
|
114
|
+
var filledMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, lng).replace(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`, namespace) + reversedFileExtensionsMap[opt.format];
|
|
115
|
+
var mkdirPath;
|
|
116
|
+
if (filledMask.lastIndexOf(path.sep) > 0) {
|
|
117
|
+
mkdirPath = filledMask.substring(0, filledMask.lastIndexOf(path.sep));
|
|
118
|
+
}
|
|
119
|
+
if (!opt.language) {
|
|
120
|
+
if (mkdirPath) mkdirp.sync(path.join(opt.path, mkdirPath));
|
|
121
|
+
fs.writeFile(path.join(opt.path, filledMask), converted, clb);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (filledMask.indexOf(path.sep) > 0) filledMask = filledMask.replace(opt.languageFolderPrefix + lng, '');
|
|
126
|
+
const parentDir = path.dirname(path.join(opt.path, filledMask));
|
|
127
|
+
mkdirp.sync(parentDir);
|
|
128
|
+
fs.writeFile(path.join(opt.path, filledMask), converted, clb);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}, (err) => {
|
|
132
|
+
if (err) {
|
|
133
|
+
if (!cb) {
|
|
134
|
+
console.error(colors.red(err.message));
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
if (cb) cb(err);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (!cb) console.log(colors.green(`downloaded ${url} to ${opt.path}...`));
|
|
142
|
+
if (cb) cb(null);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
95
146
|
const handleError = (err, cb) => {
|
|
96
147
|
if (!cb && err) {
|
|
97
148
|
console.error(colors.red(err.message));
|
|
@@ -103,7 +154,7 @@ const handleError = (err, cb) => {
|
|
|
103
154
|
const download = (opt, cb) => {
|
|
104
155
|
opt.format = opt.format || 'json';
|
|
105
156
|
if (!reversedFileExtensionsMap[opt.format]) {
|
|
106
|
-
return handleError(new Error(`${opt.format} is not a valid format!`));
|
|
157
|
+
return handleError(new Error(`${opt.format} is not a valid format!`), cb);
|
|
107
158
|
}
|
|
108
159
|
|
|
109
160
|
if (opt.skipEmpty === undefined) opt.skipEmpty = true;
|
|
@@ -115,6 +166,9 @@ const download = (opt, cb) => {
|
|
|
115
166
|
opt.pathMaskInterpolationSuffix = opt.pathMaskInterpolationSuffix || '}}';
|
|
116
167
|
opt.pathMask = opt.pathMask || `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}${path.sep}${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`;
|
|
117
168
|
opt.pathMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, `${opt.languageFolderPrefix}${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`);
|
|
169
|
+
if (opt.unpublished && !opt.apiKey) {
|
|
170
|
+
return handleError(new Error('Please provide also an api-key!'), cb);
|
|
171
|
+
}
|
|
118
172
|
|
|
119
173
|
var url = opt.apiPath + '/download/' + opt.projectId;
|
|
120
174
|
|
|
@@ -140,27 +194,59 @@ const download = (opt, cb) => {
|
|
|
140
194
|
if (!cb) console.log(colors.yellow(`downloading ${url} to ${opt.path}...`));
|
|
141
195
|
|
|
142
196
|
getRemoteLanguages(opt, (err) => {
|
|
143
|
-
if (err) return handleError(err);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
197
|
+
if (err) return handleError(err, cb);
|
|
198
|
+
|
|
199
|
+
if (!opt.unpublished) {
|
|
200
|
+
request(url, {
|
|
201
|
+
method: 'get',
|
|
202
|
+
headers: opt.apiKey ? {
|
|
203
|
+
'Authorization': opt.apiKey
|
|
204
|
+
} : undefined
|
|
205
|
+
}, (err, res, obj) => {
|
|
206
|
+
obj = obj || [];
|
|
207
|
+
if (res && res.status === 401) {
|
|
208
|
+
opt.apiKey = null;
|
|
209
|
+
request(url, {
|
|
210
|
+
method: 'get',
|
|
211
|
+
}, (err, res, obj) => {
|
|
212
|
+
obj = obj || [];
|
|
213
|
+
if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2);
|
|
214
|
+
handleDownload(opt, url, err, res, obj, cb);
|
|
215
|
+
});
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
161
218
|
|
|
162
|
-
|
|
163
|
-
|
|
219
|
+
if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2);
|
|
220
|
+
handleDownload(opt, url, err, res, obj, cb);
|
|
221
|
+
});
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
getProjectStats(opt, (err, res) => {
|
|
226
|
+
if (err) return handleError(err, cb);
|
|
227
|
+
if (!res || !res[opt.version]) return handleError(new Error('Nothing found!'), cb);
|
|
228
|
+
|
|
229
|
+
const toDownload = [];
|
|
230
|
+
const lngsToCheck = opt.language ? [opt.language] : Object.keys(res[opt.version]);
|
|
231
|
+
lngsToCheck.forEach((l) => {
|
|
232
|
+
if (opt.namespaces) {
|
|
233
|
+
opt.namespaces.forEach((n) => {
|
|
234
|
+
if (!res[opt.version][l][n]) return;
|
|
235
|
+
if (opt.skipEmpty && res[opt.version][l][n].segmentsTranslated === 0) return;
|
|
236
|
+
toDownload.push({ language: l, namespace: n });
|
|
237
|
+
});
|
|
238
|
+
} else if (opt.namespace) {
|
|
239
|
+
if (!res[opt.version][l][opt.namespace]) return;
|
|
240
|
+
if (opt.skipEmpty && res[opt.version][l][opt.namespace].segmentsTranslated === 0) return;
|
|
241
|
+
toDownload.push({ language: l, namespace: opt.namespace });
|
|
242
|
+
} else {
|
|
243
|
+
Object.keys(res[opt.version][l]).forEach((n) => {
|
|
244
|
+
if (opt.skipEmpty && res[opt.version][l][n].segmentsTranslated === 0) return;
|
|
245
|
+
toDownload.push({ language: l, namespace: n });
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
handlePull(opt, toDownload, cb);
|
|
164
250
|
});
|
|
165
251
|
});
|
|
166
252
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const colors = require('colors');
|
|
2
|
+
const request = require('./request');
|
|
3
|
+
|
|
4
|
+
const getProjectStats = (opt, cb) => {
|
|
5
|
+
request(opt.apiPath + '/stats/project/' + opt.projectId, {
|
|
6
|
+
method: 'get',
|
|
7
|
+
headers: {
|
|
8
|
+
'Authorization': opt.apiKey
|
|
9
|
+
}
|
|
10
|
+
}, (err, res, obj) => {
|
|
11
|
+
if (err || (obj && (obj.errorMessage || obj.message))) {
|
|
12
|
+
if (!cb) console.log(colors.red('getting job failed...'));
|
|
13
|
+
|
|
14
|
+
if (err) {
|
|
15
|
+
if (!cb) { console.error(colors.red(err.message)); process.exit(1); }
|
|
16
|
+
if (cb) cb(err);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
20
|
+
if (!cb) { console.error(colors.red((obj.errorMessage || obj.message))); process.exit(1); }
|
|
21
|
+
if (cb) cb(new Error((obj.errorMessage || obj.message)));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (res.status === 404) {
|
|
26
|
+
if (!cb) { console.error(colors.yellow(res.statusText + ' (' + res.status + ')')); process.exit(1); }
|
|
27
|
+
if (cb) cb(null, null);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (res.status >= 300) {
|
|
31
|
+
if (!cb) { console.error(colors.red(res.statusText + ' (' + res.status + ')')); process.exit(1); }
|
|
32
|
+
if (cb) cb(new Error(res.statusText + ' (' + res.status + ')'));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!cb) console.log(colors.green('getting project stats succesfull'));
|
|
36
|
+
if (cb) cb(null, obj);
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
module.exports = getProjectStats;
|
package/getRemoteNamespace.js
CHANGED
|
@@ -3,9 +3,9 @@ const flatten = require('flat');
|
|
|
3
3
|
const sortFlatResources = require('./sortFlatResources');
|
|
4
4
|
|
|
5
5
|
const getRemoteNamespace = (opt, lng, ns, cb) => {
|
|
6
|
-
request(opt.apiPath + (opt.isPrivate ? '/private' : '') + '/' + opt.projectId + '/' + opt.version + '/' + lng + '/' + ns + '?ts=' + Date.now(), {
|
|
6
|
+
request(opt.apiPath + (opt.isPrivate ? '/private' : opt.unpublished ? '/pull' : '') + '/' + opt.projectId + '/' + opt.version + '/' + lng + '/' + ns + '?ts=' + Date.now(), {
|
|
7
7
|
method: 'get',
|
|
8
|
-
headers: opt.isPrivate ? {
|
|
8
|
+
headers: (opt.isPrivate || opt.unpublished) ? {
|
|
9
9
|
'Authorization': opt.apiKey
|
|
10
10
|
} : undefined
|
|
11
11
|
}, (err, res, obj) => {
|
package/package.json
CHANGED
package/sync.js
CHANGED
|
@@ -15,6 +15,7 @@ const parseLocalReference = require('./parseLocalReference');
|
|
|
15
15
|
const formats = require('./formats');
|
|
16
16
|
const lngCodes = require('./lngs.json');
|
|
17
17
|
const deleteNamespace = require('./deleteNamespace');
|
|
18
|
+
const getProjectStats = require('./getProjectStats');
|
|
18
19
|
const reversedFileExtensionsMap = formats.reversedFileExtensionsMap;
|
|
19
20
|
|
|
20
21
|
const getDirectories = (srcpath) => {
|
|
@@ -24,22 +25,66 @@ const getDirectories = (srcpath) => {
|
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
const getDownloads = (opt, cb) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
|
|
28
|
+
if (!opt.unpublished) {
|
|
29
|
+
request(opt.apiPath + '/download/' + opt.projectId + '/' + opt.version, {
|
|
30
|
+
method: 'get',
|
|
31
|
+
headers: opt.apiKey ? {
|
|
32
|
+
'Authorization': opt.apiKey
|
|
33
|
+
} : undefined
|
|
34
|
+
}, (err, res, obj) => {
|
|
35
|
+
if (err) return cb(err);
|
|
36
|
+
if (res.status >= 300) {
|
|
37
|
+
if (obj && (obj.errorMessage || obj.message)) {
|
|
38
|
+
return cb(new Error((obj.errorMessage || obj.message)));
|
|
39
|
+
}
|
|
40
|
+
return cb(new Error(res.statusText + ' (' + res.status + ')'));
|
|
37
41
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2);
|
|
43
|
+
cb(null, obj);
|
|
44
|
+
});
|
|
45
|
+
} else {
|
|
46
|
+
getProjectStats(opt, (err, res) => {
|
|
47
|
+
if (err) return handleError(err, cb);
|
|
48
|
+
if (!res || !res[opt.version]) return handleError(new Error('Nothing found!'), cb);
|
|
49
|
+
|
|
50
|
+
const toDownload = [];
|
|
51
|
+
const lngsToCheck = opt.language ? [opt.language] : Object.keys(res[opt.version]);
|
|
52
|
+
lngsToCheck.forEach((l) => {
|
|
53
|
+
if (opt.namespaces) {
|
|
54
|
+
opt.namespaces.forEach((n) => {
|
|
55
|
+
if (!res[opt.version][l][n]) return;
|
|
56
|
+
if (opt.skipEmpty && res[opt.version][l][n].segmentsTranslated === 0) return;
|
|
57
|
+
toDownload.push({
|
|
58
|
+
url: `${opt.apiPath}/${opt.projectId}/${opt.version}/${l}/${n}`,
|
|
59
|
+
key: `${opt.projectId}/${opt.version}/${l}/${n}`,
|
|
60
|
+
lastModified: '1960-01-01T00:00:00.000Z',
|
|
61
|
+
size: 0
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
} else if (opt.namespace) {
|
|
65
|
+
if (!res[opt.version][l][opt.namespace]) return;
|
|
66
|
+
if (opt.skipEmpty && res[opt.version][l][opt.namespace].segmentsTranslated === 0) return;
|
|
67
|
+
toDownload.push({
|
|
68
|
+
url: `${opt.apiPath}/${opt.projectId}/${opt.version}/${l}/${opt.namespace}`,
|
|
69
|
+
key: `${opt.projectId}/${opt.version}/${l}/${opt.namespace}`,
|
|
70
|
+
lastModified: '1960-01-01T00:00:00.000Z',
|
|
71
|
+
size: 0
|
|
72
|
+
});
|
|
73
|
+
} else {
|
|
74
|
+
Object.keys(res[opt.version][l]).forEach((n) => {
|
|
75
|
+
if (opt.skipEmpty && res[opt.version][l][n].segmentsTranslated === 0) return;
|
|
76
|
+
toDownload.push({
|
|
77
|
+
url: `${opt.apiPath}/${opt.projectId}/${opt.version}/${l}/${n}`,
|
|
78
|
+
key: `${opt.projectId}/${opt.version}/${l}/${n}`,
|
|
79
|
+
lastModified: '1960-01-01T00:00:00.000Z',
|
|
80
|
+
size: 0
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
cb(null, toDownload);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
43
88
|
};
|
|
44
89
|
|
|
45
90
|
const compareNamespace = (local, remote, lastModifiedLocal, lastModifiedRemote) => {
|
|
@@ -160,7 +205,7 @@ const downloadAll = (opt, remoteLanguages, omitRef, manipulate, cb) => {
|
|
|
160
205
|
return lng !== opt.referenceLanguage;
|
|
161
206
|
});
|
|
162
207
|
}
|
|
163
|
-
async.
|
|
208
|
+
async.eachLimit(downloads, 20, (download, clb) => {
|
|
164
209
|
const splitted = download.key.split('/');
|
|
165
210
|
const lng = splitted[download.isPrivate ? 3 : 2];
|
|
166
211
|
const namespace = splitted[download.isPrivate ? 4 : 3];
|
|
@@ -327,7 +372,7 @@ const checkForMissingLocalNamespaces = (downloads, localNamespaces, opt) => {
|
|
|
327
372
|
const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
328
373
|
if (!localNamespaces || localNamespaces.length === 0) {
|
|
329
374
|
downloadAll(opt, remoteLanguages, (err) => {
|
|
330
|
-
if (err) return handleError(err);
|
|
375
|
+
if (err) return handleError(err, cb);
|
|
331
376
|
if (!cb) console.log(colors.green('FINISHED'));
|
|
332
377
|
if (cb) cb(null);
|
|
333
378
|
});
|
|
@@ -335,14 +380,14 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
|
335
380
|
}
|
|
336
381
|
|
|
337
382
|
getDownloads(opt, (err, downloads) => {
|
|
338
|
-
if (err) return handleError(err);
|
|
383
|
+
if (err) return handleError(err, cb);
|
|
339
384
|
|
|
340
385
|
opt.isPrivate = downloads.length > 0 && downloads[0].isPrivate;
|
|
341
386
|
|
|
342
387
|
const localMissingNamespaces = checkForMissingLocalNamespaces(downloads, localNamespaces, opt);
|
|
343
388
|
|
|
344
389
|
compareNamespaces(opt, localNamespaces, (err, compared) => {
|
|
345
|
-
if (err) return handleError(err);
|
|
390
|
+
if (err) return handleError(err, cb);
|
|
346
391
|
|
|
347
392
|
const onlyToUpdate = compared.filter((ns) => ns.diff.toAdd.concat(opt.skipDelete ? [] : ns.diff.toRemove).concat(ns.diff.toUpdate).length > 0);
|
|
348
393
|
|
|
@@ -412,7 +457,7 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
|
412
457
|
async.eachLimit(remoteLanguages, Math.round(require('os').cpus().length / 2), (lng, clb) => update(opt, lng, nsOnlyRemove, shouldOmit, clb), clb);
|
|
413
458
|
});
|
|
414
459
|
}, (err) => {
|
|
415
|
-
if (err) return handleError(err);
|
|
460
|
+
if (err) return handleError(err, cb);
|
|
416
461
|
if (!cb) console.log(colors.grey('syncing...'));
|
|
417
462
|
|
|
418
463
|
function down() {
|
|
@@ -432,7 +477,7 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
|
432
477
|
}
|
|
433
478
|
}
|
|
434
479
|
} : undefined, (err) => {
|
|
435
|
-
if (err) return handleError(err);
|
|
480
|
+
if (err) return handleError(err, cb);
|
|
436
481
|
if (!cb) console.log(colors.green('FINISHED'));
|
|
437
482
|
if (cb) cb(null);
|
|
438
483
|
});
|
|
@@ -450,12 +495,12 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
|
450
495
|
'Authorization': opt.apiKey
|
|
451
496
|
}
|
|
452
497
|
}, (err, res, obj) => {
|
|
453
|
-
if (err) return handleError(err);
|
|
498
|
+
if (err) return handleError(err, cb);
|
|
454
499
|
if (res.status >= 300 && res.status !== 412) {
|
|
455
500
|
if (obj && (obj.errorMessage || obj.message)) {
|
|
456
|
-
return handleError(new Error((obj.errorMessage || obj.message)));
|
|
501
|
+
return handleError(new Error((obj.errorMessage || obj.message)), cb);
|
|
457
502
|
}
|
|
458
|
-
return handleError(new Error(res.statusText + ' (' + res.status + ')'));
|
|
503
|
+
return handleError(new Error(res.statusText + ' (' + res.status + ')'), cb);
|
|
459
504
|
}
|
|
460
505
|
down();
|
|
461
506
|
});
|
|
@@ -464,7 +509,7 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
|
464
509
|
|
|
465
510
|
if (opt.deleteRemoteNamespace && localMissingNamespaces.length > 0) {
|
|
466
511
|
wasThereSomethingToUpdate = true;
|
|
467
|
-
async.
|
|
512
|
+
async.eachLimit(localMissingNamespaces, 20, (n, clb) => {
|
|
468
513
|
if (opt.dry) {
|
|
469
514
|
console.log(colors.red(`would delete complete namespace ${n.namespace}...`));
|
|
470
515
|
return clb();
|
|
@@ -478,7 +523,7 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
|
478
523
|
namespace: n.namespace
|
|
479
524
|
}, clb);
|
|
480
525
|
}, (err) => {
|
|
481
|
-
if (err) return handleError(err);
|
|
526
|
+
if (err) return handleError(err, cb);
|
|
482
527
|
updateComparedNamespaces();
|
|
483
528
|
});
|
|
484
529
|
return;
|
|
@@ -491,7 +536,7 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
|
491
536
|
const sync = (opt, cb) => {
|
|
492
537
|
opt.format = opt.format || 'json';
|
|
493
538
|
if (!reversedFileExtensionsMap[opt.format]) {
|
|
494
|
-
return handleError(new Error(`${opt.format} is not a valid format!`));
|
|
539
|
+
return handleError(new Error(`${opt.format} is not a valid format!`), cb);
|
|
495
540
|
}
|
|
496
541
|
|
|
497
542
|
opt.version = opt.version || 'latest';
|
|
@@ -510,9 +555,12 @@ const sync = (opt, cb) => {
|
|
|
510
555
|
opt.pathMask = opt.pathMask || `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}${path.sep}${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`;
|
|
511
556
|
opt.languageFolderPrefix = opt.languageFolderPrefix || '';
|
|
512
557
|
opt.pathMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, `${opt.languageFolderPrefix}${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`);
|
|
558
|
+
if (opt.unpublished && !opt.apiKey) {
|
|
559
|
+
return handleError(new Error('Please provide also an api-key!'), cb);
|
|
560
|
+
}
|
|
513
561
|
|
|
514
562
|
getRemoteLanguages(opt, (err, remoteLanguages) => {
|
|
515
|
-
if (err) return handleError(err);
|
|
563
|
+
if (err) return handleError(err, cb);
|
|
516
564
|
|
|
517
565
|
if (opt.referenceLanguageOnly && opt.language && opt.referenceLanguage !== opt.language) {
|
|
518
566
|
opt.referenceLanguage = opt.language;
|
|
@@ -520,7 +568,7 @@ const sync = (opt, cb) => {
|
|
|
520
568
|
|
|
521
569
|
if (opt.referenceLanguageOnly) {
|
|
522
570
|
parseLocalReference(opt, (err, localNamespaces) => {
|
|
523
|
-
if (err) return handleError(err);
|
|
571
|
+
if (err) return handleError(err, cb);
|
|
524
572
|
|
|
525
573
|
if (!opt.dry && opt.cleanLocalFiles) {
|
|
526
574
|
localNamespaces.forEach((ln) => fs.unlinkSync(ln.path));
|
|
@@ -533,7 +581,7 @@ const sync = (opt, cb) => {
|
|
|
533
581
|
}
|
|
534
582
|
|
|
535
583
|
parseLocalLanguages(opt, remoteLanguages, (err, localNamespaces) => {
|
|
536
|
-
if (err) return handleError(err);
|
|
584
|
+
if (err) return handleError(err, cb);
|
|
537
585
|
|
|
538
586
|
if (!opt.dry && opt.cleanLocalFiles) {
|
|
539
587
|
localNamespaces.forEach((ln) => fs.unlinkSync(ln.path));
|