locize-cli 7.6.14 → 7.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ # Number of days of inactivity before an issue becomes stale
2
+ daysUntilStale: 7
3
+ # Number of days of inactivity before a stale issue is closed
4
+ daysUntilClose: 7
5
+ # Issues with these labels will never be considered stale
6
+ exemptLabels:
7
+ - "discussion"
8
+ - "feature request"
9
+ - "bug"
10
+ - "breaking change"
11
+ - "doc"
12
+ - "issue"
13
+ - "help wanted"
14
+ - "good first issue"
15
+ # Label to use when marking an issue as stale
16
+ staleLabel: stale
17
+ # Comment to post when marking an issue as stale. Set to `false` to disable
18
+ markComment: >
19
+ This issue has been automatically marked as stale because it has not had
20
+ recent activity. It will be closed if no further activity occurs. Thank you
21
+ for your contributions.
22
+ # Comment to post when closing a stale issue. Set to `false` to disable
23
+ closeComment: false
package/CHANGELOG.md CHANGED
@@ -5,6 +5,27 @@ 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.7.0](https://github.com/locize/locize-cli/compare/v7.6.17...v7.7.0) - 2021-12-08
9
+
10
+ - sync: optimize api requests on bigger projects
11
+ - retry on very short dns resolution errors
12
+
13
+
14
+ ## [7.6.17](https://github.com/locize/locize-cli/compare/v7.6.16...v7.6.17) - 2021-09-21
15
+
16
+ - check skipEmpty flag when downloading translations
17
+
18
+
19
+ ## [7.6.16](https://github.com/locize/locize-cli/compare/v7.6.15...v7.6.16) - 2021-09-20
20
+
21
+ - by default set also languageFolderPrefix to empty string when using programmatically
22
+
23
+
24
+ ## [7.6.15](https://github.com/locize/locize-cli/compare/v7.6.14...v7.6.15) - 2021-07-23
25
+
26
+ - update some dependencies
27
+
28
+
8
29
  ## [7.6.14](https://github.com/locize/locize-cli/compare/v7.6.13...v7.6.14) - 2021-03-13
9
30
 
10
31
  - update all dependencies
package/README.md CHANGED
@@ -88,6 +88,11 @@ locize download --project-id my-project-id-93e1-442a-ab35-24331fa294ba --ver lat
88
88
 
89
89
 
90
90
  ## Synchronize locize with your repository (or any other local directory)
91
+ By using the sync command, you can keep your existing code setup and synchronize the translations with locize.
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
+
94
+ **⚠️ Since the remote source are the published translations, make sure the desired version is set to standard publish mode, or alternatively [publish](#publish-version) that version before you execute the cli command. ⚠️**
95
+
91
96
  ### Step 1: Go near to your translation files
92
97
 
93
98
  ```sh
@@ -139,6 +144,13 @@ Navigate to your locize project and check the results => [www.locize.app](https:
139
144
 
140
145
 
141
146
  ## Push missing keys to locize from your repository (or any other local directory)
147
+ This is useful, when i.e. using [i18next-scanner](https://github.com/i18next/i18next-scanner), like described [here](https://github.com/locize/i18next-locize-backend/issues/315#issuecomment-586967039).
148
+ The save-missing command uses the [missing API](https://docs.locize.com/integration/api#missing-translations) and the sync command uses the [update API](https://docs.locize.com/integration/api#update-remove-translations)
149
+ So, if you want to save new keys (that does not exist in locize), the save-missing command is the better choice.
150
+ Doing so, you can then for example make use of the “created by missing API" filter in the locize UI.
151
+
152
+ But if you need to update existing keys, the sync command is the correct choice.
153
+
142
154
  ### Step 1: Go near to your translation files
143
155
 
144
156
  ```sh
package/download.js CHANGED
@@ -152,10 +152,14 @@ const download = (opt, cb) => {
152
152
  opt.apiKey = null;
153
153
  request(url, {
154
154
  method: 'get',
155
- }, (err, res, obj) => handleDownload(opt, url, err, res, obj, cb));
155
+ }, (err, res, obj) => {
156
+ if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2);
157
+ handleDownload(opt, url, err, res, obj, cb);
158
+ });
156
159
  return;
