locize-cli 10.0.2 → 10.1.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
+ ## [10.1.0](https://github.com/locize/locize-cli/compare/v10.0.3...v10.1.0) - 2025-07-10
9
+
10
+ - introduce branching features
11
+
12
+ ## [10.0.3](https://github.com/locize/locize-cli/compare/v10.0.2...v10.0.3) - 2025-07-09
13
+
14
+ - introduce `--ignore-if-version-exists` option for `copy-version`
15
+
8
16
  ## [10.0.2](https://github.com/locize/locize-cli/compare/v10.0.1...v10.0.2) - 2025-07-02
9
17
 
10
18
  - respect opt.namespace when parsing local namespaces
package/README.md CHANGED
@@ -325,6 +325,27 @@ locize format path/to/dictionary --format android
325
325
  ```
326
326
 
327
327
 
328
+ ## Working with branches
329
+ ### Create a new branch
330
+
331
+ ```sh
332
+ locize create-branch featureXYZ --api-key my-api-key-d9de-4f55-9855-a9ef0ed44672 --project-id my-project-id-93e1-442a-ab35-24331fa294ba --ver latest
333
+ ```
334
+
335
+ ### Sync or Download that branch
336
+
337
+ ```sh
338
+ locize sync --branch featureXYZ --api-key my-api-key-d9de-4f55-9855-a9ef0ed44672 --project-id my-project-id-93e1-442a-ab35-24331fa294ba
339
+
340
+ locize download --branch featureXYZ --api-key my-api-key-d9de-4f55-9855-a9ef0ed44672 --project-id my-project-id-93e1-442a-ab35-24331fa294ba
341
+ ```
342
+
343
+ ### Merge that branch
344
+
345
+ ```sh
346
+ locize merge-branch featureXYZ --api-key my-api-key-d9de-4f55-9855-a9ef0ed44672 --project-id my-project-id-93e1-442a-ab35-24331fa294ba --delete true
347
+ ```
348
+
328
349
 
329
350
  ## Other information
330
351
 
package/bin/locize CHANGED
@@ -26,6 +26,8 @@ const removeVersion = require('../removeVersion.js');
26
26
  const publishVersion = require('../publishVersion');
27
27
  const deleteNamespace = require('../deleteNamespace');
28
28
  const formatFn = require('../format');
29
+ const createBranch = require('../createBranch');
30
+ const mergeBranch = require('../mergeBranch');
29
31
 
30
32
  var config = {};
31
33
  try {
@@ -239,6 +241,7 @@ program
239
241
  .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
242
  .option('-c, --clean <true|false>', 'Removes all local files by removing the whole folder (default: false)', 'false')
241
243
  .option('-up, --unpublished <true|false>', 'Downloads the current (unpublished) translations. This will generate private download costs (default: false)', 'false')
244
+ .option('-b, --branch <branch>', 'The branch name (or id) that should be targeted')
242
245
  .option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${configInWorkingDirectory} or ${configInHome})`)
