locize-cli 8.1.0 → 8.2.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ 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
+ ## [8.2.0](https://github.com/locize/locize-cli/compare/v8.1.1...v8.2.0) - 2024-11-12
9
+
10
+ - introduce `--backup-deleted-path` argument (#98)
11
+
12
+ ## [8.1.1](https://github.com/locize/locize-cli/compare/v8.1.0...v8.1.1) - 2024-10-29
13
+
14
+ - improve some error logs
15
+
8
16
  ## [8.1.0](https://github.com/locize/locize-cli/compare/v8.0.2...v8.1.0) - 2024-09-19
9
17
 
10
18
  - introduce `--languages lng1,lng2` argument (#96)
package/bin/locize CHANGED
@@ -359,6 +359,7 @@ program
359
359
  .option('-i, --project-id <projectId>', 'The project-id that should be used')
360
360
  .option('-v, --ver <version>', 'Found namespaces will be matched to this version (default: latest)')
361
361
  .option('-p, --path <path>', `Specify the path that should be used (default: ${process.cwd()})`, process.cwd())
362
+ .option('-B, --backup-deleted-path <path>', 'Saves the segments that will be deleted in this path')
362
363
  .option('-A, --auto-create-path <true|false>', 'This will automatically make sure the --path is created. (default: true)', 'true')
363
364
  .option('-f, --format <json>', 'File format of namespaces (default: json; [nested, flat, xliff2, xliff12, xlf2, xlf12, android, yaml, yaml-rails, yaml-nested, csv, xlsx, po, strings, resx, fluent, tmx, laravel, properties])', 'json')
364
365
  .option('-s, --skip-empty <true|false>', 'Skips to download empty files (default: false)', 'false')
@@ -423,6 +424,7 @@ program
423
424
  const pathMask = options.pathMask;
424
425
  const unpublished = options.unpublished === 'true';
425
426
  const autoCreatePath = options.autoCreatePath === 'true';
427
+ const backupDeletedPath = options.backupDeletedPath;
426
428
 
427
429
  sync({
428
430
  apiPath: url.parse(getPath).protocol + '//' + url.parse(getPath).host,
@@ -446,7 +448,8 @@ program
446
448
  dry: dry,
447
449
  pathMask: pathMask,
448
450
  unpublished: unpublished,
449
- autoCreatePath: autoCreatePath
451
+ autoCreatePath: autoCreatePath,
452
+ backupDeletedPath: backupDeletedPath
450
453
  });
451
454
  })
