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 +1 -1
- package/README.md +2 -5
- package/package.json +5 -3
- package/src/connector.js +1 -1
- package/src/export-to-spreadsheet.js +2 -2
- package/src/handler.js +6 -3
- package/src/handlers/gettext.js +5 -0
- package/src/handlers/json_structure.js +116 -0
- package/src/handlers/locale_json.js +1 -2
- package/src/handlers/properties.js +1 -1
- package/src/handlers/yaml.js +109 -0
- package/src/util/constraints.js +4 -2
- package/src/util/file-utils.js +6 -2
- package/test/test.js +249 -15
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
|
[](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.
|
|
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": "^
|
|
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 {
|
|
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
|
-
|
|
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
|
}
|
package/src/handlers/gettext.js
CHANGED
|
@@ -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
|
+
}
|
package/src/util/constraints.js
CHANGED
|
@@ -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;
|
package/src/util/file-utils.js
CHANGED
|
@@ -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
|
|
14
|
-
const base = options.namespaces ? namespace : (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('
|
|
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
|
|
642
|
+
if (testFor === 'all' || theTest.run.indexOf(testFor) > -1) {
|
|
409
643
|
it(theTest.name, theTest.fnc);
|
|
410
644
|
}
|
|
411
645
|
}
|