google-spreadsheet-translation-sync 1.2.7 → 1.3.6

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/Gruntfile.js CHANGED
@@ -75,7 +75,7 @@ module.exports = function(grunt) {
75
75
  shell: {
76
76
  publish_npm: {
77
77
  command: [
78
- 'npmrc public', // well, this is at the moment hardcoded to my personal public registry name
78
+ // 'npmrc public', // well, this is at the moment hardcoded to my personal public registry name
79
79
  'npm publish'
80
80
  ].join('&&')
81
81
  },
package/README.md CHANGED
@@ -2,10 +2,6 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/Andreas-Schoenefeldt/node-google-spreadsheet-translation-sync.svg?branch=master)](https://travis-ci.org/Andreas-Schoenefeldt/node-google-spreadsheet-translation-sync)
4
4
 
5
- > WARNING: This relies at the moment on a php script to parse the translation files. It was just more easy, to start off with my existing utilities. Please open a issue on github, if you want to give it a try, then I migrate.
6
- >
7
- > So long I'll just happy use it as it is for myself :)
8
-
9
5
  A plugin to read and write i18n translations from and to google spreadsheets
10
6
 
11
7
  ## Installation
@@ -91,7 +87,8 @@ Type: `Enum`
91
87
  Possible Values:
92
88
  * `locale_json` (translations are stored in simple key/value json files)
93
89
  * `gettext` (utilizes [node gettext-parser](https://github.com/smhg/gettext-parser) for the work with po and mo files)
94
- * `properties` (utilizes [propertie-reader](https://github.com/steveukx/properties) for java property files)
90
+ * `properties` (utilizes [propertie-reader](https://github.com/steveukx/properties) for java property files)
91
+ * `yml` (utilizes [js-yaml](https://github.com/nodeca/js-yaml) for symfony yaml translation files)
95
92
  Default value: `locale_json`
96
93
 
97
94
  Please feel free to create a PR or open an issue, if you need an additional translation format.
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "google-spreadsheet-translation-sync",
3
- "version": "1.2.7",
3
+ "version": "1.3.6",
4
4
  "description": "A plugin to read and write i18n translationsfrom and to google spreadsheets ",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "mocha --reporter spec"
7
+ "test": "mocha --reporter spec",
8
+ "build": "grunt build"
8
9
  },
9
10
  "repository": {
10
11
  "type": "git",
@@ -43,9 +44,10 @@
43
44
  },
44
45
  "dependencies": {
45
46
  "async": "^2.6.3",
46
- "fast-csv": "^2.5.0",
47
+ "fast-csv": "^4.3",
47
48
  "gettext-parser": "^4.0.2",
48
49
  "google-spreadsheet": "^3.0.11",
50
+ "js-yaml": "^4.1.0",
49
51
  "mkdirp": "^0.5.5",
50
52
  "properties-reader": "github:Andreas-Schoenefeldt/properties#master",
51
53
  "shelljs": "^0.7.8",
package/src/connector.js CHANGED
@@ -28,7 +28,7 @@ module.exports = function (sheetId, worksheetId, credentials, callback) {
28
28
  throw new Error('The sheet with the gid ' + sheetId + ' does not exist.');
29
29
  }
30
30
 
31
- console.log('Loaded doc: ' + doc.title + ' with ' + sheet.rowCount + ' rows');
31
+ // console.log('Loaded doc: ' + doc.title + ' with ' + sheet.rowCount + ' rows');
32
32
 
33
33
  callback(null, sheet);
34
34
  },
@@ -62,7 +62,7 @@ module.exports = function (translationFiles, options, callback) {
62
62
  localeKey = matches[3];
63
63
  }
64
64
  } else {
65
- localeKey = fileName.substr(options.fileBaseName.length);
65
+ localeKey = fileName.substr(options.fileBaseName.length + (options.namespaceSeparator ? options.namespaceSeparator.length : 0));
66
66
  }
67
67
 
68
68
  if (dataHeaderIndexMap[namespace] === undefined) {
@@ -199,7 +199,7 @@ module.exports = function (translationFiles, options, callback) {
199
199
  }
200
200
  }
201
201
 
202
- console.log(`Uploading rows ${rowIndexStart} - ${Math.min(rowIndexRunMax, data.length)}`);
202
+ // console.log(`Uploading rows ${rowIndexStart} - ${Math.min(rowIndexRunMax, data.length)}`);
203
203
 
204
204
  sheet.saveUpdatedCells().then(function () {
205
205
 
package/src/handler.js CHANGED
@@ -1,10 +1,9 @@
1
1
  'use strict'
2
2
 
3
-
4
3
  /**
5
4
  *
6
5
  * @param translationFormat
7
- * @return {TranslationHandler}
6
+ * @return {{loadTranslationFile: function, getTranslationKeys: function, updateTranslations: function}}
8
7
  */
9
8
  module.exports.getHandler = function (translationFormat) {
10
9
 
@@ -13,12 +12,16 @@ module.exports.getHandler = function (translationFormat) {
13
12
  switch (translationFormat) {
14
13
  default:
15
14
  throw new Error('No handler available for the translation format ' + translationFormat);
16
- break;
15
+ case TRANSLATION_FORMATS.JSON_STRUCTURE:
16
+ return require('./handlers/json_structure');
17
17
  case TRANSLATION_FORMATS.LOCALE_JSON:
18
18
  return require('./handlers/locale_json');
19
19
  case TRANSLATION_FORMATS.GETTEXT:
20
20
  return require('./handlers/gettext');
21
21
  case TRANSLATION_FORMATS.PROPERTIES:
22
22
  return require('./handlers/properties');
23
+ case 'yaml':
24
+ case TRANSLATION_FORMATS.YAML:
25
+ return require('./handlers/yaml');
23
26
  }
24
27
  }
@@ -26,6 +26,11 @@ module.exports.loadTranslationFile = function (filePath, callback) {
26
26
  });
27
27
  }
28
28
 
29
+ /**
30
+ * A wrapper to return a flat key: value object structure, used for uploading
31
+ * @param filePath
32
+ * @param callback
33
+ */
29
34
  module.exports.getTranslationKeys = function (filePath, callback) {
30
35
 
31
36
  const translations = {};
@@ -0,0 +1,116 @@
1
+ 'use strict'
2
+
3
+ const fs = require('fs');
4
+ const withoutError = require('../helpers').withoutError
5
+ const constraints = require('../util/constraints');
6
+
7
+ module.exports.loadTranslationFile = function (filePath, callback) {
8
+
9
+ fs.access(filePath, function (err) {
10
+
11
+ if (err) {
12
+ callback({}); // we return the empty json
13
+ } else {
14
+
15
+ fs.readFile(filePath, function (err, data) {
16
+ callback(err ? {} : JSON.parse(data));
17
+ })
18
+ }
19
+ });
20
+ }
21
+
22
+ /**
23
+ * A wrapper to return a flat key: value object structure, used for uploading
24
+ * @param {string} filePath
25
+ * @param {function} callback
26
+ */
27
+ module.exports.getTranslationKeys = function (filePath, callback) {
28
+ const result = {};
29
+
30
+ const keyFlattener = function(structure, prefix) {
31
+ prefix = prefix || '';
32
+
33
+ Object.keys(structure).forEach((key) => {
34
+
35
+ const subStructure = structure[key];
36
+
37
+ if (typeof subStructure === 'object' && subStructure !== null && subStructure !== undefined) {
38
+ keyFlattener(subStructure, prefix + key + '.');
39
+ } else {
40
+ result[prefix + key] = subStructure;
41
+ }
42
+ })
43
+
44
+ }
45
+
46
+ this.loadTranslationFile(filePath, (parsedObject) => {
47
+ keyFlattener(parsedObject);
48
+ callback(result);
49
+ });
50
+ }
51
+
52
+ module.exports.updateTranslations = function (translationData, translationRootFolder, options, callback) {
53
+ const path = require('path');
54
+ const async = require('async');
55
+ const mod = this;
56
+ const fileUtils = require('../util/file-utils');
57
+
58
+ if (! fs.existsSync(translationRootFolder)) {
59
+ throw new Error('The folder ' + translationRootFolder + ' does not exist');
60
+ }
61
+
62
+ async.each(Object.keys(translationData), function(locale, done) {
63
+
64
+ // is it a comment or a real translation?
65
+ if (locale.substr(0, constraints.commentCollumnName.length) !== constraints.commentCollumnName) {
66
+
67
+ async.each(Object.keys(translationData[locale]), function (namespace, done2) {
68
+
69
+ const localeFileName = fileUtils.buildTranslationFileName(constraints.TRANSLATION_FORMATS.JSON_STRUCTURE, namespace, locale, options);
70
+ const file = path.resolve(translationRootFolder + '/' + localeFileName);
71
+
72
+ mod.loadTranslationFile(file, function (translations) {
73
+ const potentiallyUpdatedTranslations = translationData[locale][namespace];
74
+
75
+ Object.keys(potentiallyUpdatedTranslations).forEach((key) => {
76
+ const parts = key.split('.');
77
+ let tree = translations;
78
+
79
+ while (parts.length > 0) {
80
+ const part = parts.shift();
81
+
82
+ if (parts.length === 0) {
83
+ tree[part] = potentiallyUpdatedTranslations[key];
84
+ } else {
85
+ if (!tree[part]) {
86
+ tree[part] = {}
87
+ }
88
+
89
+ tree = tree[part];
90
+ }
91
+ }
92
+ });
93
+
94
+ // now we write
95
+ fs.writeFile(file, JSON.stringify(translations, null, 4), function (err) {
96
+ if (withoutError(err)) {
97
+ // console.info('Updated translations of %o', localeFileName);
98
+ }
99
+ done2();
100
+ })
101
+ })
102
+ }, function () {
103
+ done();
104
+ })
105
+
106
+ } else {
107
+ done();
108
+ }
109
+ }, function (err) {
110
+ if (withoutError(err, callback)) {
111
+ callback(null);
112
+ }
113
+ });
114
+
115
+
116
+ }
@@ -17,11 +17,10 @@ module.exports.loadTranslationFile = function (filePath, callback) {
17
17
  })
18
18
  }
19
19
  });
20
-
21
20
  }
22
21
 
23
22
  /**
24
- * A wrapper to return a key: value object structure
23
+ * A wrapper to return a flat key: value object structure, used for uploading
25
24
  * @param {string} filePath
26
25
  * @param {function} callback
27
26
  */
@@ -10,7 +10,7 @@ module.exports.loadTranslationFile = function (filePath, callback) {
10
10
  }
11
11
 
12
12
  /**
13
- * A wrapper to return a key: value object structure
13
+ * A wrapper to return a flat key: value object structure, used for uploading
14
14
  * @param {string} filePath
15
15
  * @param {function} callback
16
16
  */
@@ -0,0 +1,109 @@
1
+ const fs = require("fs");
2
+ const yaml = require('js-yaml');
3
+ const constraints = require("../util/constraints");
4
+ const {withoutError} = require("../helpers");
5
+
6
+ module.exports.loadTranslationFile = function (filePath, callback) {
7
+ if (fs.existsSync(filePath)) {
8
+ callback(yaml.load(fs.readFileSync(filePath)));
9
+ } else {
10
+ callback({}); // empty object, if teh file does not exist
11
+ }
12
+ }
13
+
14
+ /**
15
+ * A wrapper to return a flat key: value object structure, used for uploading
16
+ * @param {string} filePath
17
+ * @param {function} callback
18
+ */
19
+ module.exports.getTranslationKeys = function (filePath, callback) {
20
+ const result = {};
21
+
22
+ const keyFlattener = function(structure, prefix) {
23
+ prefix = prefix || '';
24
+
25
+ Object.keys(structure).forEach((key) => {
26
+
27
+ const subStructure = structure[key];
28
+
29
+ if (typeof subStructure === 'object' && subStructure !== null && subStructure !== undefined) {
30
+ keyFlattener(subStructure, prefix + key + '.');
31
+ } else {
32
+ result[prefix + key] = subStructure;
33
+ }
34
+ })
35
+
36
+ }
37
+
38
+ this.loadTranslationFile(filePath, (parsedObject) => {
39
+ keyFlattener(parsedObject);
40
+ callback(result);
41
+ });
42
+ }
43
+
44
+
45
+ module.exports.updateTranslations = function (translationData, translationRootFolder, options, callback) {
46
+ const path = require('path');
47
+ const async = require('async');
48
+ const mod = this;
49
+ const fileUtils = require('../util/file-utils');
50
+
51
+ if (! fs.existsSync(translationRootFolder)) {
52
+ throw new Error('The folder ' + translationRootFolder + ' does not exist');
53
+ }
54
+
55
+ async.each(Object.keys(translationData), function(locale, done) {
56
+
57
+ // is it a comment or a real translation?
58
+ if (locale.substr(0, constraints.commentCollumnName.length) !== constraints.commentCollumnName) {
59
+
60
+ async.each(Object.keys(translationData[locale]), function (namespace, done2) {
61
+
62
+ const localeFileName = fileUtils.buildTranslationFileName(constraints.TRANSLATION_FORMATS.YAML, namespace, locale, options);
63
+ const file = path.resolve(translationRootFolder + '/' + localeFileName);
64
+
65
+ mod.loadTranslationFile(file, function (translations) {
66
+ const potentiallyUpdatedTranslations = translationData[locale][namespace];
67
+
68
+ Object.keys(potentiallyUpdatedTranslations).forEach((key) => {
69
+ const parts = key.split('.');
70
+ let tree = translations;
71
+
72
+ while (parts.length > 0) {
73
+ const part = parts.shift();
74
+
75
+ if (parts.length === 0) {
76
+ tree[part] = potentiallyUpdatedTranslations[key];
77
+ } else {
78
+ if (!tree[part]) {
79
+ tree[part] = {}
80
+ }
81
+
82
+ tree = tree[part];
83
+ }
84
+ }
85
+ });
86
+
87
+ // now we write
88
+ fs.writeFile(file, yaml.dump(translations, {indent: 4}), function (err) {
89
+ if (withoutError(err)) {
90
+ // console.info('Updated translations of %o', localeFileName);
91
+ }
92
+ done2();
93
+ })
94
+ })
95
+ }, function () {
96
+ done();
97
+ })
98
+
99
+ } else {
100
+ done();
101
+ }
102
+ }, function (err) {
103
+ if (withoutError(err, callback)) {
104
+ callback(null);
105
+ }
106
+ });
107
+
108
+
109
+ }
@@ -1,7 +1,9 @@
1
1
  const formats = {
2
- LOCALE_JSON: 'locale_json',
2
+ LOCALE_JSON: 'locale_json', // just a plain array - lorem.ipsum keys will be {'lorem.ipsum': 'whatever'}
3
+ JSON_STRUCTURE: 'json_structure', // lorem.ipsum keys will be converted into a json structure: {lorem: {ipsum: 'whatever'}}
3
4
  GETTEXT: 'gettext',
4
- PROPERTIES: 'properties'
5
+ PROPERTIES: 'properties',
6
+ YAML: 'yml'
5
7
  };
6
8
 
7
9
  module.exports.TRANSLATION_FORMATS = formats;
@@ -10,8 +10,8 @@ const constraints = require('./constraints');
10
10
  * @returns {string}
11
11
  */
12
12
  module.exports.buildTranslationFileName = function (format, namespace, locale, options) {
13
- const namespaceSeparator = options.namespaceSeparator ? options.namespaceSeparator : '-';
14
- const base = options.namespaces ? namespace : (options.fileBaseName ? options.fileBaseName : '');
13
+ const namespaceSeparator = options.namespaceSeparator || '-';
14
+ const base = options.namespaces ? namespace : (options.fileBaseName || '');
15
15
  let extension;
16
16
 
17
17
  switch (format) {
@@ -19,11 +19,15 @@ module.exports.buildTranslationFileName = function (format, namespace, locale, o
19
19
  throw new Error('Unknown extension for translation format ' + format);
20
20
  break;
21
21
  case constraints.TRANSLATION_FORMATS.LOCALE_JSON:
22
+ case constraints.TRANSLATION_FORMATS.JSON_STRUCTURE:
22
23
  extension = 'json';
23
24
  break;
24
25
  case constraints.TRANSLATION_FORMATS.GETTEXT:
25
26
  extension = 'po';
26
27
  break;
28
+ case constraints.TRANSLATION_FORMATS.YAML:
29
+ extension = 'yml';
30
+ break;
27
31
  case constraints.TRANSLATION_FORMATS.PROPERTIES:
28
32
 
29
33
  if (options.defaultLocaleName === locale) {
package/test/test.js CHANGED
@@ -13,6 +13,7 @@ const testSheetId = '1ZJK1G_3wrEo9lnu1FenjOzSy3uoAi-RLWbph1cI6DWI';
13
13
  const testWorksheetId = '1209225803';
14
14
  const testSheetId_gettext = '1CRvX4TCxUGCcs_MtKC5BdEViHYzYzLXdqtbuVaAXfKc';
15
15
  const testSheetId_properties = '1Z0Mpbf6lgdGiuiHlpb9DENVfKxkxSRwcfQEDYrgokEE';
16
+ const testSheetId_yaml = '1Ml3jLK6RgbPQ4e7XZpILvB-XWMeziHpwdxS8r4AYNtE';
16
17
  const timeout = 20000;
17
18
 
18
19
  // preparations
@@ -20,12 +21,15 @@ const timeout = 20000;
20
21
  var tmpFile = tmp.fileSync({postfix: '.csv'});
21
22
 
22
23
  const csv = require('fast-csv');
24
+ const fileUtils = require("../src/util/file-utils");
25
+ const yamlHandler = require("../src/handlers/yaml");
26
+ const rimraf = require("rimraf");
27
+ const yaml = require("js-yaml");
23
28
  const testFile = tmpFile.name;
24
- const targetPath = path.basename(testFile);
25
29
  const csvData = [
26
30
  ['key', 'default', 'de', 'it', 'fr', 'pl', 'hu'],
27
31
  ['additional.news.' + Math.round(Math.random() * 10000), 'Additional News', null, null, null, 'czecz ' + Math.round(Math.random() * 10000), 'Elfogadom'],
28
- ['some.key', 'a Key ' + Math.round(Math.random() * 10000), 'ein Schlüssel ' + Math.round(Math.random() * 10000)]
32
+ ['some.key', 'a Key ' + Math.round(Math.random() * 10000), 'ein Schlüssel ' + Math.round(Math.random() * 10000)],
29
33
  ];
30
34
 
31
35
  // this provokes the "Cannot read property 'toLocaleLowerCase' of undefined" ERROR
@@ -36,6 +40,7 @@ frOnlyLine2[4] = 'bon!';
36
40
 
37
41
  csvData.push(frOnlyLine);
38
42
  csvData.push(frOnlyLine2);
43
+ csvData.push(['some.other', 'with : colon', 'mit : Doppelpunkt']);
39
44
 
40
45
 
41
46
  csv.writeToPath(
@@ -44,19 +49,22 @@ csv.writeToPath(
44
49
 
45
50
  function ensureFolder (folder) {
46
51
  if (!fs.existsSync(folder)){
47
- fs.mkdirSync(folder);
52
+ fs.mkdirSync(folder, {
53
+ recursive: true
54
+ });
48
55
  }
49
56
  return folder;
50
57
  }
51
58
 
52
59
 
53
- // const testFor = 'all' // 'connect', 'upload', 'import'
60
+ // const testFor = 'all' // 'connect', 'upload', 'import', 'properties', 'locale_json', 'gettext', 'yml', 'json_structure'
61
+ // const testFor = 'json_structure';
54
62
  const testFor = 'all';
55
63
 
56
64
  const tests = [
57
65
  {
58
66
  name: 'should connect to the test google doc',
59
- run: 'connect',
67
+ run: ['connect'],
60
68
  fnc: function (done) {
61
69
  this.timeout(timeout);
62
70
 
@@ -76,7 +84,7 @@ const tests = [
76
84
 
77
85
  {
78
86
  name: 'should not connect with wrong credentials',
79
- run: 'connect',
87
+ run: ['connect'],
80
88
  fnc: function (done) {
81
89
  this.timeout(timeout);
82
90
 
@@ -89,7 +97,7 @@ const tests = [
89
97
 
90
98
  {
91
99
  name: 'should connect to a specific sheet',
92
- run: 'connect',
100
+ run: ['connect'],
93
101
  fnc: function (done) {
94
102
  this.timeout(timeout);
95
103
 
@@ -115,7 +123,7 @@ const tests = [
115
123
 
116
124
  {
117
125
  name: 'should upload changes in the namespace properties test project',
118
- run: 'upload',
126
+ run: ['upload', 'properties'],
119
127
  fnc: function (done) {
120
128
 
121
129
  const PropertiesReader = require('properties-reader');
@@ -226,7 +234,7 @@ const tests = [
226
234
 
227
235
  {
228
236
  name: 'should upload changes in the json test project',
229
- run: 'upload',
237
+ run: ['upload', 'locale_json'],
230
238
  fnc: function (done) {
231
239
  this.timeout(timeout);
232
240
 
@@ -294,7 +302,7 @@ const tests = [
294
302
 
295
303
  {
296
304
  name: 'should import updated properties keys in the test project',
297
- run: 'import',
305
+ run: ['import', 'properties'],
298
306
  fnc: function (done) {
299
307
  this.timeout(timeout);
300
308
 
@@ -332,7 +340,7 @@ const tests = [
332
340
 
333
341
  {
334
342
  name: 'should import updated locale_json keys in the test project',
335
- run: 'import',
343
+ run: ['import', 'locale_json'],
336
344
  fnc: function (done) {
337
345
  this.timeout(timeout);
338
346
 
@@ -362,7 +370,7 @@ const tests = [
362
370
 
363
371
  {
364
372
  name: 'should import updated gettext keys in the test project',
365
- run: 'import',
373
+ run: ['import', 'gettext'],
366
374
  fnc: function (done) {
367
375
  this.timeout(timeout);
368
376
 
@@ -395,17 +403,243 @@ const tests = [
395
403
  done();
396
404
  });
397
405
  }
398
- }
406
+ },
407
+
408
+ {
409
+ name: 'should upload changes in the yaml test project',
410
+ run: ['upload', 'yml'],
411
+ fnc: function (done) {
412
+ this.timeout(timeout);
413
+
414
+ const baseName = 'messages';
415
+
416
+ const fs = require('fs');
417
+ const options = {
418
+ translationFormat: 'yml',
419
+ fileBaseName: baseName,
420
+ keyId: csvData[0][0],
421
+ gid: 0,
422
+ namespaceSeparator: '.',
423
+ spreadsheetId: testSheetId,
424
+ credentials: accessData
425
+ }
426
+
427
+ const files = [];
428
+
429
+ const tempFolder = tmp.dirSync({prefix: 'trans-dyn-to-update'});
430
+ const yamlHandler = require('../src/handlers/yaml');
431
+ const fileUtils = require('../src/util/file-utils');
432
+
433
+ const data = {};
434
+
435
+ csvData[0].forEach( function (key, index) {
436
+
437
+ if (index > 0) {
438
+ data[key] = {default: {}}
439
+ csvData.forEach(function (lines, i) {
440
+ if (i > 0 && lines[index]) {
441
+ data[key].default[lines[0]] = lines[index];
442
+ }
443
+ });
444
+ files.push(tempFolder.name + '/' + fileUtils.buildTranslationFileName(options.translationFormat, null, key, options));
445
+ }
446
+ });
447
+
448
+ yamlHandler.updateTranslations(data, tempFolder.name, options, () => {
449
+
450
+ app.exportToSpreadsheet(files, options, function (err) {
451
+ const rimraf = require("rimraf");
452
+ expect(err).to.be.null;
453
+
454
+ if (!err) {
455
+ connector(options.spreadsheetId, options.gid, accessData, function (err, sheet) {
456
+ expect(err).to.be.null;
457
+ expect(sheet).to.be.an('object');
458
+
459
+ sheet.getRows({
460
+ offset: 0,
461
+ limit: csvData.length - 1
462
+ }).then(function (rows) {
463
+ expect(rows).to.have.lengthOf(csvData.length - 1);
464
+ expect(rows[0][options.keyId]).to.equal(csvData[1][0]);
465
+ expect(rows[0].pl).to.equal(csvData[1][5]);
466
+ expect(rows[0].default).to.equal(csvData[1][1]);
467
+ expect(rows[0].hu).to.equal('Elfogadom'); // this was not part of the upload and should not be overwrittem
468
+ expect(rows[1].default).to.equal(csvData[2][1]);
469
+ expect(rows[1].de).to.equal(csvData[2][2]);
470
+ expect(rows[1].key).to.equal(csvData[2][0]);
471
+ rimraf.sync(tempFolder.name);
472
+ done()
473
+ })
474
+ })
475
+ } else {
476
+ rimraf.sync(tempFolder.name);
477
+ done()
478
+ }
479
+ })
480
+ });
481
+ }
482
+ },
483
+
484
+ {
485
+ name: 'should import updated yml keys in the test project',
486
+ run: ['import', 'yml'],
487
+ fnc: function (done) {
488
+ this.timeout(timeout);
489
+
490
+ const baseName = 'messages';
491
+
492
+ const options = {
493
+ translationFormat: 'yml',
494
+ fileBaseName: baseName,
495
+ namespaceSeparator: '.',
496
+ spreadsheetId: testSheetId_yaml,
497
+ credentials: accessData
498
+ };
499
+
500
+ const translationRoot = ensureFolder(path.resolve('./test/translations/' + options.translationFormat + '/'));
501
+ const testFile = path.resolve(translationRoot + '/' + baseName + '.en.yml');
502
+
503
+ app.importFromSpreadsheet(translationRoot, options, function (err) {
504
+ expect(err).to.be.null
505
+
506
+ if (!err) {
507
+ const yaml = require('js-yaml');
508
+ const fs = require('fs');
509
+
510
+ expect(fs.existsSync(testFile)).to.equal(true);
511
+
512
+ const translations = yaml.load(fs.readFileSync(testFile, 'utf8'));
513
+
514
+ expect(translations.add_address).to.equal("Add new address");
515
+ expect(translations.additional.news).to.equal("Additional News");
516
+ }
517
+ done();
518
+ });
519
+ }
520
+ },
521
+
522
+ {
523
+ name: 'should upload changes in the json_structure test project',
524
+ run: ['upload', 'json_structure'],
525
+ fnc: function (done) {
526
+ this.timeout(timeout);
527
+
528
+ const baseName = 'messages';
529
+
530
+ const options = {
531
+ translationFormat: 'json_structure',
532
+ fileBaseName: baseName,
533
+ keyId: csvData[0][0],
534
+ gid: 0,
535
+ namespaceSeparator: '.',
536
+ spreadsheetId: testSheetId,
537
+ credentials: accessData
538
+ }
539
+
540
+ const files = [];
541
+
542
+ const tempFolder = tmp.dirSync({prefix: 'trans-dyn-to-update'});
543
+ const handler = require('../src/handlers/json_structure');
544
+ const fileUtils = require('../src/util/file-utils');
545
+
546
+ const data = {};
547
+
548
+ csvData[0].forEach( function (key, index) {
549
+
550
+ if (index > 0) {
551
+ data[key] = {default: {}}
552
+ csvData.forEach(function (lines, i) {
553
+ if (i > 0 && lines[index]) {
554
+ data[key].default[lines[0]] = lines[index];
555
+ }
556
+ });
557
+ files.push(tempFolder.name + '/' + fileUtils.buildTranslationFileName(options.translationFormat, null, key, options));
558
+ }
559
+ });
560
+
561
+ handler.updateTranslations(data, tempFolder.name, options, () => {
562
+
563
+ app.exportToSpreadsheet(files, options, function (err) {
564
+ const rimraf = require("rimraf");
565
+ expect(err).to.be.null;
566
+
567
+ if (!err) {
568
+ connector(options.spreadsheetId, options.gid, accessData, function (err, sheet) {
569
+ expect(err).to.be.null;
570
+ expect(sheet).to.be.an('object');
571
+
572
+ sheet.getRows({
573
+ offset: 0,
574
+ limit: csvData.length - 1
575
+ }).then(function (rows) {
576
+ expect(rows).to.have.lengthOf(csvData.length - 1);
577
+ expect(rows[0][options.keyId]).to.equal(csvData[1][0]);
578
+ expect(rows[0].pl).to.equal(csvData[1][5]);
579
+ expect(rows[0].default).to.equal(csvData[1][1]);
580
+ expect(rows[0].hu).to.equal('Elfogadom'); // this was not part of the upload and should not be overwrittem
581
+ expect(rows[1].default).to.equal(csvData[2][1]);
582
+ expect(rows[1].de).to.equal(csvData[2][2]);
583
+ expect(rows[1].key).to.equal(csvData[2][0]);
584
+ rimraf.sync(tempFolder.name);
585
+ done()
586
+ })
587
+ })
588
+ } else {
589
+ rimraf.sync(tempFolder.name);
590
+ done()
591
+ }
592
+ })
593
+ });
594
+ }
595
+ },
596
+
597
+ {
598
+ name: 'should import updated json_structure keys from the test project',
599
+ run: ['import', 'json_structure'],
600
+ fnc: function (done) {
601
+ this.timeout(timeout);
602
+
603
+ const baseName = 'messages';
604
+
605
+ const options = {
606
+ translationFormat: 'json_structure',
607
+ fileBaseName: baseName,
608
+ namespaceSeparator: '.',
609
+ spreadsheetId: testSheetId_yaml,
610
+ credentials: accessData
611
+ };
612
+
613
+ const translationRoot = ensureFolder(path.resolve('./test/translations/' + options.translationFormat + '/'));
614
+ const testFile = path.resolve(translationRoot + '/' + baseName + '.en.json');
615
+
616
+ app.importFromSpreadsheet(translationRoot, options, function (err) {
617
+ expect(err).to.be.null
618
+
619
+ if (!err) {
620
+ const fs = require('fs');
621
+
622
+ expect(fs.existsSync(testFile)).to.equal(true);
623
+
624
+ const translations = require(testFile);
625
+
626
+ expect(translations.add_address).to.equal("Add new address");
627
+ expect(translations.additional.news).to.equal("Additional News");
628
+ }
629
+ done();
630
+ });
631
+ }
632
+ },
399
633
  ];
400
634
 
401
635
 
402
636
  // run the test
403
- describe('#Export', function () {
637
+ describe('Running ' + testFor + ' tests', function () {
404
638
 
405
639
  for (let i = 0; i < tests.length; i++) {
406
640
  const theTest = tests[i];
407
641
 
408
- if (testFor === 'all' || theTest.run === testFor) {
642
+ if (testFor === 'all' || theTest.run.indexOf(testFor) > -1) {
409
643
  it(theTest.name, theTest.fnc);
410
644
  }
411
645
  }