243
246
  .action((options) => {
244
247
  try {
@@ -275,6 +278,8 @@ program
275
278
 
276
279
  const pathMask = options.pathMask;
277
280
 
281
+ const branch = options.branch;
282
+
278
283
  download({
279
284
  apiKey: apiKey,
280
285
  projectId: projectId,
@@ -289,7 +294,8 @@ program
289
294
  clean: clean,
290
295
  languageFolderPrefix: languageFolderPrefix,
291
296
  pathMask: pathMask,
292
- unpublished: unpublished
297
+ unpublished: unpublished,
298
+ branch: branch
293
299
  });
294
300
  })
295
301
  .on('--help', () => {
@@ -380,6 +386,7 @@ program
380
386
  .option('-n, --namespace <ns>', 'The namespace that should be targeted (you can also pass a comma separated list)')
381
387
  .option('-g, --get-path <url>', `Specify the get-path url that should be used (default: ${getPathUrl})`)
382
388
  .option('-up, --unpublished <true|false>', 'Downloads the current (unpublished) translations. This will generate private download costs (default: false)', 'false')
389
+ .option('-b, --branch <branch>', 'The branch name (or id) that should be targeted')
383
390
  .option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${configInWorkingDirectory} or ${configInHome})`)
384
391
  .action((options) => {
385
392
  try {
@@ -428,6 +435,7 @@ program
428
435
  const unpublished = options.unpublished === 'true';
429
436
  const autoCreatePath = options.autoCreatePath === 'true';
430
437
  const backupDeletedPath = options.backupDeletedPath;
438
+ const branch = options.branch;
431
439
 
432
440
  sync({
433
441
  apiPath: url.parse(getPath).protocol + '//' + url.parse(getPath).host,
@@ -453,7 +461,8 @@ program
453
461
  pathMask: pathMask,
454
462
  unpublished: unpublished,
455
463
  autoCreatePath: autoCreatePath,
456
- backupDeletedPath: backupDeletedPath
464
+ backupDeletedPath: backupDeletedPath,
465
+ branch: branch
457
466
  });
458
467
  })
459
468
  .on('--help', () => {
@@ -552,6 +561,7 @@ program
552
561
  .option('-k, --api-key <apiKey>', 'The api-key that should be used')
553
562
  .option('-v, --ver <version>', 'The target version to be used to copy to (default: latest)')
554
563
  .option('-i, --project-id <projectId>', 'The project-id that should be used')
564
+ .option('-iv, --ignore-if-version-exists <true|false>', 'The project-id that should be used (default: false)', 'false')
555
565
  .option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${configInWorkingDirectory} or ${configInHome})`)
556
566
  .action((fromVersion, options) => {
557
567
  try {
@@ -576,19 +586,22 @@ program
576
586
 
577
587
  const getPath = options.getPath || config.getPath || getPathUrl;
578
588
 
589
+ const ignoreIfVersionExists = options.ignoreIfVersionExists === 'true';
590
+
579
591
  copyVersion({
580
592
  apiKey: apiKey,
581
593
  projectId: projectId,
582
594
  apiPath: url.parse(getPath).protocol + '//' + url.parse(getPath).host,
583
595
  fromVersion: fromVersion,
584
- toVersion: version
596
+ toVersion: version,
597
+ ignoreIfVersionExists: ignoreIfVersionExists
585
598
  });
586
599
  })
587
600
  .on('--help', () => {
588
601
  console.log(' Examples:');
589
602
  console.log();
590
- console.log(' $ locize copy-version latest"');
591
- console.log(' $ locize copy-version latest --ver production"');
603
+ console.log(' $ locize copy-version latest');
604
+ console.log(' $ locize copy-version latest --ver production');
592
605
  console.log(' $ locize copy-version latest --api-key <apiKey> --project-id <projectId> --ver <version>');
593
606
  console.log();
594
607
  });
@@ -631,7 +644,7 @@ program
631
644
  .on('--help', () => {
632
645
  console.log(' Examples:');
633
646
  console.log();
634
- console.log(' $ locize remove-version tmp-ver"');
647
+ console.log(' $ locize remove-version tmp-ver');
635
648
  console.log(' $ locize remove-version tmp-ver --api-key <apiKey> --project-id <projectId>');
636
649
  console.log();
637
650
  });
@@ -681,8 +694,8 @@ program
681
694
  .on('--help', () => {
682
695
  console.log(' Examples:');
683
696
  console.log();
684
- console.log(' $ locize publish-version"');
685
- console.log(' $ locize publish-version --ver production"');
697
+ console.log(' $ locize publish-version');
698
+ console.log(' $ locize publish-version --ver production');
686
699
  console.log(' $ locize publish-version --api-key <apiKey> --project-id <projectId> --ver <version>');
687
700
  console.log();
688
701
  });
@@ -777,6 +790,100 @@ program
777
790
  console.log();
778
791
  });
779
792
 