157
160
  }
158
161
 
162
+ if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2);
159
163
  handleDownload(opt, url, err, res, obj, cb);
160
164
  });
161
165
  });
package/missing.js CHANGED
@@ -139,6 +139,7 @@ const missing = (opt, cb) => {
139
139
  opt.pathMaskInterpolationPrefix = opt.pathMaskInterpolationPrefix || '{{';
140
140
  opt.pathMaskInterpolationSuffix = opt.pathMaskInterpolationSuffix || '}}';
141
141
  opt.pathMask = opt.pathMask || `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}${path.sep}${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`;
142
+ opt.languageFolderPrefix = opt.languageFolderPrefix || '';
142
143
  opt.pathMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, `${opt.languageFolderPrefix}${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`);
143
144
 
144
145
  getRemoteLanguages(opt, (err, remoteLanguages) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locize-cli",
3
- "version": "7.6.14",
3
+ "version": "7.7.0",
4
4
  "description": "locize cli to import locales",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -9,32 +9,32 @@
9
9
  "dependencies": {
10
10
  "@js.properties/properties": "0.5.4",
11
11
  "android-string-resource": "2.3.4",
12
- "async": "3.2.0",
12
+ "async": "3.2.1",
13
13
  "colors": "1.4.0",
14
- "commander": "7.1.0",
14
+ "commander": "7.2.0",
15
15
  "csvjson": "5.1.0",
16
16
  "diff": "5.0.0",
17
17
  "flat": "5.0.2",
18
18
  "fluent_conv": "3.1.0",
19
- "gettext-converter": "1.0.7",
19
+ "gettext-converter": "1.1.0",
20
20
  "https-proxy-agent": "5.0.0",
21
21
  "ini": "2.0.0",
22
- "js-yaml": "4.0.0",
22
+ "js-yaml": "4.1.0",
23
23
  "laravelphp": "2.0.3",
24
24
  "lodash.clonedeep": "4.5.0",
25
25
  "mkdirp": "1.0.4",
26
- "node-fetch": "2.6.1",
26
+ "node-fetch": "2.6.2",
27
27
  "resx": "2.0.3",
28
28
  "rimraf": "3.0.2",
29
29
  "strings-file": "0.0.5",
30
30
  "tmexchange": "2.0.4",
31
- "xliff": "5.5.1",
32
- "xlsx": "0.16.9"
31
+ "xliff": "5.6.2",
32
+ "xlsx": "0.17.2"
33
33
  },
34
34
  "devDependencies": {
35
- "eslint": "7.22.0",
36
- "gh-release": "5.0.0",
37
- "pkg": "4.4.9"
35
+ "eslint": "7.32.0",
36
+ "gh-release": "6.0.0",
37
+ "pkg": "5.3.2"
38
38
  },
39
39
  "scripts": {
40
40
  "lint": "eslint .",
package/request.js CHANGED
@@ -22,5 +22,19 @@ module.exports = (url, options, callback) => {
22
22
  } else {
23
23
  return { res };
24
24
  }
25
- }).then((ret) => callback(null, ret.res, ret.obj)).catch(callback);
25
+ }).then((ret) => callback(null, ret.res, ret.obj)).catch((err) => {
26
+ if (err && err.message && err.message.indexOf('ENOTFOUND') > -1) {
27
+ setTimeout(() => {
28
+ fetch(url, options).then((res) => {
29
+ if (res.headers.get('content-type') && res.headers.get('content-type').indexOf('json') > 0) {
30
+ return new Promise((resolve, reject) => res.json().then((obj) => resolve({ res, obj })).catch(reject));
31
+ } else {
32
+ return { res };
33
+ }
34
+ }).then((ret) => callback(null, ret.res, ret.obj)).catch(callback);
35
+ }, 3000);
36
+ return;
37
+ }
38
+ callback(err);
39
+ });
26
40
  };