452
455
  .on('--help', () => {
@@ -6,7 +6,12 @@ const getRemoteLanguages = (opt, cb) => {
6
6
  }, (err, res, obj) => {
7
7
  if (err || (obj && (obj.errorMessage || obj.message))) {
8
8
  if (err) return cb(err);
9
- if (obj && (obj.errorMessage || obj.message)) return cb(new Error((obj.errorMessage || obj.message)));
9
+ if (obj && (obj.errorMessage || obj.message)) {
10
+ if (res && res.statusText && res.status) {
11
+ return cb(new Error(res.statusText + ' (' + res.status + ') | ' + (obj.errorMessage || obj.message)));
12
+ }
13
+ return cb(new Error((obj.errorMessage || obj.message)));
14
+ }
10
15
  }
11
16
  if (res.status >= 300) return cb(new Error(res.statusText + ' (' + res.status + ')'));
12
17
 
@@ -22,6 +22,9 @@ const pullNamespacePaged = (opt, lng, ns, cb, next, retry) => {
22
22
  return;
23
23
  }
24
24
  if (obj && (obj.errorMessage || obj.message)) {
25
+ if (res.statusText && res.status) {
26
+ return cb(new Error(res.statusText + ' (' + res.status + ') | ' + (obj.errorMessage || obj.message)));
27
+ }
25
28
  return cb(new Error((obj.errorMessage || obj.message)));
26
29
  }
27
30
  return cb(new Error(res.statusText + ' (' + res.status + ')'));
@@ -70,6 +73,9 @@ const getRemoteNamespace = (opt, lng, ns, cb) => {
70
73
  if (err) return cb(err);
71
74
  if (res.status >= 300) {
72
75
  if (obj && (obj.errorMessage || obj.message)) {
76
+ if (res.statusText && res.status) {
77
+ return cb(new Error(res.statusText + ' (' + res.status + ') | ' + (obj.errorMessage || obj.message)));
78
+ }
73
79
  return cb(new Error((obj.errorMessage || obj.message)));
74
80
  }
75
81
  return cb(new Error(res.statusText + ' (' + res.status + ')'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locize-cli",
3
- "version": "8.1.0",
3
+ "version": "8.2.0",
4
4
  "description": "locize cli to import locales",
5
5
  "main": "index.js",
6
6
  "bin": {
package/request.js CHANGED
@@ -11,6 +11,8 @@ const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY || process.en
11
11
  const isRetriableError = (err) => {
12
12
  return err && err.message && (
13
13
  err.message.indexOf('ETIMEDOUT') > -1 || // on timeout retry
14
+ err.message.indexOf('FetchError') > -1 ||
15
+ err.code === 'ETIMEDOUT' ||
14
16
  // on dns errors
15
17
  err.message.indexOf('ENOTFOUND') > -1 ||
16
18
  err.message.indexOf('ENODATA') > -1 ||
package/sync.js CHANGED
@@ -35,6 +35,9 @@ const getDownloads = (opt, cb) => {
35
35
  if (err) return cb(err);
36
36
  if (res.status >= 300) {
37
37
  if (obj && (obj.errorMessage || obj.message)) {
38
+ if (res.statusText && res.status) {
39
+ return cb(new Error(res.statusText + ' (' + res.status + ') | ' + (obj.errorMessage || obj.message)));
40
+ }
38
41
  return cb(new Error((obj.errorMessage || obj.message)));
39
42
  }
40
43
  return cb(new Error(res.statusText + ' (' + res.status + ')'));
@@ -135,7 +138,7 @@ const compareNamespace = (local, remote, lastModifiedLocal, lastModifiedRemote)
135
138
  };
136
139
 
137
140
  const compareNamespaces = (opt, localNamespaces, cb) => {
138
- async.map(localNamespaces, (ns, clb) => {
141
+ async.mapLimit(localNamespaces, 20, (ns, clb) => {
139
142
  getRemoteNamespace(opt, ns.language, ns.namespace, (err, remoteNamespace, lastModified) => {
140
143
  if (err) return clb(err);
141
144
 
@@ -378,6 +381,28 @@ const checkForMissingLocalNamespaces = (downloads, localNamespaces, opt) => {
378
381
  return localMissingNamespaces;
379
382
  };
380
383
 
384
+ const backupDeleted = (opt, ns, now) => {
385
+ if (opt.dry || ns.diff.toRemove.length === 0) return;
386
+ var m = now.getMonth() + 1;
387
+ if (m < 10) m = `0${m}`;
388
+ var d = now.getDate();
389
+ if (d < 10) d = `0${d}`;
390
+ var h = now.getHours();
391
+ if (h < 10) h = `0${h}`;
392
+ var mi = now.getMinutes();
393
+ if (mi < 10) mi = `0${mi}`;
394
+ var s = now.getSeconds();
395
+ if (s < 10) s = `0${s}`;
396
+ const currentBackupPath = path.join(opt.backupDeletedPath, `${now.getFullYear()}${m}${d}-${h}${mi}${s}`);
397
+ mkdirp.sync(currentBackupPath);
398
+ const removingRemote = ns.diff.toRemove.reduce((prev, k) => {
399
+ prev[k] = ns.remoteContent[k];
400
+ return prev;
401
+ }, {});
402
+ mkdirp.sync(path.join(currentBackupPath, ns.language));
403
+ fs.writeFileSync(path.join(currentBackupPath, ns.language, `${ns.namespace}.json`), JSON.stringify(removingRemote, null, 2));
404
+ };
405
+
381
406
  const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
382
407
  if (!localNamespaces || localNamespaces.length === 0) {
383
408
  downloadAll(opt, remoteLanguages, (err) => {
@@ -415,6 +440,7 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
415
440
  var wasThereSomethingToUpdate = false;
416
441
 
417
442
  function updateComparedNamespaces() {
443
+ const now = new Date();
418
444
  async.eachLimit(compared, Math.round(require('os').cpus().length / 2), (ns, clb) => {
419
445
  if (!cb) {
420
446
  if (ns.diff.toRemove.length > 0) {
@@ -424,6 +450,7 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
424
450
  } else {
425
451
  console.log(colors.red(`removing ${ns.diff.toRemove.length} keys in ${ns.language}/${ns.namespace}...`));
426
452
  if (opt.dry) console.log(colors.red(`would remove ${ns.diff.toRemove.join(', ')} in ${ns.language}/${ns.namespace}...`));
453
+ if (!opt.dry && opt.backupDeletedPath) backupDeleted(opt, ns, now);
427
454
  }
428
455
  }
429
456
  if (ns.diff.toRemoveLocally.length > 0) {