793
+ program
794
+ .command('create-branch <branch>')
795
+ .alias('cb')
796
+ .description('create branch')
797
+ .option('-k, --api-key <apiKey>', 'The api-key that should be used')
798
+ .option('-v, --ver <version>', 'The target version to be used to copy to (default: latest)')
799
+ .option('-i, --project-id <projectId>', 'The project-id that should be used')
800
+ .option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${configInWorkingDirectory} or ${configInHome})`)
801
+ .action((branch, options) => {
802
+ try {
803
+ config = ini.parse(fs.readFileSync(options.configPath, 'utf-8')) || config;
804
+ } catch (e) {}
805
+
806
+ const apiKey = options.apiKey || config.apiKey || process.env.LOCIZE_API_KEY || process.env.LOCIZE_KEY;
807
+ if (!apiKey) {
808
+ console.error(' error: missing required argument `apiKey`');
809
+ process.exit(1);
810
+ return;
811
+ }
812
+
813
+ const projectId = options.projectId || config.projectId || process.env.LOCIZE_PROJECTID || process.env.LOCIZE_PID;
814
+ if (!projectId) {
815
+ console.error(' error: missing required argument `projectId`');
816
+ process.exit(1);
817
+ return;
818
+ }
819
+
820
+ const version = options.ver || config.ver || config.version || process.env.LOCIZE_VERSION || process.env.LOCIZE_VER || 'latest';
821
+
822
+ const getPath = options.getPath || config.getPath || options.addPath || config.addPath || getPathUrl;
823
+
824
+ createBranch({
825
+ apiKey: apiKey,
826
+ projectId: projectId,
827
+ apiPath: url.parse(getPath).protocol + '//' + url.parse(getPath).host,
828
+ version: version,
829
+ branch: branch
830
+ });
831
+ })
832
+ .on('--help', () => {
833
+ console.log(' Examples:');
834
+ console.log();
835
+ console.log(' $ locize creaete-branch featureX');
836
+ console.log(' $ locize creaete-branch featureX --ver production');
837
+ console.log(' $ locize creaete-branch featureX --api-key <apiKey> --project-id <projectId> --ver <version>');
838
+ console.log();
839
+ });
840
+
841
+ program
842
+ .command('merge-branch <branch>')
843
+ .alias('mb')
844
+ .description('merge branch')
845
+ .option('-k, --api-key <apiKey>', 'The api-key that should be used')
846
+ .option('-i, --project-id <projectId>', 'The project-id that should be used')
847
+ .option('-d, --delete <true|false>', 'This will delete the branch after merging. (default: false)', 'false')
848
+ .option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${configInWorkingDirectory} or ${configInHome})`)
849
+ .action((branch, options) => {
850
+ try {
851
+ config = ini.parse(fs.readFileSync(options.configPath, 'utf-8')) || config;
852
+ } catch (e) {}
853
+
854
+ const apiKey = options.apiKey || config.apiKey || process.env.LOCIZE_API_KEY || process.env.LOCIZE_KEY;
855
+ if (!apiKey) {
856
+ console.error(' error: missing required argument `apiKey`');
857
+ process.exit(1);
858
+ return;
859
+ }
860
+
861
+ const projectId = options.projectId || config.projectId || process.env.LOCIZE_PROJECTID || process.env.LOCIZE_PID;
862
+ if (!projectId) {
863
+ console.error(' error: missing required argument `projectId`');
864
+ process.exit(1);
865
+ return;
866
+ }
867
+
868
+ const getPath = options.getPath || config.getPath || options.addPath || config.addPath || getPathUrl;
869
+
870
+ mergeBranch({
871
+ apiKey: apiKey,
872
+ projectId: projectId,
873
+ apiPath: url.parse(getPath).protocol + '//' + url.parse(getPath).host,
874
+ delete: options.delete === 'true',
875
+ branch: branch
876
+ });
877
+ })
878
+ .on('--help', () => {
879
+ console.log(' Examples:');
880
+ console.log();
881
+ console.log(' $ locize merge-branch featureX');
882
+ console.log(' $ locize merge-branch <projectId-of-branch>');
883
+ console.log(' $ locize merge-branch featureX --delete true');
884
+ console.log(' $ locize merge-branch featureX --api-key <apiKey> --project-id <projectId> --delete true');
885
+ console.log();
886
+ });
780
887
 
781
888
  program.parse(process.argv);
782
889
 
package/copyVersion.js CHANGED
@@ -3,7 +3,12 @@ const request = require('./request');
3
3
  const getJob = require('./getJob');
4
4
 