package/sync.js CHANGED
@@ -36,6 +36,7 @@ const getDownloads = (opt, cb) => {
36
36
  }
37
37
  return cb(new Error(res.statusText + ' (' + res.status + ')'));
38
38
  }
39
+ if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2);
39
40
  cb(null, obj);
40
41
  });
41
42
  };
@@ -197,7 +198,7 @@ const downloadAll = (opt, remoteLanguages, omitRef, manipulate, cb) => {
197
198
  });
198
199
  };
199
200
 
200
- const update = (opt, lng, ns, cb) => {
201
+ const update = (opt, lng, ns, shouldOmit, cb) => {
201
202
  var data = {};
202
203
  if (!opt.skipDelete) {
203
204
  ns.diff.toRemove.forEach((k) => data[k] = null);
@@ -214,7 +215,7 @@ const update = (opt, lng, ns, cb) => {
214
215
  var payloadKeysLimit = 1000;
215
216
 
216
217
  function send(d, clb, isRetrying) {
217
- request(opt.apiPath + '/update/' + opt.projectId + '/' + opt.version + '/' + lng + '/' + ns.namespace, {
218
+ request(opt.apiPath + '/update/' + opt.projectId + '/' + opt.version + '/' + lng + '/' + ns.namespace + (shouldOmit ? '?omitstatsgeneration=true' : ''), {
218
219
  method: 'post',
219
220
  body: d,
220
221
  headers: {
@@ -320,6 +321,20 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
320
321
  compareNamespaces(opt, localNamespaces, (err, compared) => {
321
322
  if (err) return handleError(err);
322
323
 
324
+ const onlyToUpdate = compared.filter((ns) => ns.diff.toAdd.concat(opt.skipDelete ? [] : ns.diff.toRemove).concat(ns.diff.toUpdate).length > 0);
325
+
326
+ const lngsInReqs = [];
327
+ const nsInReqs = [];
328
+ onlyToUpdate.forEach((n) => {
329
+ if (lngsInReqs.indexOf(n.language) < 0) {
330
+ lngsInReqs.push(n.language);
331
+ }
332
+ if (nsInReqs.indexOf(n.namespace) < 0) {
333
+ nsInReqs.push(n.namespace);
334
+ }
335
+ });
336
+ const shouldOmit = lngsInReqs.length > 5 || nsInReqs.length > 5;
337
+
323
338
  var wasThereSomethingToUpdate = false;
324
339
  async.eachLimit(compared, Math.round(require('os').cpus().length / 2), (ns, clb) => {
325
340
  if (!cb) {
@@ -363,40 +378,63 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
363
378
  if (!somethingToUpdate) console.log(colors.grey(`nothing to update for ${ns.language}/${ns.namespace}`));
364
379
  if (!wasThereSomethingToUpdate && somethingToUpdate) wasThereSomethingToUpdate = true;
365
380
  }
366
- update(opt, ns.language, ns, (err) => {
381
+ update(opt, ns.language, ns, shouldOmit, (err) => {
367
382
  if (err) return clb(err);
368
383
  if (ns.diff.toRemove.length === 0 || ns.language !== opt.referenceLanguage) return clb();
369
384
  const nsOnlyRemove = cloneDeep(ns);
370
385
  nsOnlyRemove.diff.toAdd = [];
371
386
  nsOnlyRemove.diff.toUpdate = [];
372
- async.eachLimit(remoteLanguages, Math.round(require('os').cpus().length / 2), (lng, clb) => update(opt, lng, nsOnlyRemove, clb), clb);
387
+ async.eachLimit(remoteLanguages, Math.round(require('os').cpus().length / 2), (lng, clb) => update(opt, lng, nsOnlyRemove, shouldOmit, clb), clb);
373
388
  });
374
389
  }, (err) => {
375
390
  if (err) return handleError(err);
376
-
377
391
  if (!cb) console.log(colors.grey('syncing...'));
378
- setTimeout(() => {
379
- downloadAll(opt, remoteLanguages, false, opt.skipDelete ? (lng, namespace, ns) => {
380
- const found = compared.find((n) => n.namespace === namespace && n.language === lng);
381
- if (found && found.diff) {
382
- if (found.diff.toAddLocally && found.diff.toAddLocally.length > 0) {
383
- found.diff.toAddLocally.forEach((k) => {
384
- delete ns[k];
385
- });
386
- }
387
- if (found.diff.toRemove && found.diff.toRemove.length > 0) {
388
- found.diff.toRemove.forEach((k) => {
389
- delete ns[k];
390
- });
392
+
393
+ function down() {
394
+ setTimeout(() => { // wait a bit before downloading... just to have a chance to get the newly published files
395
+ downloadAll(opt, remoteLanguages, false, opt.skipDelete ? (lng, namespace, ns) => {
396
+ const found = compared.find((n) => n.namespace === namespace && n.language === lng);
397
+ if (found && found.diff) {
398
+ if (found.diff.toAddLocally && found.diff.toAddLocally.length > 0) {
399
+ found.diff.toAddLocally.forEach((k) => {
400
+ delete ns[k];
401
+ });
402
+ }
403
+ if (found.diff.toRemove && found.diff.toRemove.length > 0) {
404
+ found.diff.toRemove.forEach((k) => {
405
+ delete ns[k];
406
+ });
407
+ }
391
408
  }
409
+ } : undefined, (err) => {
410
+ if (err) return handleError(err);
411
+ if (!cb) console.log(colors.green('FINISHED'));
412
+ if (cb) cb(null);
413
+ });
414
+ }, wasThereSomethingToUpdate && !opt.dry ? 5000 : 0);
415
+ }
416
+
417
+ if (!shouldOmit) return down();
418
+ if (opt.dry) return down();
419
+
420
+ // optimize stats generation...
421
+ request(opt.apiPath + '/stats/project/regenerate/' + opt.projectId + '/' + opt.version + (lngsInReqs.length === 1 ? `/${lngsInReqs[0]}` : '') + (nsInReqs.length === 1 ? `?namespace=${nsInReqs[0]}` : ''), {
422
+ method: 'post',
423
+ body: {},
424
+ headers: {
425
+ 'Authorization': opt.apiKey
426
+ }
427
+ }, (err, res, obj) => {
428
+ if (err) return handleError(err);
429
+ if (res.status >= 300 && res.status !== 412) {
430
+ if (obj && (obj.errorMessage || obj.message)) {
431
+ return handleError(new Error((obj.errorMessage || obj.message)));
392
432
  }
393
- } : undefined, (err) => {
394
- if (err) return handleError(err);
395
- if (!cb) console.log(colors.green('FINISHED'));
396
- if (cb) cb(null);
397
- });
398
- }, wasThereSomethingToUpdate && !opt.dry ? 5000 : 0);
399
- }); // wait a bit before downloading... just to have a chance to get the newly published files
433
+ return handleError(new Error(res.statusText + ' (' + res.status + ')'));
434
+ }
435
+ down();
436
+ });
437
+ });
400
438
  });
401
439
  });
402
440
  };
@@ -421,6 +459,7 @@ const sync = (opt, cb) => {
421
459
  opt.pathMaskInterpolationPrefix = opt.pathMaskInterpolationPrefix || '{{';
422
460
  opt.pathMaskInterpolationSuffix = opt.pathMaskInterpolationSuffix || '}}';
423
461
  opt.pathMask = opt.pathMask || `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}${path.sep}${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`;
462
+ opt.languageFolderPrefix = opt.languageFolderPrefix || '';
424
463
  opt.pathMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, `${opt.languageFolderPrefix}${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`);
425
464
 
426
465
  getRemoteLanguages(opt, (err, remoteLanguages) => {