@esgettext/tools 1.2.0 → 1.3.1
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/commands/add-language.js +100 -0
- package/dist/commands/convert.js +1 -1
- package/dist/commands/init.js +743 -0
- package/dist/commands/install.js +11 -3
- package/dist/commands/msgfmt-all.js +7 -4
- package/dist/commands/msgmerge-all.js +8 -4
- package/dist/commands/potfiles.js +165 -0
- package/dist/commands/xgettext.js +21 -10
- package/dist/configuration.js +140 -97
- package/dist/index.js +25 -8
- package/dist/optspec.js +28 -0
- package/dist/package.js +4 -1
- package/package.json +9 -5
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.Init = void 0;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const util = __importStar(require("util"));
|
|
42
|
+
const child_process = __importStar(require("child_process"));
|
|
43
|
+
const mkdirp = __importStar(require("mkdirp"));
|
|
44
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
45
|
+
const glob_1 = require("glob");
|
|
46
|
+
const runtime_1 = require("@esgettext/runtime");
|
|
47
|
+
const configuration_1 = require("../configuration");
|
|
48
|
+
const package_json_1 = __importDefault(require("@npmcli/package-json"));
|
|
49
|
+
const package_1 = require("../package");
|
|
50
|
+
const optspec_1 = require("../optspec");
|
|
51
|
+
const gtx = runtime_1.Textdomain.getInstance('com.cantanea.esgettext-tools');
|
|
52
|
+
class Init {
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
54
|
+
constructor(configuration) {
|
|
55
|
+
this.options = undefined;
|
|
56
|
+
this.packageJson = undefined;
|
|
57
|
+
this.configuration = configuration;
|
|
58
|
+
}
|
|
59
|
+
synopsis() {
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
description() {
|
|
63
|
+
return gtx._('Prepare a package to use esgettext.');
|
|
64
|
+
}
|
|
65
|
+
aliases() {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
args() {
|
|
69
|
+
return {
|
|
70
|
+
force: {
|
|
71
|
+
alias: 'f',
|
|
72
|
+
type: 'boolean',
|
|
73
|
+
describe: gtx._('Overwrite existing files.'),
|
|
74
|
+
},
|
|
75
|
+
'dry-run': {
|
|
76
|
+
alias: 'n',
|
|
77
|
+
type: 'boolean',
|
|
78
|
+
describe: gtx._('Just print what would be done without writing anything; implies --verbose.'),
|
|
79
|
+
},
|
|
80
|
+
verbose: {
|
|
81
|
+
alias: 'V',
|
|
82
|
+
type: 'boolean',
|
|
83
|
+
describe: gtx._('Enable verbose output'),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
88
|
+
additional(_) { }
|
|
89
|
+
init(argv) {
|
|
90
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
const options = argv;
|
|
92
|
+
this.packageJson = yield configuration_1.ConfigurationFactory.getPackageJson();
|
|
93
|
+
this.options = options;
|
|
94
|
+
if (this.options.dryRun)
|
|
95
|
+
this.options.verbose = true;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
setPrograms(config, setup) {
|
|
99
|
+
var _a, _b, _c, _d;
|
|
100
|
+
var _e, _f, _g, _h;
|
|
101
|
+
if (!config.programs)
|
|
102
|
+
config.programs = {};
|
|
103
|
+
const msgmergeOptions = setup.msgmergeOptions
|
|
104
|
+
.split(/ +/)
|
|
105
|
+
.map(option => option.replace(/^-+/, ''));
|
|
106
|
+
const msgfmtOptions = setup.msgfmtOptions
|
|
107
|
+
.split(/ +/)
|
|
108
|
+
.map(option => option.replace(/^-+/, ''));
|
|
109
|
+
if (setup.msgmerge !== 'msgmerge') {
|
|
110
|
+
(_a = (_e = config.programs).msgmerge) !== null && _a !== void 0 ? _a : (_e.msgmerge = {});
|
|
111
|
+
config.programs.msgmerge.path = setup.msgmerge;
|
|
112
|
+
}
|
|
113
|
+
else if (this.options.verbose) {
|
|
114
|
+
console.log(gtx._x("The tool '{tool}' is in your $PATH. No need to" +
|
|
115
|
+
' save it in the configuration.', { tool: 'msgmerge' }));
|
|
116
|
+
}
|
|
117
|
+
if (msgmergeOptions.length > 0) {
|
|
118
|
+
(_b = (_f = config.programs).msgmerge) !== null && _b !== void 0 ? _b : (_f.msgmerge = {});
|
|
119
|
+
config.programs.msgmerge.options = msgmergeOptions;
|
|
120
|
+
}
|
|
121
|
+
if (setup.msgfmt !== 'msgfmt') {
|
|
122
|
+
(_c = (_g = config.programs).msgfmt) !== null && _c !== void 0 ? _c : (_g.msgfmt = {});
|
|
123
|
+
config.programs.msgfmt.path = setup.msgfmt;
|
|
124
|
+
}
|
|
125
|
+
else if (this.options.verbose) {
|
|
126
|
+
console.log(gtx._x("The tool '{tool}' is in your $PATH. No need to" +
|
|
127
|
+
' save it in the configuration.', { tool: 'msgfmt' }));
|
|
128
|
+
}
|
|
129
|
+
if (msgfmtOptions.length > 0) {
|
|
130
|
+
(_d = (_h = config.programs).msgfmt) !== null && _d !== void 0 ? _d : (_h.msgfmt = {});
|
|
131
|
+
config.programs.msgfmt.options = msgfmtOptions;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
getConfiguration(setup) {
|
|
135
|
+
var _a, _b;
|
|
136
|
+
const pkg = this.packageJson;
|
|
137
|
+
const verbose = this.options.verbose;
|
|
138
|
+
if (verbose) {
|
|
139
|
+
console.log(gtx._('Setting configuration values.'));
|
|
140
|
+
}
|
|
141
|
+
// We could actually initialize this in a smarter manner by setting
|
|
142
|
+
// all properties to empty objects. But that does not compile because
|
|
143
|
+
// all of them are optiona.
|
|
144
|
+
const config = {};
|
|
145
|
+
if (!config.package)
|
|
146
|
+
config.package = {};
|
|
147
|
+
if (typeof pkg.name === 'undefined') {
|
|
148
|
+
config.package.name = setup.textdomain;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
config.package.name = pkg.name;
|
|
152
|
+
}
|
|
153
|
+
config.package.version = pkg.version;
|
|
154
|
+
config.package.textdomain = setup.textdomain;
|
|
155
|
+
let msgidBugsAddressFile = gtx._('Your input');
|
|
156
|
+
if (typeof ((_a = this.configuration.package) === null || _a === void 0 ? void 0 : _a['msgid-bugs-address']) !== 'undefined') {
|
|
157
|
+
config.package['msgid-bugs-address'] =
|
|
158
|
+
this.configuration.package['msgid-bugs-address'];
|
|
159
|
+
msgidBugsAddressFile = 'package.json: bugs';
|
|
160
|
+
}
|
|
161
|
+
let copyrightHolderFile = gtx._('Your input');
|
|
162
|
+
if (typeof ((_b = this.configuration.package) === null || _b === void 0 ? void 0 : _b['copyright-holder']) !== 'undefined') {
|
|
163
|
+
config.package['copyright-holder'] =
|
|
164
|
+
this.configuration.package['copyright-holder'];
|
|
165
|
+
copyrightHolderFile = 'package.json: people.author';
|
|
166
|
+
}
|
|
167
|
+
if (!config.po)
|
|
168
|
+
config.po = {};
|
|
169
|
+
config.po.directory = setup.poDirectory;
|
|
170
|
+
config.po.locales = [];
|
|
171
|
+
if (!config.install)
|
|
172
|
+
config.install = {};
|
|
173
|
+
config.install.directory = setup.localeDirectory;
|
|
174
|
+
this.setPrograms(config, setup);
|
|
175
|
+
if (this.options.verbose) {
|
|
176
|
+
console.log(gtx._('Validating the configuration.'));
|
|
177
|
+
}
|
|
178
|
+
if (!configuration_1.ConfigurationFactory.validate(config, {
|
|
179
|
+
jsConfigFile: gtx._('your input'),
|
|
180
|
+
msgidBugsAddressFile: msgidBugsAddressFile,
|
|
181
|
+
copyrightHolderFile: copyrightHolderFile,
|
|
182
|
+
versionFile: 'package.json',
|
|
183
|
+
nameFile: 'package.json',
|
|
184
|
+
}, runtime_1.Textdomain.locale)) {
|
|
185
|
+
this.error(gtx._('Please try again with option --verbose to see the origin of the above errors.'));
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
return config;
|
|
189
|
+
}
|
|
190
|
+
getJsonConfig(config, indent) {
|
|
191
|
+
return JSON.stringify(config, null, indent);
|
|
192
|
+
}
|
|
193
|
+
getJsConfig(config, setup, indent) {
|
|
194
|
+
var _a;
|
|
195
|
+
const header = setup.configFile === 'esgettext.config.mjs'
|
|
196
|
+
? 'export default '
|
|
197
|
+
: 'module.exports = ';
|
|
198
|
+
const comment = gtx._x('Configuration for esgettext, created by {package} {version}.', {
|
|
199
|
+
package: package_1.Package.getName(),
|
|
200
|
+
version: 'v' + package_1.Package.getVersion(),
|
|
201
|
+
});
|
|
202
|
+
const body = util.inspect(config, {
|
|
203
|
+
depth: null,
|
|
204
|
+
maxArrayLength: null,
|
|
205
|
+
maxStringLength: null,
|
|
206
|
+
});
|
|
207
|
+
const bodyLines = body.split('\n');
|
|
208
|
+
const match = bodyLines[1].match(/^(\t| *)/);
|
|
209
|
+
const bodyIndent = (_a = match === null || match === void 0 ? void 0 : match.groups) === null || _a === void 0 ? void 0 : _a[1];
|
|
210
|
+
const indentedBody = body;
|
|
211
|
+
const code = `// ${comment}\n${header} ${indentedBody}`;
|
|
212
|
+
return code.replace(new RegExp(`^${bodyIndent}`, 'gm'), indent);
|
|
213
|
+
}
|
|
214
|
+
createPODirectory(setup) {
|
|
215
|
+
if (!fs.existsSync(setup.poDirectory)) {
|
|
216
|
+
console.log(gtx._x("Creating PO directory '{directory}'."));
|
|
217
|
+
if (!this.options.dryRun) {
|
|
218
|
+
mkdirp.sync(setup.poDirectory);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (this.options.verbose) {
|
|
222
|
+
console.log(gtx._x("PO directory '{directory}' already exists."));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
writeFiles(config, setup) {
|
|
226
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
227
|
+
var _a, _b, _c, _d;
|
|
228
|
+
this.createPODirectory(setup);
|
|
229
|
+
const pkg = yield package_json_1.default.load(process.cwd());
|
|
230
|
+
const content = pkg.content;
|
|
231
|
+
const newline = content[Symbol.for('newline')];
|
|
232
|
+
const indent = content[Symbol.for('indent')];
|
|
233
|
+
let serialized;
|
|
234
|
+
if (setup.configFile === 'package.json') {
|
|
235
|
+
content.esgettext = config;
|
|
236
|
+
}
|
|
237
|
+
else if (setup.configFile === 'esgettext.config.json') {
|
|
238
|
+
serialized = this.getJsonConfig(config, indent);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
serialized = this.getJsConfig(config, setup, indent);
|
|
242
|
+
}
|
|
243
|
+
if (this.options.verbose) {
|
|
244
|
+
console.log(gtx._x("Writing configuration to '{filename}'.", {
|
|
245
|
+
filename: setup.configFile,
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
if (typeof serialized !== 'undefined' && !this.options.dryRun) {
|
|
249
|
+
const data = serialized.replace('\n', newline);
|
|
250
|
+
fs.writeFileSync(setup.configFile, data);
|
|
251
|
+
}
|
|
252
|
+
if (this.options.verbose) {
|
|
253
|
+
console.log(gtx._x("Adding package '{package}' version '{version}' as a dependency.", {
|
|
254
|
+
package: '@esgettext/runtime',
|
|
255
|
+
version: `^${package_1.Package.getVersion()}`,
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
const dependencies = Object.assign(Object.assign({}, pkg.content.dependencies), { '@esgettext/runtime': `^${package_1.Package.getVersion()}` });
|
|
259
|
+
if (this.options.verbose) {
|
|
260
|
+
console.log(gtx._x("Adding package '{package}' version {version} as a development dependencyy.", { package: '@esgettext/tools', version: `^${package_1.Package.getVersion()}` }));
|
|
261
|
+
}
|
|
262
|
+
const devDependencies = Object.assign(Object.assign({}, pkg.content.devDependencies), { '@esgettext/tools': `^${package_1.Package.getVersion()}` });
|
|
263
|
+
if (!((_a = pkg.content.devDependencies) === null || _a === void 0 ? void 0 : _a['npm-run-all']) &&
|
|
264
|
+
!((_b = pkg.content.dependencies) === null || _b === void 0 ? void 0 : _b['npm-run-all'])) {
|
|
265
|
+
if (this.options.verbose) {
|
|
266
|
+
console.log(gtx._x("Adding package '{package}' version {version} as a development dependencyy.", { package: 'npm-run-all', version: package_1.Package.getNpmRunAllVersion() }));
|
|
267
|
+
}
|
|
268
|
+
devDependencies['npm-run-all'] = package_1.Package.getNpmRunAllVersion();
|
|
269
|
+
}
|
|
270
|
+
const potfilesOptions = this.potfilesOptions(setup).join(' ');
|
|
271
|
+
let directory = setup.poDirectory;
|
|
272
|
+
if (directory.includes(' ') || directory.includes('"')) {
|
|
273
|
+
directory = `"${directory.replace(/([\\""])/g, '\\$1')}"`;
|
|
274
|
+
}
|
|
275
|
+
const scripts = Object.assign(Object.assign({}, pkg.content.scripts), { esgettext: 'npm-run-all esgettext:potfiles esgettext:extract esgettext:update-po esgettext:update-mo esgettext:install', 'esgettext:potfiles': `esgettext potfiles ${potfilesOptions} >${setup.poDirectory}/POTFILES`, 'esgettext:extract': `esgettext extract --directory ${directory} --files-from=${directory}/POTFILES`, 'esgettext:update-po': `esgettext msgmerge-all`, 'esgettext:update-mo': `esgettext msgfmt-all`, 'esgettext:install': `esgettext install`, 'esgettext:addlang': `esgettext msginit` });
|
|
276
|
+
const peerDependencies = (_c = pkg.content.peerDependencies) !== null && _c !== void 0 ? _c : undefined;
|
|
277
|
+
const optionalDependencies = (_d = pkg.content.optionalDependencies) !== null && _d !== void 0 ? _d : undefined;
|
|
278
|
+
pkg.update({
|
|
279
|
+
scripts,
|
|
280
|
+
dependencies,
|
|
281
|
+
devDependencies,
|
|
282
|
+
peerDependencies,
|
|
283
|
+
optionalDependencies,
|
|
284
|
+
});
|
|
285
|
+
if (this.options.verbose) {
|
|
286
|
+
console.log(gtx._x("Writing updated '{filename}'.", { filename: 'package.json' }));
|
|
287
|
+
}
|
|
288
|
+
if (!this.options.dryRun) {
|
|
289
|
+
yield pkg.save();
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
installDependencies(setup) {
|
|
294
|
+
const command = `${setup.packageManager} install`;
|
|
295
|
+
if (this.options.verbose) {
|
|
296
|
+
console.log(gtx._x("Run '{command}'.", { command }));
|
|
297
|
+
}
|
|
298
|
+
if (!this.options.dryRun) {
|
|
299
|
+
child_process.execSync(command, {
|
|
300
|
+
stdio: ['ignore', process.stdout, process.stderr],
|
|
301
|
+
encoding: 'utf-8',
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
nextSteps(setup) {
|
|
306
|
+
if (this.options.verbose) {
|
|
307
|
+
console.log('');
|
|
308
|
+
}
|
|
309
|
+
console.log(gtx._('The next steps are:'));
|
|
310
|
+
console.log(gtx._('1) Mark translatable strings in your code like this "gtx._(\'Hello, world!\')".'));
|
|
311
|
+
console.log(gtx._x("2) Extract strings with '{command}' into '{filename}'.", {
|
|
312
|
+
command: 'npm run esgettext:update-po',
|
|
313
|
+
filename: `${setup.poDirectory}/${setup.textdomain}.pot`,
|
|
314
|
+
}));
|
|
315
|
+
console.log(gtx._x("3) Create a translation file with '{command}' (replace 'xy' with a language code like 'de' or 'pt_BR').", {
|
|
316
|
+
command: `msginit -l xy -i ${setup.poDirectory}/${setup.textdomain}.pot -o po/xy.po`,
|
|
317
|
+
}));
|
|
318
|
+
console.log(gtx._x('4) Translate the message with a PO editor of your choice.', {
|
|
319
|
+
command: `msginit -l xy -i ${setup.poDirectory}/${setup.textdomain}.pot -o po/xy.po`,
|
|
320
|
+
}));
|
|
321
|
+
console.log(gtx._x("5) Install the translation with '{command}'.", {
|
|
322
|
+
command: 'npm run esgettext:install',
|
|
323
|
+
}));
|
|
324
|
+
console.log();
|
|
325
|
+
console.log(gtx._x("The command '{command}' executes all steps of the translation workflow at once.", { command: 'npm run esgettext' }));
|
|
326
|
+
}
|
|
327
|
+
getGitFiles() {
|
|
328
|
+
try {
|
|
329
|
+
return child_process
|
|
330
|
+
.execSync('git ls-files', {
|
|
331
|
+
stdio: 'pipe',
|
|
332
|
+
encoding: 'utf-8',
|
|
333
|
+
})
|
|
334
|
+
.split(/[\r\n]+/);
|
|
335
|
+
}
|
|
336
|
+
catch (_) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
potfilesOptions(setup) {
|
|
341
|
+
const hasNodeModules = fs.existsSync('node_modules');
|
|
342
|
+
let exclude = [];
|
|
343
|
+
if (hasNodeModules) {
|
|
344
|
+
exclude.push('node_modules');
|
|
345
|
+
}
|
|
346
|
+
if (this.options.verbose) {
|
|
347
|
+
console.log(gtx._('Analyzing source files.'));
|
|
348
|
+
}
|
|
349
|
+
if (typeof this.packageJson.main !== 'undefined' &&
|
|
350
|
+
this.packageJson.main.length) {
|
|
351
|
+
const dir = path.dirname(this.packageJson.main);
|
|
352
|
+
if (dir != '.') {
|
|
353
|
+
exclude.push(path.dirname(this.packageJson.main));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (typeof this.packageJson.module !== 'undefined' &&
|
|
357
|
+
this.packageJson.module.length) {
|
|
358
|
+
const dir = path.dirname(this.packageJson.module);
|
|
359
|
+
if (dir != '.') {
|
|
360
|
+
exclude.push(path.dirname(this.packageJson.module));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (typeof this.packageJson.browser !== 'undefined' &&
|
|
364
|
+
this.packageJson.browser.length) {
|
|
365
|
+
const dir = path.dirname(this.packageJson.browser);
|
|
366
|
+
if (dir != '.') {
|
|
367
|
+
exclude.push(path.dirname(this.packageJson.browser));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// sort | uniq for JavaScript.
|
|
371
|
+
exclude = exclude
|
|
372
|
+
.sort()
|
|
373
|
+
.filter((item, index) => {
|
|
374
|
+
return index === 0 || item !== exclude[index - 1];
|
|
375
|
+
})
|
|
376
|
+
.map(name => `${name}/**/*`);
|
|
377
|
+
let candidates = (0, glob_1.globSync)('./**/*.{js,mjs,cjs,jsx,ts,tsx}', {
|
|
378
|
+
ignore: exclude,
|
|
379
|
+
});
|
|
380
|
+
const gitFiles = this.getGitFiles();
|
|
381
|
+
if (gitFiles) {
|
|
382
|
+
if (this.options.verbose) {
|
|
383
|
+
console.log(gtx._('This is a git repo. We will only translate files under version control.'));
|
|
384
|
+
}
|
|
385
|
+
candidates = candidates.filter(filename => gitFiles.includes(filename));
|
|
386
|
+
}
|
|
387
|
+
let hasTestDir = false;
|
|
388
|
+
let hasSpec = false;
|
|
389
|
+
for (const candidate of candidates) {
|
|
390
|
+
const parts = candidate.split('/');
|
|
391
|
+
if (!hasTestDir && parts[0].match(/^tests?$/)) {
|
|
392
|
+
if (this.options.verbose) {
|
|
393
|
+
console.log(gtx._x('Looks like you have test files under {directory}. We will not translate them.'));
|
|
394
|
+
}
|
|
395
|
+
exclude.push(`${parts[0]}/*/**`);
|
|
396
|
+
hasTestDir = true;
|
|
397
|
+
}
|
|
398
|
+
if (!hasSpec && parts[parts.length - 1].match(/\.spec\./)) {
|
|
399
|
+
exclude.push(`**/*.spec.*`);
|
|
400
|
+
hasSpec = true;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const extenders = {};
|
|
404
|
+
let topLevelDirectories = candidates.map(name => {
|
|
405
|
+
var _a;
|
|
406
|
+
const parts = name.split('/');
|
|
407
|
+
const filename = parts[parts.length - 1];
|
|
408
|
+
const fparts = filename.split('.');
|
|
409
|
+
let tld;
|
|
410
|
+
if (parts.length === 1) {
|
|
411
|
+
tld = '.';
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
tld = parts[0];
|
|
415
|
+
}
|
|
416
|
+
(_a = extenders[tld]) !== null && _a !== void 0 ? _a : (extenders[tld] = []);
|
|
417
|
+
extenders[tld].push(fparts[fparts.length - 1]);
|
|
418
|
+
return tld;
|
|
419
|
+
});
|
|
420
|
+
// And make them unique.
|
|
421
|
+
topLevelDirectories = topLevelDirectories.sort().filter((item, index) => {
|
|
422
|
+
return index === 0 || item !== topLevelDirectories[index - 1];
|
|
423
|
+
});
|
|
424
|
+
const options = [`--directory=${setup.poDirectory}`];
|
|
425
|
+
if (gitFiles) {
|
|
426
|
+
options.push('--git');
|
|
427
|
+
}
|
|
428
|
+
for (const pattern of exclude) {
|
|
429
|
+
options.push(`--exclude="${pattern}"`);
|
|
430
|
+
}
|
|
431
|
+
if (!topLevelDirectories.length) {
|
|
432
|
+
this.error(gtx._x("Warning! Could not find any source files. Will use the pattern './src/**/*.{js,jsx,ts,tsx}."));
|
|
433
|
+
options.push('"./src/**/*.{js,jsx,ts,tsx}"');
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
for (const tld in extenders) {
|
|
437
|
+
let x = extenders[tld];
|
|
438
|
+
x = x.sort().filter((item, index) => {
|
|
439
|
+
return index === 0 || item !== x[index - 1];
|
|
440
|
+
});
|
|
441
|
+
if (x.length > 1) {
|
|
442
|
+
options.push(`"./${tld}/**/*.{${x.join(',')}}"`);
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
options.push(`"./${tld}/**/*.${x[0]}"`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (this.options.verbose) {
|
|
450
|
+
console.log(gtx._x('Command-line options for extracting source files are: {options}', { options: options.join(' ') }));
|
|
451
|
+
}
|
|
452
|
+
return options;
|
|
453
|
+
}
|
|
454
|
+
checkOverwrite(setup) {
|
|
455
|
+
if (this.options.force)
|
|
456
|
+
return true;
|
|
457
|
+
// The po directory are already checked.
|
|
458
|
+
const filename = setup.configFile;
|
|
459
|
+
if (filename !== 'package.json' && fs.existsSync(filename)) {
|
|
460
|
+
this.error(gtx._x("Error: The file '{filename}' already exists!", {
|
|
461
|
+
filename,
|
|
462
|
+
}));
|
|
463
|
+
this.error(gtx._x("Will not overwrite without option '{option}'.", {
|
|
464
|
+
option: '--force',
|
|
465
|
+
}));
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
const pkg = this.packageJson;
|
|
469
|
+
if (pkg.scripts) {
|
|
470
|
+
const esgettextScripts = [
|
|
471
|
+
'esgettext',
|
|
472
|
+
'esgettext:potfiles',
|
|
473
|
+
'esgettext:extract',
|
|
474
|
+
'esgettext:update-po',
|
|
475
|
+
'esgettext:update-mo',
|
|
476
|
+
'esgettext:install',
|
|
477
|
+
];
|
|
478
|
+
for (const script of esgettextScripts) {
|
|
479
|
+
if (Object.prototype.hasOwnProperty.call(pkg.scripts, script)) {
|
|
480
|
+
this.error(gtx._x("Error: The file '{filename}' already defines a script '{script}'.", { filename: 'package.json' }));
|
|
481
|
+
this.error(gtx._x("Will not overwrite without option '{option}'.", {
|
|
482
|
+
option: '--force',
|
|
483
|
+
}));
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
escapePath(name) {
|
|
491
|
+
if (name.includes(' ') || name.includes('"')) {
|
|
492
|
+
return `"${name.replace(/([\\""])/g, '\\$1')}"`;
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
return name;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
checkTool(name) {
|
|
499
|
+
return new Promise(resolve => {
|
|
500
|
+
const command = this.escapePath(name) + ' --version';
|
|
501
|
+
try {
|
|
502
|
+
child_process.execSync(command, {
|
|
503
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
504
|
+
});
|
|
505
|
+
return resolve(true);
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
return resolve(gtx._x('The command {command} did not work.' + ' Error: {error}.', {
|
|
509
|
+
command,
|
|
510
|
+
error,
|
|
511
|
+
}));
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
doRun(argv) {
|
|
516
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
517
|
+
yield this.init(argv);
|
|
518
|
+
const setup = yield this.promptUser();
|
|
519
|
+
if (!this.checkOverwrite(setup)) {
|
|
520
|
+
return 1;
|
|
521
|
+
}
|
|
522
|
+
const configuration = this.getConfiguration(setup);
|
|
523
|
+
try {
|
|
524
|
+
yield this.writeFiles(configuration, setup);
|
|
525
|
+
this.installDependencies(setup);
|
|
526
|
+
}
|
|
527
|
+
catch (error) {
|
|
528
|
+
this.error(gtx._('Error writing output:'));
|
|
529
|
+
this.error(error);
|
|
530
|
+
return 1;
|
|
531
|
+
}
|
|
532
|
+
this.nextSteps(setup);
|
|
533
|
+
return 0;
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
run(argv) {
|
|
537
|
+
return new Promise(resolve => {
|
|
538
|
+
if (!(0, optspec_1.coerceOptions)(argv, this.args())) {
|
|
539
|
+
return resolve(1);
|
|
540
|
+
}
|
|
541
|
+
this.doRun(argv)
|
|
542
|
+
.then(() => {
|
|
543
|
+
resolve(0);
|
|
544
|
+
})
|
|
545
|
+
.catch(() => {
|
|
546
|
+
resolve(1);
|
|
547
|
+
});
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
nonEmpty(answer) {
|
|
551
|
+
return new Promise(resolve => {
|
|
552
|
+
if (answer.trim().length === 0) {
|
|
553
|
+
resolve(gtx._('Please enter a string with at least one character!'));
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
resolve(true);
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
checkTextdomain(textdomain) {
|
|
561
|
+
return this.nonEmpty(textdomain)
|
|
562
|
+
.then(notEmpty => {
|
|
563
|
+
if (typeof notEmpty === 'string') {
|
|
564
|
+
return notEmpty;
|
|
565
|
+
}
|
|
566
|
+
if (textdomain.trim().match(/[/\\:]/)) {
|
|
567
|
+
return gtx._x('A valid textdomain must not contain a' +
|
|
568
|
+
" slash ('{slash}'), backslash ('{backslash}', or" +
|
|
569
|
+
" colon ('{colon}').", {
|
|
570
|
+
slash: '/',
|
|
571
|
+
backslash: '\\',
|
|
572
|
+
colon: ':',
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
})
|
|
579
|
+
.catch((error) => {
|
|
580
|
+
return gtx._x('An unknown error occurred: {error}!', { error });
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
checkDirectory(answer) {
|
|
584
|
+
return new Promise(resolve => {
|
|
585
|
+
const directory = answer.trim();
|
|
586
|
+
if (directory.length === 0) {
|
|
587
|
+
return resolve(gtx._('Please enter a string with at least one character!'));
|
|
588
|
+
}
|
|
589
|
+
if (!this.options.force) {
|
|
590
|
+
if (fs.existsSync(directory)) {
|
|
591
|
+
return resolve(gtx._x("The directory '{directory}' already exists!", {
|
|
592
|
+
directory,
|
|
593
|
+
}) +
|
|
594
|
+
' ' +
|
|
595
|
+
gtx._x("Will not overwrite without option '{option}'.", {
|
|
596
|
+
option: '--force',
|
|
597
|
+
}));
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return resolve(true);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
guessTextdomain() {
|
|
604
|
+
var _a, _b;
|
|
605
|
+
if ((_a = this.configuration.package) === null || _a === void 0 ? void 0 : _a.name) {
|
|
606
|
+
return (_b = this.configuration.package) === null || _b === void 0 ? void 0 : _b.name.replace(/^@(.+)\/(.+)/, '$1-$2');
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
guessPackageManager() {
|
|
610
|
+
if (fs.existsSync('package-lock.json')) {
|
|
611
|
+
return 'npm';
|
|
612
|
+
}
|
|
613
|
+
else if (fs.existsSync('yarn.lock')) {
|
|
614
|
+
return 'yarn';
|
|
615
|
+
}
|
|
616
|
+
else if (fs.existsSync('pnpm-lock.yaml')) {
|
|
617
|
+
return 'pnpm';
|
|
618
|
+
}
|
|
619
|
+
else if (fs.existsSync('bun.lockb')) {
|
|
620
|
+
return 'bun';
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
return 'npm';
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
guessLocaleDir() {
|
|
627
|
+
if (fs.existsSync('assets')) {
|
|
628
|
+
return 'assets/locale';
|
|
629
|
+
}
|
|
630
|
+
else if (fs.existsSync('src')) {
|
|
631
|
+
return 'src/locale';
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
return 'assets/locale';
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
guessConfigFile() {
|
|
638
|
+
if (this.packageJson.type === 'module' || this.packageJson.module) {
|
|
639
|
+
return 'esgettext.config.mjs';
|
|
640
|
+
}
|
|
641
|
+
else if (this.packageJson.type === 'commonjs') {
|
|
642
|
+
return 'esgettext.config.cjs';
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
return 'esgettext.config.json';
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
promptUser() {
|
|
649
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
650
|
+
console.log('⚡ ' +
|
|
651
|
+
gtx._("We'll prepare your package for esgettext in a few seconds."));
|
|
652
|
+
console.log('🤔 ¯\\_(ツ)_/¯ ' + gtx._('In doubt, just hit return!'));
|
|
653
|
+
console.log();
|
|
654
|
+
return {
|
|
655
|
+
textdomain: yield (0, prompts_1.input)({
|
|
656
|
+
message: gtx._('Textdomain of your package'),
|
|
657
|
+
default: this.guessTextdomain(),
|
|
658
|
+
validate: answer => this.checkTextdomain(answer),
|
|
659
|
+
}),
|
|
660
|
+
msgmerge: yield (0, prompts_1.input)({
|
|
661
|
+
message: gtx._x("The '{tool}' program to use:", { tool: 'msgmerge' }),
|
|
662
|
+
default: 'msgmerge',
|
|
663
|
+
validate: answer => this.checkTool(answer),
|
|
664
|
+
}),
|
|
665
|
+
msgmergeOptions: yield (0, prompts_1.input)({
|
|
666
|
+
message: gtx._x("(Boolean) options to invoke '{tool}' with", {
|
|
667
|
+
tool: 'msgmerge',
|
|
668
|
+
}),
|
|
669
|
+
default: '--verbose',
|
|
670
|
+
}),
|
|
671
|
+
msgfmt: yield (0, prompts_1.input)({
|
|
672
|
+
message: gtx._x("The '{tool}' program to use:", { tool: 'msgfmt' }),
|
|
673
|
+
default: 'msgfmt',
|
|
674
|
+
validate: answer => this.checkTool(answer),
|
|
675
|
+
}),
|
|
676
|
+
msgfmtOptions: yield (0, prompts_1.input)({
|
|
677
|
+
message: gtx._x("Options to invoke '{tool}' with", { tool: 'msgfmt' }),
|
|
678
|
+
default: '--check --statistics --verbose',
|
|
679
|
+
}),
|
|
680
|
+
poDirectory: yield (0, prompts_1.input)({
|
|
681
|
+
message: gtx._('Where to store translation files'),
|
|
682
|
+
default: 'po',
|
|
683
|
+
validate: answer => this.checkDirectory(answer),
|
|
684
|
+
}),
|
|
685
|
+
localeDirectory: yield (0, prompts_1.input)({
|
|
686
|
+
message: gtx._('Where to store compiled translations'),
|
|
687
|
+
default: this.guessLocaleDir(),
|
|
688
|
+
validate: answer => this.checkDirectory(answer),
|
|
689
|
+
}),
|
|
690
|
+
packageManager: yield (0, prompts_1.select)({
|
|
691
|
+
message: gtx._('Which package manager should be used'),
|
|
692
|
+
choices: [
|
|
693
|
+
{
|
|
694
|
+
name: 'npm',
|
|
695
|
+
value: 'npm',
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
name: 'yarn',
|
|
699
|
+
value: 'yarn',
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
name: 'pnpm',
|
|
703
|
+
value: 'pnpm',
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
name: 'bun',
|
|
707
|
+
value: 'bun',
|
|
708
|
+
},
|
|
709
|
+
],
|
|
710
|
+
default: this.guessPackageManager(),
|
|
711
|
+
}),
|
|
712
|
+
configFile: yield (0, prompts_1.select)({
|
|
713
|
+
message: gtx._('Where do you want to put configuration'),
|
|
714
|
+
choices: [
|
|
715
|
+
{
|
|
716
|
+
name: 'esgettext.config.mjs',
|
|
717
|
+
value: 'esgettext.config.mjs',
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
name: 'esgettext.config.cjs',
|
|
721
|
+
value: 'esgettext.config.cjs',
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
name: 'esgettext.config.json',
|
|
725
|
+
value: 'esgettext.config.json',
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
name: 'package.json',
|
|
729
|
+
value: 'package.json',
|
|
730
|
+
},
|
|
731
|
+
],
|
|
732
|
+
default: this.guessConfigFile(),
|
|
733
|
+
}),
|
|
734
|
+
};
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
error(...args) {
|
|
738
|
+
const redOn = '\x1b[31m';
|
|
739
|
+
const redOff = '\x1b[0m';
|
|
740
|
+
console.error(redOn, ...args, redOff);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
exports.Init = Init;
|