5
5
  const copyVersion = (opt, cb) => {
6
- request(opt.apiPath + '/copy/' + opt.projectId + '/version/' + opt.fromVersion + '/' + opt.toVersion, {
6
+ const queryParams = new URLSearchParams();
7
+ if (opt.ignoreIfVersionExists) {
8
+ queryParams.append('ignoreIfVersionExists', 'true');
9
+ }
10
+ const queryString = queryParams.size > 0 ? '?' + queryParams.toString() : '';
11
+ request(opt.apiPath + '/copy/' + opt.projectId + '/version/' + opt.fromVersion + '/' + opt.toVersion + queryString, {
7
12
  method: 'post',
8
13
  headers: {
9
14
  'Authorization': opt.apiKey
@@ -0,0 +1,41 @@
1
+ const colors = require('colors');
2
+ const request = require('./request');
3
+
4
+ const createBranch = (opt, cb) => {
5
+ request(opt.apiPath + '/branch/create/' + opt.projectId + '/' + opt.version, {
6
+ method: 'post',
7
+ headers: {
8
+ 'Authorization': opt.apiKey
9
+ },
10
+ body: { name: opt.branch }
11
+ }, (err, res, obj) => {
12
+ if (err || (obj && (obj.errorMessage || obj.message))) {
13
+ if (!cb) console.log(colors.red('creating branch failed...'));
14
+
15
+ if (err) {
16
+ if (!cb) { console.error(colors.red(err.message)); process.exit(1); }
17
+ if (cb) cb(err);
18
+ return;
19
+ }
20
+ if (obj && (obj.errorMessage || obj.message)) {
21
+ if (!cb) { console.error(colors.red((obj.errorMessage || obj.message))); process.exit(1); }
22
+ if (cb) cb(new Error((obj.errorMessage || obj.message)));
23
+ return;
24
+ }
25
+ }
26
+ if (res.status === 404) {
27
+ if (!cb) { console.error(colors.yellow(res.statusText + ' (' + res.status + ')')); process.exit(1); }
28
+ if (cb) cb(null, null);
29
+ return;
30
+ }
31
+ if (res.status >= 300) {
32
+ if (!cb) { console.error(colors.red(res.statusText + ' (' + res.status + ')')); process.exit(1); }
33
+ if (cb) cb(new Error(res.statusText + ' (' + res.status + ')'));
34
+ return;
35
+ }
36
+ if (!cb) console.log(colors.green('creating branch "' + obj.name + '" (' + obj.id + ') successful'));
37
+ if (cb) cb(null, obj);
38
+ });
39
+ };
40
+
41
+ module.exports = createBranch;
package/download.js CHANGED
@@ -13,6 +13,8 @@ const formats = require('./formats');
13
13
  const getProjectStats = require('./getProjectStats');
14
14
  const reversedFileExtensionsMap = formats.reversedFileExtensionsMap;
15
15
  const locize2xcstrings = require('locize-xcstrings/cjs/locize2xcstrings');
16
+ const getBranches = require('./getBranches');
17
+ const isValidUuid = require('./isValidUuid');
16
18
 
17
19
  function getInfosInUrl(download) {
18
20
  const splitted = download.key.split('/');
@@ -370,25 +372,7 @@ const filterDownloads = (opt, downloads) => {
370
372
  return filterDownloadsLanguages(opt, downloads);
371
373
  };
372
374
 
373
- const download = (opt, cb) => {
374
- opt.format = opt.format || 'json';
375
- if (!reversedFileExtensionsMap[opt.format]) {
376
- return handleError(new Error(`${opt.format} is not a valid format!`), cb);
377
- }
378
-
379
- if (opt.skipEmpty === undefined) opt.skipEmpty = true;
380
- opt.apiPath = opt.apiPath || 'https://api.locize.app';
381
- opt.version = opt.version || 'latest';
382
- opt.languageFolderPrefix = opt.languageFolderPrefix || '';
383
- opt.path = opt.path || opt.target;
384
- opt.pathMaskInterpolationPrefix = opt.pathMaskInterpolationPrefix || '{{';
385
- opt.pathMaskInterpolationSuffix = opt.pathMaskInterpolationSuffix || '}}';
386
- opt.pathMask = opt.pathMask || `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}${path.sep}${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`;
387
- opt.pathMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, `${opt.languageFolderPrefix}${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`);
388
- if (opt.unpublished && !opt.apiKey) {
389
- return handleError(new Error('Please provide also an api-key!'), cb);
390
- }
391
-
375
+ const continueToDownload = (opt, cb) => {
392
376
  var url = opt.apiPath + '/download/' + opt.projectId;
393
377
 
394
378
  if (opt.namespace && opt.namespace.indexOf(',') > 0 && opt.namespace.indexOf(' ') < 0) {
@@ -468,4 +452,44 @@ const download = (opt, cb) => {
468
452
  });
469
453
  };
470
454
 
455
+ const download = (opt, cb) => {
456
+ opt.format = opt.format || 'json';
457
+ if (!reversedFileExtensionsMap[opt.format]) {
458
+ return handleError(new Error(`${opt.format} is not a valid format!`), cb);
459
+ }
460
+
461
+ if (opt.skipEmpty === undefined) opt.skipEmpty = true;
462
+ opt.apiPath = opt.apiPath || 'https://api.locize.app';
463
+ opt.version = opt.version || 'latest';
464
+ opt.languageFolderPrefix = opt.languageFolderPrefix || '';
465
+ opt.path = opt.path || opt.target;
466
+ opt.pathMaskInterpolationPrefix = opt.pathMaskInterpolationPrefix || '{{';
467
+ opt.pathMaskInterpolationSuffix = opt.pathMaskInterpolationSuffix || '}}';
468
+ opt.pathMask = opt.pathMask || `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}${path.sep}${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`;
469
+ opt.pathMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, `${opt.languageFolderPrefix}${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`);
470
+ if (opt.unpublished && !opt.apiKey) {
471
+ return handleError(new Error('Please provide also an api-key!'), cb);
472
+ }
473
+
474
+ if (opt.branch) {
475
+ getBranches(opt, (err, branches) => {
476
+ if (err) return handleError(err, cb);
477
+
478
+ let b;
479
+ if (isValidUuid(opt.branch)) b = branches.find((br) => br.id === opt.branch);
480
+ if (!b) b = branches.find((br) => br.name === opt.branch);
481
+ if (!b) {
482
+ return handleError(new Error(`Branch ${opt.branch} not found!`), cb);
483
+ }
484
+ opt.projectId = b.id;
485
+ opt.version = b.version;
486
+
487
+ continueToDownload(opt, cb);
488
+ });
489
+ return;
490
+ }
491
+
492
+ continueToDownload(opt, cb);
493
+ };
494
+
471
495
  module.exports = download;
package/getBranches.js ADDED
@@ -0,0 +1,40 @@
1
+ const colors = require('colors');
2
+ const request = require('./request');
3
+
4
+ const getBranches = (opt, cb) => {
5
+ request(opt.apiPath + '/branches/' + 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 branches 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 branches successful'));
36
+ if (cb) cb(null, obj);
37
+ });
38
+ };
39
+
40
+ module.exports = getBranches;
package/getJob.js CHANGED
@@ -32,7 +32,7 @@ const getJob = (opt, jobId, cb) => {
32
32
  if (cb) cb(new Error(res.statusText + ' (' + res.status + ')'));
33
33
  return;
34
34
  }
35
- if (!cb) console.log(colors.green('getting job succesfull'));
35
+ if (!cb) console.log(colors.green('getting job successful'));
36
36
  if (cb) cb(null, obj);
37
37
  });
38
38
  };
@@ -32,7 +32,7 @@ const getProjectStats = (opt, cb) => {
32
32
  if (cb) cb(new Error(res.statusText + ' (' + res.status + ')'));
33
33
  return;
34
34
  }
35
- if (!cb) console.log(colors.green('getting project stats succesfull'));
35
+ if (!cb) console.log(colors.green('getting project stats successful'));
36
36
  if (cb) cb(null, obj);
37
37
  });
