@tolgee/cli 2.8.4 → 2.10.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/dist/cli.js +116 -94
- package/dist/client/ApiClient.js +40 -32
- package/dist/client/ExportClient.js +24 -11
- package/dist/client/ImportClient.js +25 -16
- package/dist/client/TolgeeClient.js +1 -5
- package/dist/client/errorFromLoadable.js +3 -2
- package/dist/client/getApiKeyInformation.js +16 -6
- package/dist/commands/extract/check.js +38 -27
- package/dist/commands/extract/print.js +46 -35
- package/dist/commands/login.js +39 -26
- package/dist/commands/pull.js +60 -43
- package/dist/commands/push.js +167 -117
- package/dist/commands/sync/compare.js +43 -31
- package/dist/commands/sync/sync.js +118 -99
- package/dist/commands/sync/syncUtils.js +2 -1
- package/dist/commands/tag.js +52 -38
- package/dist/config/credentials.js +110 -93
- package/dist/config/tolgeerc.js +51 -35
- package/dist/extractor/extractor.js +45 -31
- package/dist/extractor/parser/extractComment.js +1 -1
- package/dist/extractor/parser/generateReport.js +8 -6
- package/dist/extractor/parser/iterator.js +2 -1
- package/dist/extractor/parser/mergerMachine.js +2 -11
- package/dist/extractor/parser/nodeUtils.js +1 -1
- package/dist/extractor/parser/parser.js +4 -2
- package/dist/extractor/parser/rules/tNsSourceGeneral.js +1 -1
- package/dist/extractor/parser/tree/getTranslateProps.js +21 -16
- package/dist/extractor/parser/tree/getValue.js +1 -1
- package/dist/extractor/parser/tree/parseTag.js +1 -1
- package/dist/extractor/parserNgx/ParserNgx.js +1 -3
- package/dist/extractor/parserNgx/ngxMapper.js +2 -1
- package/dist/extractor/parserNgx/ngxTreeTransform.js +3 -2
- package/dist/extractor/parserNgx/rules/translatePipe.js +1 -1
- package/dist/extractor/parserReact/ParserReact.js +1 -3
- package/dist/extractor/parserSvelte/ParserSvelte.js +1 -3
- package/dist/extractor/parserVue/ParserVue.js +1 -3
- package/dist/extractor/parserVue/tokenMergers/hyphenPropsMerger.js +1 -4
- package/dist/extractor/parserVue/vueTreeTransform.js +13 -2
- package/dist/extractor/runner.js +53 -39
- package/dist/extractor/tokenizer.js +50 -35
- package/dist/extractor/visualizers/printTokens.js +2 -1
- package/dist/extractor/visualizers/visualizeRules.js +4 -7
- package/dist/extractor/warnings.js +3 -2
- package/dist/extractor/worker.js +29 -16
- package/dist/options.js +2 -1
- package/dist/utils/apiKeyList.js +31 -19
- package/dist/utils/ask.js +35 -21
- package/dist/utils/checkPathNotAFile.js +22 -11
- package/dist/utils/filesTemplate.js +147 -0
- package/dist/utils/mapExportFormat.js +2 -0
- package/dist/utils/mapImportFormat.js +1 -1
- package/dist/utils/moduleLoader.js +37 -23
- package/dist/utils/prepareDir.js +20 -9
- package/dist/utils/valueToArray.js +8 -0
- package/package.json +2 -2
- package/schema.json +20 -4
@@ -1,48 +1,59 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
1
10
|
import { relative } from 'path';
|
2
11
|
import { Command } from 'commander';
|
3
12
|
import { extractKeysOfFiles } from '../../extractor/runner.js';
|
4
13
|
import { WarningMessages } from '../../extractor/warnings.js';
|
5
14
|
import { loading } from '../../utils/logger.js';
|
6
|
-
const printHandler = (config) =>
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
const printHandler = (config) => function () {
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
17
|
+
const opts = this.optsWithGlobals();
|
18
|
+
const extracted = yield loading('Analyzing code...', extractKeysOfFiles(opts));
|
19
|
+
let warningCount = 0;
|
20
|
+
const keySet = new Set();
|
21
|
+
for (const [file, { keys, warnings }] of extracted) {
|
22
|
+
if (keys.length) {
|
23
|
+
const relFile = relative(process.cwd(), file);
|
24
|
+
console.log('%d key%s found in %s:', keys.length, keys.length !== 1 ? 's' : '', relFile);
|
25
|
+
for (const key of keys) {
|
26
|
+
keySet.add(key);
|
27
|
+
console.log('\tline %d: %s', key.line, key.keyName);
|
28
|
+
if (key.namespace) {
|
29
|
+
console.log('\t\tnamespace: %s', key.namespace);
|
30
|
+
}
|
31
|
+
if (key.defaultValue) {
|
32
|
+
console.log('\t\tdefault: %s', key.defaultValue);
|
33
|
+
}
|
23
34
|
}
|
24
35
|
}
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
if (warnings === null || warnings === void 0 ? void 0 : warnings.length) {
|
37
|
+
warningCount += warnings.length;
|
38
|
+
console.log('%d warning%s %s emitted during extraction:', warnings.length, warnings.length !== 1 ? 's' : '', warnings.length !== 1 ? 'were' : 'was');
|
39
|
+
for (const warning of warnings) {
|
40
|
+
if (warning.warning in WarningMessages) {
|
41
|
+
const warn = warning.warning;
|
42
|
+
const { name } = WarningMessages[warn];
|
43
|
+
console.log('\tline %d: %s', warning.line, name);
|
44
|
+
}
|
45
|
+
else {
|
46
|
+
console.log('\tline %d: %s', warning.line, warning.warning);
|
47
|
+
}
|
37
48
|
}
|
38
49
|
}
|
50
|
+
if (keys.length || (warnings === null || warnings === void 0 ? void 0 : warnings.length)) {
|
51
|
+
console.log();
|
52
|
+
}
|
39
53
|
}
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
}
|
44
|
-
console.log('Total unique keys found: %d', keySet.size);
|
45
|
-
console.log('Total warnings: %d', warningCount);
|
54
|
+
console.log('Total unique keys found: %d', keySet.size);
|
55
|
+
console.log('Total warnings: %d', warningCount);
|
56
|
+
});
|
46
57
|
};
|
47
58
|
export default (config) => new Command('print')
|
48
59
|
.description('Prints extracted data to the console')
|
package/dist/commands/login.js
CHANGED
@@ -1,36 +1,49 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
1
10
|
import { Command } from 'commander';
|
2
11
|
import ansi from 'ansi-colors';
|
3
12
|
import { saveApiKey, removeApiKeys, clearAuthStore, } from '../config/credentials.js';
|
4
13
|
import { exitWithError, success } from '../utils/logger.js';
|
5
14
|
import { createTolgeeClient } from '../client/TolgeeClient.js';
|
6
15
|
import { printApiKeyLists } from '../utils/apiKeyList.js';
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
function loginHandler(key) {
|
17
|
+
return __awaiter(this, void 0, void 0, function* () {
|
18
|
+
const opts = this.optsWithGlobals();
|
19
|
+
if (opts.list) {
|
20
|
+
printApiKeyLists();
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
else if (!key) {
|
24
|
+
exitWithError('Missing argument [API Key]');
|
25
|
+
}
|
26
|
+
const keyInfo = yield createTolgeeClient({
|
27
|
+
baseUrl: opts.apiUrl.toString(),
|
28
|
+
apiKey: key,
|
29
|
+
}).getApiKeyInfo();
|
30
|
+
yield saveApiKey(opts.apiUrl, keyInfo);
|
31
|
+
success(keyInfo.type === 'PAK'
|
32
|
+
? `Logged in as ${keyInfo.username} on ${ansi.blue(opts.apiUrl.hostname)} for project ${ansi.blue(String(keyInfo.project.id))} (${keyInfo.project.name}). Welcome back!`
|
33
|
+
: `Logged in as ${keyInfo.username} on ${ansi.blue(opts.apiUrl.hostname)}. Welcome back!`);
|
34
|
+
});
|
24
35
|
}
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
36
|
+
function logoutHandler() {
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
38
|
+
const opts = this.optsWithGlobals();
|
39
|
+
if (opts.all) {
|
40
|
+
yield clearAuthStore();
|
41
|
+
success("You've been logged out of all Tolgee instances you were logged in.");
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
yield removeApiKeys(opts.apiUrl);
|
45
|
+
success(`You're now logged out of ${opts.apiUrl.hostname}.`);
|
46
|
+
});
|
34
47
|
}
|
35
48
|
export const Login = new Command()
|
36
49
|
.name('login')
|
package/dist/commands/pull.js
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
1
10
|
import { Command, Option } from 'commander';
|
2
11
|
import { unzipBuffer } from '../utils/zip.js';
|
3
12
|
import { prepareDir } from '../utils/prepareDir.js';
|
@@ -5,49 +14,57 @@ import { exitWithError, loading, success } from '../utils/logger.js';
|
|
5
14
|
import { checkPathNotAFile } from '../utils/checkPathNotAFile.js';
|
6
15
|
import { mapExportFormat } from '../utils/mapExportFormat.js';
|
7
16
|
import { handleLoadableError } from '../client/TolgeeClient.js';
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
format,
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
function fetchZipBlob(opts) {
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
19
|
+
var _a;
|
20
|
+
const exportFormat = mapExportFormat(opts.format);
|
21
|
+
const { format, messageFormat } = exportFormat;
|
22
|
+
const loadable = yield opts.client.export.export({
|
23
|
+
format,
|
24
|
+
messageFormat,
|
25
|
+
supportArrays: opts.supportArrays,
|
26
|
+
languages: opts.languages,
|
27
|
+
filterState: opts.states,
|
28
|
+
structureDelimiter: (_a = opts.delimiter) !== null && _a !== void 0 ? _a : '',
|
29
|
+
filterNamespace: opts.namespaces,
|
30
|
+
filterTagIn: opts.tags,
|
31
|
+
filterTagNotIn: opts.excludeTags,
|
32
|
+
fileStructureTemplate: opts.fileStructureTemplate,
|
33
|
+
});
|
34
|
+
handleLoadableError(loadable);
|
35
|
+
return loadable.data;
|
22
36
|
});
|
23
|
-
handleLoadableError(loadable);
|
24
|
-
return loadable.data;
|
25
37
|
}
|
26
|
-
const pullHandler = () =>
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
38
|
+
const pullHandler = () => function () {
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
40
|
+
const opts = this.optsWithGlobals();
|
41
|
+
if (!opts.path) {
|
42
|
+
exitWithError('Missing option --path <path> or `pull.path` in tolgee config');
|
43
|
+
}
|
44
|
+
yield checkPathNotAFile(opts.path);
|
45
|
+
const zipBlob = yield loading('Fetching strings from Tolgee...', fetchZipBlob(opts));
|
46
|
+
yield prepareDir(opts.path, opts.emptyDir);
|
47
|
+
yield loading('Extracting strings...', unzipBuffer(zipBlob, opts.path));
|
48
|
+
success('Done!');
|
49
|
+
});
|
50
|
+
};
|
51
|
+
export default (config) => {
|
52
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
53
|
+
return new Command()
|
54
|
+
.name('pull')
|
55
|
+
.description('Pulls translations from Tolgee')
|
56
|
+
.addOption(new Option('--path <path>', 'Destination of a folder where translation files will be stored in').default((_a = config.pull) === null || _a === void 0 ? void 0 : _a.path))
|
57
|
+
.addOption(new Option('-l, --languages <languages...>', 'List of languages to pull. Leave unspecified to export them all').default((_b = config.pull) === null || _b === void 0 ? void 0 : _b.languages))
|
58
|
+
.addOption(new Option('-s, --states <states...>', 'List of translation states to include. Defaults all except untranslated')
|
59
|
+
.choices(['UNTRANSLATED', 'TRANSLATED', 'REVIEWED'])
|
60
|
+
.default((_c = config.pull) === null || _c === void 0 ? void 0 : _c.states)
|
61
|
+
.argParser((v, a) => [v.toUpperCase(), ...(a || [])]))
|
62
|
+
.addOption(new Option('-d, --delimiter <delimiter>', 'Structure delimiter to use. By default, Tolgee interprets `.` as a nested structure. You can change the delimiter, or disable structure formatting by not specifying any value to the option').default(((_d = config.pull) === null || _d === void 0 ? void 0 : _d.delimiter) === undefined ? '.' : config.pull.delimiter))
|
63
|
+
.addOption(new Option('-n, --namespaces <namespaces...>', 'List of namespaces to pull. Defaults to all namespaces').default((_e = config.pull) === null || _e === void 0 ? void 0 : _e.namespaces))
|
64
|
+
.addOption(new Option('-t, --tags <tags...>', 'List of tags which to include. Keys tagged by at least one of these tags will be included.').default((_f = config.pull) === null || _f === void 0 ? void 0 : _f.tags))
|
65
|
+
.addOption(new Option('--exclude-tags <tags...>', 'List of tags which to exclude. Keys tagged by at least one of these tags will be excluded.').default((_g = config.pull) === null || _g === void 0 ? void 0 : _g.excludeTags))
|
66
|
+
.addOption(new Option('--support-arrays', 'Export keys with array syntax (e.g. item[0]) as arrays.').default((_j = (_h = config.pull) === null || _h === void 0 ? void 0 : _h.supportArrays) !== null && _j !== void 0 ? _j : false))
|
67
|
+
.addOption(new Option('--empty-dir', 'Empty target directory before inserting pulled files.').default((_k = config.pull) === null || _k === void 0 ? void 0 : _k.emptyDir))
|
68
|
+
.addOption(new Option('--file-structure-template <template>', 'Defines exported file structure: https://tolgee.io/tolgee-cli/push-pull-strings#file-structure-template-format').default((_l = config.pull) === null || _l === void 0 ? void 0 : _l.fileStructureTemplate))
|
69
|
+
.action(pullHandler());
|
36
70
|
};
|
37
|
-
export default (config) => new Command()
|
38
|
-
.name('pull')
|
39
|
-
.description('Pulls translations from Tolgee')
|
40
|
-
.addOption(new Option('--path <path>', 'Destination of a folder where translation files will be stored in').default(config.pull?.path))
|
41
|
-
.addOption(new Option('-l, --languages <languages...>', 'List of languages to pull. Leave unspecified to export them all').default(config.pull?.languages))
|
42
|
-
.addOption(new Option('-s, --states <states...>', 'List of translation states to include. Defaults all except untranslated')
|
43
|
-
.choices(['UNTRANSLATED', 'TRANSLATED', 'REVIEWED'])
|
44
|
-
.default(config.pull?.states)
|
45
|
-
.argParser((v, a) => [v.toUpperCase(), ...(a || [])]))
|
46
|
-
.addOption(new Option('-d, --delimiter <delimiter>', 'Structure delimiter to use. By default, Tolgee interprets `.` as a nested structure. You can change the delimiter, or disable structure formatting by not specifying any value to the option').default(config.pull?.delimiter === undefined ? '.' : config.pull.delimiter))
|
47
|
-
.addOption(new Option('-n, --namespaces <namespaces...>', 'List of namespaces to pull. Defaults to all namespaces').default(config.pull?.namespaces))
|
48
|
-
.addOption(new Option('-t, --tags <tags...>', 'List of tags which to include. Keys tagged by at least one of these tags will be included.').default(config.pull?.tags))
|
49
|
-
.addOption(new Option('--exclude-tags <tags...>', 'List of tags which to exclude. Keys tagged by at least one of these tags will be excluded.').default(config.pull?.excludeTags))
|
50
|
-
.addOption(new Option('--support-arrays', 'Export keys with array syntax (e.g. item[0]) as arrays.').default(config.pull?.supportArrays ?? false))
|
51
|
-
.addOption(new Option('--empty-dir', 'Empty target directory before inserting pulled files.').default(config.pull?.emptyDir))
|
52
|
-
.addOption(new Option('--file-structure-template <template>', 'Defines exported file structure: https://tolgee.io/tolgee-cli/push-pull-strings#file-structure-template-format').default(config.pull?.fileStructureTemplate))
|
53
|
-
.action(pullHandler());
|
package/dist/commands/push.js
CHANGED
@@ -1,140 +1,190 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
1
10
|
import { extname, join } from 'path';
|
2
11
|
import { readdir, readFile, stat } from 'fs/promises';
|
3
12
|
import { Command, Option } from 'commander';
|
4
13
|
import { glob } from 'tinyglobby';
|
14
|
+
import { exit } from 'process';
|
5
15
|
import { loading, success, error, warn, exitWithError, } from '../utils/logger.js';
|
6
16
|
import { askString } from '../utils/ask.js';
|
7
17
|
import { mapImportFormat } from '../utils/mapImportFormat.js';
|
8
18
|
import { handleLoadableError } from '../client/TolgeeClient.js';
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
19
|
+
import { findFilesByTemplate } from '../utils/filesTemplate.js';
|
20
|
+
import { valueToArray } from '../utils/valueToArray.js';
|
21
|
+
function allInPattern(pattern) {
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
23
|
+
const files = [];
|
24
|
+
const items = yield glob(pattern);
|
25
|
+
for (const item of items) {
|
26
|
+
if ((yield stat(item)).isDirectory()) {
|
27
|
+
files.push(...(yield readDirectory(item)));
|
28
|
+
}
|
29
|
+
else {
|
30
|
+
const blob = yield readFile(item);
|
31
|
+
files.push({ name: item, data: blob });
|
32
|
+
}
|
15
33
|
}
|
16
|
-
|
17
|
-
|
18
|
-
|
34
|
+
return files;
|
35
|
+
});
|
36
|
+
}
|
37
|
+
function readDirectory(directory_1) {
|
38
|
+
return __awaiter(this, arguments, void 0, function* (directory, base = '') {
|
39
|
+
const files = [];
|
40
|
+
const dir = yield readdir(directory);
|
41
|
+
for (const file of dir) {
|
42
|
+
const filePath = join(directory, file);
|
43
|
+
const fileStat = yield stat(filePath);
|
44
|
+
if (fileStat.isDirectory()) {
|
45
|
+
const dirFiles = yield readDirectory(filePath, `${file}/`);
|
46
|
+
files.push(...dirFiles);
|
47
|
+
}
|
48
|
+
else {
|
49
|
+
const blob = yield readFile(filePath);
|
50
|
+
files.push({ name: base + file, data: blob });
|
51
|
+
}
|
19
52
|
}
|
20
|
-
|
21
|
-
|
53
|
+
return files;
|
54
|
+
});
|
22
55
|
}
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
const filePath = join(directory, file);
|
28
|
-
const fileStat = await stat(filePath);
|
29
|
-
if (fileStat.isDirectory()) {
|
30
|
-
const dirFiles = await readDirectory(filePath, `${file}/`);
|
31
|
-
files.push(...dirFiles);
|
56
|
+
function promptConflicts(opts) {
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
58
|
+
if (opts.forceMode === 'NO_FORCE') {
|
59
|
+
exitWithError(`There are conflicts in the import and the force mode is set to "NO_FORCE". Set it to "KEEP" or "OVERRIDE" to continue.`);
|
32
60
|
}
|
33
|
-
|
34
|
-
|
35
|
-
files.push({ name: base + file, data: blob });
|
61
|
+
if (opts.forceMode) {
|
62
|
+
return opts.forceMode;
|
36
63
|
}
|
37
|
-
|
38
|
-
|
39
|
-
}
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
return
|
46
|
-
}
|
47
|
-
if (!process.stdout.isTTY) {
|
48
|
-
exitWithError(`There are conflicts in the import. Please specify a --force-mode.`);
|
49
|
-
}
|
50
|
-
warn('There are conflicts in the import. What do you want to do?');
|
51
|
-
const resp = await askString('Type "KEEP" to preserve the version on the server, "OVERRIDE" to use the version from the import, and nothing to abort: ');
|
52
|
-
if (resp !== 'KEEP' && resp !== 'OVERRIDE') {
|
53
|
-
exitWithError(`Aborting.`);
|
54
|
-
}
|
55
|
-
return resp;
|
64
|
+
if (!process.stdout.isTTY) {
|
65
|
+
exitWithError(`There are conflicts in the import. Please specify a --force-mode.`);
|
66
|
+
}
|
67
|
+
warn('There are conflicts in the import. What do you want to do?');
|
68
|
+
const resp = yield askString('Type "KEEP" to preserve the version on the server, "OVERRIDE" to use the version from the import, and nothing to abort: ');
|
69
|
+
if (resp !== 'KEEP' && resp !== 'OVERRIDE') {
|
70
|
+
exitWithError(`Aborting.`);
|
71
|
+
}
|
72
|
+
return resp;
|
73
|
+
});
|
56
74
|
}
|
57
|
-
|
58
|
-
return
|
75
|
+
function importData(client, data) {
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
77
|
+
return loading('Uploading files...', client.import.import(data));
|
78
|
+
});
|
59
79
|
}
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
const
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
data: file.data,
|
68
|
-
name: file.name,
|
80
|
+
function readRecords(matchers) {
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
82
|
+
const result = [];
|
83
|
+
for (const matcher of matchers) {
|
84
|
+
const files = yield allInPattern(matcher.path);
|
85
|
+
files.forEach((file) => {
|
86
|
+
result.push(Object.assign(Object.assign({}, matcher), { data: file.data, name: file.name }));
|
69
87
|
});
|
70
|
-
}
|
71
|
-
|
72
|
-
|
88
|
+
}
|
89
|
+
return result;
|
90
|
+
});
|
91
|
+
}
|
92
|
+
function handleMappingError(fileMappings) {
|
93
|
+
error('Not able to map files to existing languages in the platform');
|
94
|
+
console.log(`Pushed files:`);
|
95
|
+
fileMappings.forEach(({ fileName, languageTag }) => {
|
96
|
+
console.log(`"${fileName}"${languageTag ? ` => "${languageTag}"` : ''}`);
|
97
|
+
});
|
98
|
+
console.log('\nYou can use `push.files[*].language` property in `tolgeerc` file to map language correctly');
|
99
|
+
exit(1);
|
73
100
|
}
|
74
|
-
const pushHandler = (config) =>
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
if (
|
81
|
-
|
101
|
+
const pushHandler = (config) => function () {
|
102
|
+
return __awaiter(this, void 0, void 0, function* () {
|
103
|
+
var _a, _b, _c, _d;
|
104
|
+
const opts = this.optsWithGlobals();
|
105
|
+
let allMatchers = [];
|
106
|
+
const filesTemplate = opts.filesTemplate;
|
107
|
+
if (!filesTemplate && !((_b = (_a = config.push) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b.length)) {
|
108
|
+
exitWithError('Missing option `push.filesTemplate` or `push.files`.');
|
82
109
|
}
|
83
|
-
if (
|
84
|
-
|
110
|
+
if (filesTemplate) {
|
111
|
+
for (const template of filesTemplate) {
|
112
|
+
allMatchers = allMatchers.concat(...(yield findFilesByTemplate(template)));
|
113
|
+
}
|
85
114
|
}
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
format: format,
|
104
|
-
languageTag: f.language,
|
105
|
-
namespace: f.namespace ?? '',
|
106
|
-
};
|
107
|
-
}),
|
108
|
-
removeOtherKeys: opts.removeOtherKeys,
|
109
|
-
};
|
110
|
-
const attempt1 = await loading('Importing...', importData(opts.client, {
|
111
|
-
files,
|
112
|
-
params,
|
113
|
-
}));
|
114
|
-
if (attempt1.error) {
|
115
|
-
if (attempt1.error.code !== 'conflict_is_not_resolved') {
|
116
|
-
handleLoadableError(attempt1);
|
115
|
+
allMatchers = allMatchers.concat(...(((_c = config.push) === null || _c === void 0 ? void 0 : _c.files) || []));
|
116
|
+
const filteredMatchers = allMatchers.filter((r) => {
|
117
|
+
var _a;
|
118
|
+
if (r.language &&
|
119
|
+
opts.languages &&
|
120
|
+
!opts.languages.includes(r.language)) {
|
121
|
+
return false;
|
122
|
+
}
|
123
|
+
if (opts.namespaces && !opts.namespaces.includes((_a = r.namespace) !== null && _a !== void 0 ? _a : '')) {
|
124
|
+
return false;
|
125
|
+
}
|
126
|
+
return true;
|
127
|
+
});
|
128
|
+
const files = yield loading('Reading files...', readRecords(filteredMatchers));
|
129
|
+
if (files.length === 0) {
|
130
|
+
error('Nothing to import.');
|
131
|
+
return;
|
117
132
|
}
|
118
|
-
const
|
119
|
-
|
133
|
+
const params = {
|
134
|
+
createNewKeys: true,
|
135
|
+
forceMode: opts.forceMode,
|
136
|
+
overrideKeyDescriptions: opts.overrideKeyDescriptions,
|
137
|
+
convertPlaceholdersToIcu: opts.convertPlaceholdersToIcu,
|
138
|
+
tagNewKeys: (_d = opts.tagNewKeys) !== null && _d !== void 0 ? _d : [],
|
139
|
+
fileMappings: files.map((f) => {
|
140
|
+
var _a;
|
141
|
+
const format = mapImportFormat(opts.format, extname(f.name));
|
142
|
+
return {
|
143
|
+
fileName: f.name,
|
144
|
+
format: format,
|
145
|
+
languageTag: f.language,
|
146
|
+
namespace: (_a = f.namespace) !== null && _a !== void 0 ? _a : '',
|
147
|
+
languageTagsToImport: opts.languages,
|
148
|
+
};
|
149
|
+
}),
|
150
|
+
removeOtherKeys: opts.removeOtherKeys,
|
151
|
+
};
|
152
|
+
const attempt1 = yield loading('Importing...', importData(opts.client, {
|
120
153
|
files,
|
121
|
-
params
|
154
|
+
params,
|
122
155
|
}));
|
123
|
-
|
124
|
-
|
125
|
-
|
156
|
+
if (attempt1.error) {
|
157
|
+
if (attempt1.error.code === 'existing_language_not_selected') {
|
158
|
+
handleMappingError(params.fileMappings);
|
159
|
+
}
|
160
|
+
if (attempt1.error.code !== 'conflict_is_not_resolved') {
|
161
|
+
handleLoadableError(attempt1);
|
162
|
+
}
|
163
|
+
const forceMode = yield promptConflicts(opts);
|
164
|
+
const attempt2 = yield loading('Overriding...', importData(opts.client, {
|
165
|
+
files,
|
166
|
+
params: Object.assign(Object.assign({}, params), { forceMode }),
|
167
|
+
}));
|
168
|
+
handleLoadableError(attempt2);
|
169
|
+
}
|
170
|
+
success('Done!');
|
171
|
+
});
|
172
|
+
};
|
173
|
+
export default (config) => {
|
174
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
175
|
+
return new Command()
|
176
|
+
.name('push')
|
177
|
+
.description('Pushes translations to Tolgee')
|
178
|
+
.addOption(new Option('-ft, --files-template <templates...>', 'A template that describes the structure of the local files and their location with file structure template format (more at: https://docs.tolgee.io/tolgee-cli/push-pull-strings#file-structure-template-format).\n\nExample: `./public/{namespace}/{languageTag}.json`\n\n').default(valueToArray((_a = config.push) === null || _a === void 0 ? void 0 : _a.filesTemplate)))
|
179
|
+
.addOption(new Option('-f, --force-mode <mode>', 'What should we do with possible conflicts? If unspecified, the user will be prompted interactively, or the command will fail when in non-interactive')
|
180
|
+
.choices(['OVERRIDE', 'KEEP', 'NO_FORCE'])
|
181
|
+
.argParser((v) => v.toUpperCase())
|
182
|
+
.default((_b = config.push) === null || _b === void 0 ? void 0 : _b.forceMode))
|
183
|
+
.addOption(new Option('--override-key-descriptions', 'Override existing key descriptions from local files (only relevant for some formats).').default((_d = (_c = config.push) === null || _c === void 0 ? void 0 : _c.overrideKeyDescriptions) !== null && _d !== void 0 ? _d : true))
|
184
|
+
.addOption(new Option('--convert-placeholders-to-icu', 'Convert placeholders in local files to ICU format.').default((_f = (_e = config.push) === null || _e === void 0 ? void 0 : _e.convertPlaceholdersToIcu) !== null && _f !== void 0 ? _f : true))
|
185
|
+
.addOption(new Option('-l, --languages <languages...>', 'Specifies which languages should be pushed (see push.files in config).').default((_g = config.push) === null || _g === void 0 ? void 0 : _g.languages))
|
186
|
+
.addOption(new Option('-n, --namespaces <namespaces...>', 'Specifies which namespaces should be pushed (see push.files in config).').default((_h = config.push) === null || _h === void 0 ? void 0 : _h.namespaces))
|
187
|
+
.addOption(new Option('--tag-new-keys <tags...>', 'Specify tags that will be added to newly created keys.').default((_j = config.push) === null || _j === void 0 ? void 0 : _j.tagNewKeys))
|
188
|
+
.addOption(new Option('--remove-other-keys', 'Remove keys which are not present in the import.').default((_k = config.push) === null || _k === void 0 ? void 0 : _k.removeOtherKeys))
|
189
|
+
.action(pushHandler(config));
|
126
190
|
};
|
127
|
-
export default (config) => new Command()
|
128
|
-
.name('push')
|
129
|
-
.description('Pushes translations to Tolgee')
|
130
|
-
.addOption(new Option('-f, --force-mode <mode>', 'What should we do with possible conflicts? If unspecified, the user will be prompted interactively, or the command will fail when in non-interactive')
|
131
|
-
.choices(['OVERRIDE', 'KEEP', 'NO_FORCE'])
|
132
|
-
.argParser((v) => v.toUpperCase())
|
133
|
-
.default(config.push?.forceMode))
|
134
|
-
.addOption(new Option('--override-key-descriptions', 'Override existing key descriptions from local files (only relevant for some formats).').default(config.push?.overrideKeyDescriptions ?? true))
|
135
|
-
.addOption(new Option('--convert-placeholders-to-icu', 'Convert placeholders in local files to ICU format.').default(config.push?.convertPlaceholdersToIcu ?? true))
|
136
|
-
.addOption(new Option('-l, --languages <languages...>', 'Specifies which languages should be pushed (see push.files in config).').default(config.push?.languages))
|
137
|
-
.addOption(new Option('-n, --namespaces <namespaces...>', 'Specifies which namespaces should be pushed (see push.files in config).').default(config.push?.namespaces))
|
138
|
-
.addOption(new Option('--tag-new-keys <tags...>', 'Specify tags that will be added to newly created keys.').default(config.push?.tagNewKeys))
|
139
|
-
.addOption(new Option('--remove-other-keys', 'Remove keys which are not present in the import.').default(config.push?.removeOtherKeys))
|
140
|
-
.action(pushHandler(config));
|