38
38
  };
package/isValidUuid.js ADDED
@@ -0,0 +1,2 @@
1
+ const uuidRegex = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
2
+ module.exports = (id) => uuidRegex.test(id);
package/mergeBranch.js ADDED
@@ -0,0 +1,98 @@
1
+ const colors = require('colors');
2
+ const request = require('./request');
3
+ const getBranches = require('./getBranches');
4
+ const isValidUuid = require('./isValidUuid');
5
+ const getJob = require('./getJob');
6
+
7
+ const mergeBranch = (opt, cb) => {
8
+ const queryParams = new URLSearchParams();
9
+ if (opt.delete) {
10
+ queryParams.append('delete', 'true');
11
+ }
12
+ const queryString = queryParams.size > 0 ? '?' + queryParams.toString() : '';
13
+ request(opt.apiPath + '/branch/merge/' + opt.branch + queryString, {
14
+ method: 'post',
15
+ headers: {
16
+ 'Authorization': opt.apiKey
17
+ }
18
+ }, (err, res, obj) => {
19
+ if (err || (obj && (obj.errorMessage || obj.message))) {
20
+ if (!cb) console.log(colors.red('merging branch failed...'));
21
+
22
+ if (err) {
23
+ if (!cb) { console.error(colors.red(err.message)); process.exit(1); }
24
+ if (cb) cb(err);
25
+ return;
26
+ }
27
+ if (obj && (obj.errorMessage || obj.message)) {
28
+ if (!cb) { console.error(colors.red((obj.errorMessage || obj.message))); process.exit(1); }
29
+ if (cb) cb(new Error((obj.errorMessage || obj.message)));
30
+ return;
31
+ }
32
+ }
33
+ if (res.status === 404) {
34
+ if (!cb) { console.error(colors.yellow(res.statusText + ' (' + res.status + ')')); process.exit(1); }
35
+ if (cb) cb(null, null);
36
+ return;
37
+ }
38
+ if (res.status >= 300) {
39
+ if (!cb) { console.error(colors.red(res.statusText + ' (' + res.status + ')')); process.exit(1); }
40
+ if (cb) cb(new Error(res.statusText + ' (' + res.status + ')'));
41
+ return;
42
+ }
43
+
44
+ if (!obj || !obj.jobId) {
45
+ if (!cb) { console.error(colors.red('No jobId! Something went wrong!')); process.exit(1); }
46
+ if (cb) cb(new Error('No jobId! Something went wrong!'));
47
+ return;
48
+ }
49
+
50
+ (function waitForJob() {
51
+ getJob(opt, obj.jobId, (err, job) => {
52
+ if (err) {
53
+ if (!cb) { console.error(colors.red(err.message)); process.exit(1); }
54
+ if (cb) cb(err);
55
+ return;
56
+ }
57
+
58
+ if (job && !job.timeouted) {
59
+ setTimeout(waitForJob, 2000);
60
+ return;
61
+ }
62
+
63
+ if (job && job.timeouted) {
64
+ if (!cb) { console.error(colors.red('Job timeouted!')); process.exit(1); }
65
+ if (cb) cb(new Error('Job timeouted!'));
66
+ return;
67
+ }
68
+
69
+ if (!cb) console.log(colors.green('merging branch successful'));
70
+ if (cb) cb(null);
71
+ });
72
+ })();
73
+ });
74
+ };
75
+
76
+ const handleError = (err, cb) => {
77
+ if (!cb && err) {
78
+ console.error(colors.red(err.stack));
79
+ process.exit(1);
80
+ }
81
+ if (cb) cb(err);
82
+ };
83
+
84
+ module.exports = (opt, cb) => {
85
+ getBranches(opt, (err, branches) => {
86
+ if (err) return handleError(err, cb);
87
+
88
+ let b;
89
+ if (isValidUuid(opt.branch)) b = branches.find((br) => br.id === opt.branch);
90
+ if (!b) b = branches.find((br) => br.name === opt.branch);
91
+ if (!b) {
92
+ return handleError(new Error(`Branch ${opt.branch} not found!`), cb);
93
+ }
94
+ opt.branch = b.id;
95
+
96
+ mergeBranch(opt, cb);
97
+ });
98
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locize-cli",
3
- "version": "10.0.2",
3
+ "version": "10.1.0",
4
4
  "description": "locize cli to import locales",
5
5
  "main": "index.js",
6
6
  "bin": {
package/sync.js CHANGED
@@ -18,6 +18,8 @@ const deleteNamespace = require('./deleteNamespace');
18
18
  const getProjectStats = require('./getProjectStats');
19
19
  const reversedFileExtensionsMap = formats.reversedFileExtensionsMap;
20
20
  const locize2xcstrings = require('locize-xcstrings/cjs/locize2xcstrings');
21
+ const getBranches = require('./getBranches');
22
+ const isValidUuid = require('./isValidUuid');
21
23
 
22
24
  const getDirectories = (srcpath) => {
23
25
  return fs.readdirSync(srcpath).filter((file) => {
@@ -659,6 +661,49 @@ const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
659
661
  });
660
662
  };
661
663
 
664
+ const continueToSync = (opt, cb) => {
665
+ console.log(colors.grey('checking remote (locize)...'));
666
+ getRemoteLanguages(opt, (err, remoteLanguages) => {
667
+ if (err) return handleError(err, cb);
668
+
669
+ if (opt.referenceLanguageOnly && opt.language && opt.referenceLanguage !== opt.language) {
670
+ opt.referenceLanguage = opt.language;
671
+ }
672
+ if (opt.referenceLanguageOnly && !opt.language && opt.languages && opt.languages.length > 0 && opt.languages.indexOf(opt.referenceLanguage) < 0) {
673
+ opt.referenceLanguage = opt.languages[0];
674
+ }
675
+
676
+ if (opt.referenceLanguageOnly) {
677
+ console.log(colors.grey(`checking local${opt.path !== process.cwd() ? ` (${opt.path})` : ''} only reference language...`));
678
+ parseLocalReference(opt, (err, localNamespaces) => {
679
+ if (err) return handleError(err, cb);
680
+
681
+ if (!opt.dry && opt.cleanLocalFiles) {
682
+ localNamespaces.forEach((ln) => fs.unlinkSync(ln.path));
683
+ localNamespaces = [];
684
+ }
685
+
686
+ console.log(colors.grey('calculate diffs...'));
687
+ handleSync(opt, remoteLanguages, localNamespaces, cb);
688
+ });
689
+ return;
690
+ }
691
+
692
+ console.log(colors.grey(`checking local${opt.path !== process.cwd() ? ` (${opt.path})` : ''}...`));
693
+ parseLocalLanguages(opt, remoteLanguages, (err, localNamespaces) => {
694
+ if (err) return handleError(err, cb);
695
+
696
+ if (!opt.dry && opt.cleanLocalFiles) {
697
+ localNamespaces.forEach((ln) => fs.unlinkSync(ln.path));
698
+ localNamespaces = [];
699
+ }
700
+
701
+ console.log(colors.grey('calculate diffs...'));
702
+ handleSync(opt, remoteLanguages, localNamespaces, cb);
703
+ });
704
+ });
705
+ };
706
+
662
707
  const sync = (opt, cb) => {
663
708
  opt.format = opt.format || 'json';
664
709
  if (!reversedFileExtensionsMap[opt.format]) {
@@ -695,46 +740,25 @@ const sync = (opt, cb) => {
695
740
  return handleError(new Error('Please provide also an api-key!'), cb);
696
741
  }
697
742
 
698
- console.log(colors.grey('checking remote (locize)...'));
699
- getRemoteLanguages(opt, (err, remoteLanguages) => {
700
- if (err) return handleError(err, cb);
701
-
702
- if (opt.referenceLanguageOnly && opt.language && opt.referenceLanguage !== opt.language) {
703
- opt.referenceLanguage = opt.language;
704
- }
705
- if (opt.referenceLanguageOnly && !opt.language && opt.languages && opt.languages.length > 0 && opt.languages.indexOf(opt.referenceLanguage) < 0) {
706
- opt.referenceLanguage = opt.languages[0];
707
- }
708
-
709
- if (opt.referenceLanguageOnly) {
710
- console.log(colors.grey(`checking local${opt.path !== process.cwd() ? ` (${opt.path})` : ''} only reference language...`));
711
- parseLocalReference(opt, (err, localNamespaces) => {
712
- if (err) return handleError(err, cb);
713
-
714
- if (!opt.dry && opt.cleanLocalFiles) {
715
- localNamespaces.forEach((ln) => fs.unlinkSync(ln.path));
716
- localNamespaces = [];
717
- }
718
-
719
- console.log(colors.grey('calculate diffs...'));
720
- handleSync(opt, remoteLanguages, localNamespaces, cb);
721
- });
722
- return;
723
- }
724
-
725
- console.log(colors.grey(`checking local${opt.path !== process.cwd() ? ` (${opt.path})` : ''}...`));
726
- parseLocalLanguages(opt, remoteLanguages, (err, localNamespaces) => {
743
+ if (opt.branch) {
744
+ getBranches(opt, (err, branches) => {
727
745
  if (err) return handleError(err, cb);
728
746
 
729
- if (!opt.dry && opt.cleanLocalFiles) {
730
- localNamespaces.forEach((ln) => fs.unlinkSync(ln.path));
731
- localNamespaces = [];
747
+ let b;
748
+ if (isValidUuid(opt.branch)) b = branches.find((br) => br.id === opt.branch);
749
+ if (!b) b = branches.find((br) => br.name === opt.branch);
750
+ if (!b) {
751
+ return handleError(new Error(`Branch ${opt.branch} not found!`), cb);
732
752
  }
753
+ opt.projectId = b.id;
754
+ opt.version = b.version;
733
755
 
734
- console.log(colors.grey('calculate diffs...'));
735
- handleSync(opt, remoteLanguages, localNamespaces, cb);
756
+ continueToSync(opt, cb);
736
757
  });
737
- });
758
+ return;
759
+ }
760
+
761
+ continueToSync(opt, cb);
738
762
  };
739
763
 
740
764
  module.exports = sync;