@red-hat-developer-hub/translations-cli 0.0.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/CHANGELOG.md +7 -0
- package/bin/translations-cli +34 -0
- package/dist/commands/clean.cjs.js +130 -0
- package/dist/commands/deploy.cjs.js +53 -0
- package/dist/commands/download.cjs.js +304 -0
- package/dist/commands/generate.cjs.js +1294 -0
- package/dist/commands/index.cjs.js +146 -0
- package/dist/commands/init.cjs.js +115 -0
- package/dist/commands/list.cjs.js +178 -0
- package/dist/commands/setupMemsource.cjs.js +338 -0
- package/dist/commands/status.cjs.js +40 -0
- package/dist/commands/sync.cjs.js +226 -0
- package/dist/commands/upload.cjs.js +506 -0
- package/dist/index.cjs.js +30 -0
- package/dist/lib/errors.cjs.js +36 -0
- package/dist/lib/i18n/analyzeStatus.cjs.js +79 -0
- package/dist/lib/i18n/config.cjs.js +256 -0
- package/dist/lib/i18n/deployTranslations.cjs.js +1213 -0
- package/dist/lib/i18n/extractKeys.cjs.js +418 -0
- package/dist/lib/i18n/formatReport.cjs.js +138 -0
- package/dist/lib/i18n/generateFiles.cjs.js +94 -0
- package/dist/lib/i18n/loadFile.cjs.js +93 -0
- package/dist/lib/i18n/mergeFiles.cjs.js +126 -0
- package/dist/lib/i18n/uploadCache.cjs.js +83 -0
- package/dist/lib/i18n/validateFile.cjs.js +189 -0
- package/dist/lib/paths.cjs.js +51 -0
- package/dist/lib/utils/exec.cjs.js +41 -0
- package/dist/lib/utils/translationUtils.cjs.js +33 -0
- package/dist/lib/version.cjs.js +38 -0
- package/package.json +65 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var path = require('node:path');
|
|
4
|
+
var os = require('node:os');
|
|
5
|
+
var readline = require('node:readline');
|
|
6
|
+
var process$1 = require('process');
|
|
7
|
+
var chalk = require('chalk');
|
|
8
|
+
var fs = require('fs-extra');
|
|
9
|
+
|
|
10
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
11
|
+
|
|
12
|
+
function _interopNamespaceCompat(e) {
|
|
13
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
14
|
+
var n = Object.create(null);
|
|
15
|
+
if (e) {
|
|
16
|
+
Object.keys(e).forEach(function (k) {
|
|
17
|
+
if (k !== 'default') {
|
|
18
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
19
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return e[k]; }
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
n.default = e;
|
|
27
|
+
return Object.freeze(n);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
31
|
+
var os__default = /*#__PURE__*/_interopDefaultCompat(os);
|
|
32
|
+
var readline__namespace = /*#__PURE__*/_interopNamespaceCompat(readline);
|
|
33
|
+
var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
|
|
34
|
+
var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
35
|
+
|
|
36
|
+
function isInteractiveTerminal() {
|
|
37
|
+
return process$1.stdin.isTTY && process$1.stdout.isTTY;
|
|
38
|
+
}
|
|
39
|
+
async function promptUsername(rl) {
|
|
40
|
+
const question = (query) => {
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
rl.question(query, resolve);
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const username = await question(chalk__default.default.yellow("Enter Memsource username: "));
|
|
46
|
+
if (!username || username.trim() === "") {
|
|
47
|
+
rl.close();
|
|
48
|
+
throw new Error("Username is required");
|
|
49
|
+
}
|
|
50
|
+
return username;
|
|
51
|
+
}
|
|
52
|
+
async function promptPassword(rl) {
|
|
53
|
+
const questionPassword = (query) => {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const wasRawMode = process$1.stdin.isRaw || false;
|
|
56
|
+
if (process$1.stdin.isTTY) {
|
|
57
|
+
process$1.stdin.setRawMode(true);
|
|
58
|
+
}
|
|
59
|
+
process$1.stdin.resume();
|
|
60
|
+
process$1.stdin.setEncoding("utf8");
|
|
61
|
+
process$1.stdout.write(query);
|
|
62
|
+
let inputPassword = "";
|
|
63
|
+
let cleanup;
|
|
64
|
+
const onData = (char) => {
|
|
65
|
+
if (char === "\r" || char === "\n") {
|
|
66
|
+
cleanup();
|
|
67
|
+
process$1.stdout.write("\n");
|
|
68
|
+
resolve(inputPassword);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (char === "") {
|
|
72
|
+
cleanup();
|
|
73
|
+
process$1.stdout.write("\n");
|
|
74
|
+
process.exit(130);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (char === "\x7F" || char === "\b" || char === "\x1B[3~") {
|
|
78
|
+
if (inputPassword.length > 0) {
|
|
79
|
+
inputPassword = inputPassword.slice(0, -1);
|
|
80
|
+
process$1.stdout.write("\b \b");
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
inputPassword += char;
|
|
88
|
+
process$1.stdout.write("*");
|
|
89
|
+
};
|
|
90
|
+
cleanup = () => {
|
|
91
|
+
process$1.stdin.removeListener("data", onData);
|
|
92
|
+
if (process$1.stdin.isTTY) {
|
|
93
|
+
process$1.stdin.setRawMode(wasRawMode);
|
|
94
|
+
}
|
|
95
|
+
process$1.stdin.pause();
|
|
96
|
+
};
|
|
97
|
+
process$1.stdin.on("data", onData);
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
const password = await questionPassword(
|
|
101
|
+
chalk__default.default.yellow("Enter Memsource password: ")
|
|
102
|
+
);
|
|
103
|
+
if (!password || password.trim() === "") {
|
|
104
|
+
rl.close();
|
|
105
|
+
throw new Error("Password is required");
|
|
106
|
+
}
|
|
107
|
+
return password;
|
|
108
|
+
}
|
|
109
|
+
async function promptCredentials() {
|
|
110
|
+
const rl = readline__namespace.createInterface({
|
|
111
|
+
input: process$1.stdin,
|
|
112
|
+
output: process$1.stdout
|
|
113
|
+
});
|
|
114
|
+
try {
|
|
115
|
+
const username = await promptUsername(rl);
|
|
116
|
+
const password = await promptPassword(rl);
|
|
117
|
+
return { username, password };
|
|
118
|
+
} finally {
|
|
119
|
+
rl.close();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function getCredentials(isInteractive, noInput, username, password) {
|
|
123
|
+
if (username && password) {
|
|
124
|
+
return { username, password };
|
|
125
|
+
}
|
|
126
|
+
if (isInteractive && !noInput) {
|
|
127
|
+
const prompted = await promptCredentials();
|
|
128
|
+
return {
|
|
129
|
+
username: username || prompted.username,
|
|
130
|
+
password: password || prompted.password
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (!isInteractive || noInput) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
"Username and password are required. Provide them via --username and --password options, or use environment variables (MEMSOURCE_USERNAME, MEMSOURCE_PASSWORD), or run in an interactive terminal to be prompted."
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
throw new Error("Username and password are required");
|
|
139
|
+
}
|
|
140
|
+
function generateMemsourceRcContent(memsourceVenv, memsourceUrl, username, password) {
|
|
141
|
+
return `source ${memsourceVenv}
|
|
142
|
+
|
|
143
|
+
export MEMSOURCE_URL="${memsourceUrl}"
|
|
144
|
+
|
|
145
|
+
export MEMSOURCE_USERNAME=${username}
|
|
146
|
+
|
|
147
|
+
export MEMSOURCE_PASSWORD="${password}"
|
|
148
|
+
|
|
149
|
+
export MEMSOURCE_TOKEN=$(memsource auth login --user-name $MEMSOURCE_USERNAME --password "$"MEMSOURCE_PASSWORD -c token -f value)
|
|
150
|
+
`.replace('$"MEMSOURCE_PASSWORD', "${MEMSOURCE_PASSWORD}");
|
|
151
|
+
}
|
|
152
|
+
function displaySetupInstructions(memsourceRcPath) {
|
|
153
|
+
console.log(
|
|
154
|
+
chalk__default.default.green(`\u2705 Created .memsourcerc file at ${memsourceRcPath}`)
|
|
155
|
+
);
|
|
156
|
+
console.log(chalk__default.default.yellow("\n\u26A0\uFE0F Security Note:"));
|
|
157
|
+
console.log(chalk__default.default.gray(" This file contains your password in plain text."));
|
|
158
|
+
console.log(
|
|
159
|
+
chalk__default.default.gray(" File permissions are set to 600 (owner read/write only).")
|
|
160
|
+
);
|
|
161
|
+
console.log(
|
|
162
|
+
chalk__default.default.gray(
|
|
163
|
+
" Keep this file secure and never commit it to version control."
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
console.log(chalk__default.default.yellow("\n\u{1F4DD} Next steps:"));
|
|
167
|
+
console.log(chalk__default.default.gray(" 1. Source the file in your shell:"));
|
|
168
|
+
console.log(chalk__default.default.cyan(` source ~/.memsourcerc`));
|
|
169
|
+
console.log(
|
|
170
|
+
chalk__default.default.gray(
|
|
171
|
+
" 2. Or add it to your shell profile (~/.bashrc, ~/.zshrc, etc.):"
|
|
172
|
+
)
|
|
173
|
+
);
|
|
174
|
+
console.log(chalk__default.default.cyan(` echo "source ~/.memsourcerc" >> ~/.zshrc`));
|
|
175
|
+
console.log(chalk__default.default.gray(" 3. Verify the setup:"));
|
|
176
|
+
console.log(
|
|
177
|
+
chalk__default.default.cyan(` source ~/.memsourcerc && echo $MEMSOURCE_TOKEN`)
|
|
178
|
+
);
|
|
179
|
+
console.log(
|
|
180
|
+
chalk__default.default.gray(
|
|
181
|
+
" 4. After sourcing, you can use i18n commands without additional setup"
|
|
182
|
+
)
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
async function detectMemsourceVenv() {
|
|
186
|
+
const homeDir = os__default.default.homedir();
|
|
187
|
+
const commonPaths = [
|
|
188
|
+
// Common installation locations
|
|
189
|
+
path__default.default.join(
|
|
190
|
+
homeDir,
|
|
191
|
+
"git",
|
|
192
|
+
"memsource-cli-client",
|
|
193
|
+
".memsource",
|
|
194
|
+
"bin",
|
|
195
|
+
"activate"
|
|
196
|
+
),
|
|
197
|
+
path__default.default.join(homeDir, "memsource-cli-client", ".memsource", "bin", "activate"),
|
|
198
|
+
path__default.default.join(homeDir, ".memsource", "bin", "activate"),
|
|
199
|
+
path__default.default.join(
|
|
200
|
+
homeDir,
|
|
201
|
+
".local",
|
|
202
|
+
"memsource-cli-client",
|
|
203
|
+
".memsource",
|
|
204
|
+
"bin",
|
|
205
|
+
"activate"
|
|
206
|
+
)
|
|
207
|
+
];
|
|
208
|
+
for (const venvPath of commonPaths) {
|
|
209
|
+
if (venvPath && await fs__default.default.pathExists(venvPath)) {
|
|
210
|
+
return venvPath;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
async function promptMemsourceVenv(rl) {
|
|
216
|
+
const question = (query) => {
|
|
217
|
+
return new Promise((resolve) => {
|
|
218
|
+
rl.question(query, resolve);
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
console.log(chalk__default.default.yellow("\n\u{1F4C1} Memsource CLI Virtual Environment Path"));
|
|
222
|
+
console.log(
|
|
223
|
+
chalk__default.default.gray(" The memsource CLI requires a Python virtual environment.")
|
|
224
|
+
);
|
|
225
|
+
console.log(chalk__default.default.gray(" Common locations:"));
|
|
226
|
+
console.log(
|
|
227
|
+
chalk__default.default.gray(" - ~/git/memsource-cli-client/.memsource/bin/activate")
|
|
228
|
+
);
|
|
229
|
+
console.log(
|
|
230
|
+
chalk__default.default.gray(" - ~/memsource-cli-client/.memsource/bin/activate")
|
|
231
|
+
);
|
|
232
|
+
console.log(chalk__default.default.gray(" - ~/.memsource/bin/activate"));
|
|
233
|
+
console.log(
|
|
234
|
+
chalk__default.default.gray(
|
|
235
|
+
" Or wherever you installed the memsource-cli-client repository.\n"
|
|
236
|
+
)
|
|
237
|
+
);
|
|
238
|
+
const venvPath = await question(
|
|
239
|
+
chalk__default.default.yellow("Enter path to memsource venv activate script: ")
|
|
240
|
+
);
|
|
241
|
+
if (!venvPath || venvPath.trim() === "") {
|
|
242
|
+
rl.close();
|
|
243
|
+
throw new Error("Virtual environment path is required");
|
|
244
|
+
}
|
|
245
|
+
return venvPath.trim();
|
|
246
|
+
}
|
|
247
|
+
async function getMemsourceVenv(providedPath, isInteractive, noInput) {
|
|
248
|
+
if (providedPath) {
|
|
249
|
+
return providedPath;
|
|
250
|
+
}
|
|
251
|
+
const detectedPath = await detectMemsourceVenv();
|
|
252
|
+
if (detectedPath) {
|
|
253
|
+
console.log(
|
|
254
|
+
chalk__default.default.gray(
|
|
255
|
+
` Detected memsource venv at: ${detectedPath.replace(
|
|
256
|
+
os__default.default.homedir(),
|
|
257
|
+
"~"
|
|
258
|
+
)}`
|
|
259
|
+
)
|
|
260
|
+
);
|
|
261
|
+
return detectedPath;
|
|
262
|
+
}
|
|
263
|
+
if (isInteractive && !noInput) {
|
|
264
|
+
const rl = readline__namespace.createInterface({
|
|
265
|
+
input: process$1.stdin,
|
|
266
|
+
output: process$1.stdout
|
|
267
|
+
});
|
|
268
|
+
try {
|
|
269
|
+
return await promptMemsourceVenv(rl);
|
|
270
|
+
} finally {
|
|
271
|
+
rl.close();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
throw new Error(
|
|
275
|
+
"Memsource virtual environment path is required. Provide it via --memsource-venv option, or run in an interactive terminal to be prompted."
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
async function checkVirtualEnvironment(memsourceVenv) {
|
|
279
|
+
const expandedVenvPath = memsourceVenv.replaceAll(
|
|
280
|
+
/\$\{HOME\}/g,
|
|
281
|
+
os__default.default.homedir()
|
|
282
|
+
);
|
|
283
|
+
if (!await fs__default.default.pathExists(expandedVenvPath)) {
|
|
284
|
+
console.log(
|
|
285
|
+
chalk__default.default.yellow(
|
|
286
|
+
`
|
|
287
|
+
\u26A0\uFE0F Warning: Virtual environment not found at ${expandedVenvPath}`
|
|
288
|
+
)
|
|
289
|
+
);
|
|
290
|
+
console.log(
|
|
291
|
+
chalk__default.default.gray(
|
|
292
|
+
" Please update the path in ~/.memsourcerc if your venv is located elsewhere."
|
|
293
|
+
)
|
|
294
|
+
);
|
|
295
|
+
console.log(
|
|
296
|
+
chalk__default.default.gray(
|
|
297
|
+
' You can edit ~/.memsourcerc and update the "source" line with the correct path.'
|
|
298
|
+
)
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async function setupMemsourceCommand(opts) {
|
|
303
|
+
console.log(
|
|
304
|
+
chalk__default.default.blue("\u{1F527} Setting up .memsourcerc file for Memsource CLI...")
|
|
305
|
+
);
|
|
306
|
+
const {
|
|
307
|
+
memsourceVenv,
|
|
308
|
+
memsourceUrl = "https://cloud.memsource.com/web",
|
|
309
|
+
username,
|
|
310
|
+
password
|
|
311
|
+
} = opts;
|
|
312
|
+
try {
|
|
313
|
+
const isInteractive = isInteractiveTerminal();
|
|
314
|
+
const noInput = opts.noInput === true;
|
|
315
|
+
const finalMemsourceVenv = await getMemsourceVenv(
|
|
316
|
+
memsourceVenv,
|
|
317
|
+
isInteractive,
|
|
318
|
+
noInput
|
|
319
|
+
);
|
|
320
|
+
const { username: finalUsername, password: finalPassword } = await getCredentials(isInteractive, noInput, username, password);
|
|
321
|
+
const memsourceRcContent = generateMemsourceRcContent(
|
|
322
|
+
finalMemsourceVenv,
|
|
323
|
+
memsourceUrl,
|
|
324
|
+
finalUsername,
|
|
325
|
+
finalPassword
|
|
326
|
+
);
|
|
327
|
+
const memsourceRcPath = path__default.default.join(os__default.default.homedir(), ".memsourcerc");
|
|
328
|
+
await fs__default.default.writeFile(memsourceRcPath, memsourceRcContent, { mode: 384 });
|
|
329
|
+
displaySetupInstructions(memsourceRcPath);
|
|
330
|
+
await checkVirtualEnvironment(finalMemsourceVenv);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
console.error(chalk__default.default.red("\u274C Error setting up .memsourcerc:"), error);
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
exports.setupMemsourceCommand = setupMemsourceCommand;
|
|
338
|
+
//# sourceMappingURL=setupMemsource.cjs.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chalk = require('chalk');
|
|
4
|
+
var analyzeStatus = require('../lib/i18n/analyzeStatus.cjs.js');
|
|
5
|
+
var formatReport = require('../lib/i18n/formatReport.cjs.js');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
|
|
10
|
+
|
|
11
|
+
async function statusCommand(opts) {
|
|
12
|
+
console.log(chalk__default.default.blue("\u{1F4CA} Analyzing translation status..."));
|
|
13
|
+
const {
|
|
14
|
+
sourceDir = "src",
|
|
15
|
+
i18nDir = "i18n",
|
|
16
|
+
localesDir = "src/locales",
|
|
17
|
+
format = "table",
|
|
18
|
+
includeStats = true
|
|
19
|
+
} = opts;
|
|
20
|
+
try {
|
|
21
|
+
const status = await analyzeStatus.analyzeTranslationStatus({
|
|
22
|
+
sourceDir,
|
|
23
|
+
i18nDir,
|
|
24
|
+
localesDir
|
|
25
|
+
});
|
|
26
|
+
const report = await formatReport.formatStatusReport(status, format, includeStats);
|
|
27
|
+
console.log(report);
|
|
28
|
+
console.log(chalk__default.default.green(`\u2705 Status analysis completed!`));
|
|
29
|
+
console.log(chalk__default.default.gray(` Source files: ${status.sourceFiles.length}`));
|
|
30
|
+
console.log(chalk__default.default.gray(` Translation keys: ${status.totalKeys}`));
|
|
31
|
+
console.log(chalk__default.default.gray(` Languages: ${status.languages.length}`));
|
|
32
|
+
console.log(chalk__default.default.gray(` Completion: ${status.overallCompletion}%`));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(chalk__default.default.red("\u274C Error analyzing translation status:"), error);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
exports.statusCommand = statusCommand;
|
|
40
|
+
//# sourceMappingURL=status.cjs.js.map
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var path = require('node:path');
|
|
4
|
+
var chalk = require('chalk');
|
|
5
|
+
var config = require('../lib/i18n/config.cjs.js');
|
|
6
|
+
var exec = require('../lib/utils/exec.cjs.js');
|
|
7
|
+
var generate = require('./generate.cjs.js');
|
|
8
|
+
var upload = require('./upload.cjs.js');
|
|
9
|
+
var download = require('./download.cjs.js');
|
|
10
|
+
var deploy = require('./deploy.cjs.js');
|
|
11
|
+
|
|
12
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
13
|
+
|
|
14
|
+
var path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
15
|
+
var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
|
|
16
|
+
|
|
17
|
+
function hasTmsConfig(tmsUrl, tmsToken, projectId) {
|
|
18
|
+
return !!(tmsUrl && tmsToken && projectId);
|
|
19
|
+
}
|
|
20
|
+
async function executeStep(_stepName, action) {
|
|
21
|
+
await action();
|
|
22
|
+
}
|
|
23
|
+
function simulateStep(stepName) {
|
|
24
|
+
console.log(chalk__default.default.yellow(`\u{1F50D} Dry run: Would ${stepName}`));
|
|
25
|
+
}
|
|
26
|
+
async function stepGenerate(sourceDir, outputDir, sprint, dryRun) {
|
|
27
|
+
console.log(
|
|
28
|
+
chalk__default.default.blue("\n\u{1F4DD} Step 1: Generating translation reference files...")
|
|
29
|
+
);
|
|
30
|
+
if (dryRun) {
|
|
31
|
+
simulateStep("generate translation files");
|
|
32
|
+
return { step: "Generate" };
|
|
33
|
+
}
|
|
34
|
+
let generatedFile;
|
|
35
|
+
await executeStep("generate translation files", async () => {
|
|
36
|
+
if (!sprint) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
"--sprint is required for generate command. Please provide --sprint option (e.g., --sprint s3285)"
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
await generate.generateCommand({
|
|
42
|
+
sourceDir,
|
|
43
|
+
outputDir,
|
|
44
|
+
sprint,
|
|
45
|
+
format: "json",
|
|
46
|
+
includePattern: "**/*.{ts,tsx,js,jsx}",
|
|
47
|
+
excludePattern: "**/node_modules/**",
|
|
48
|
+
extractKeys: true,
|
|
49
|
+
mergeExisting: false
|
|
50
|
+
});
|
|
51
|
+
const repoName = detectRepoName();
|
|
52
|
+
const normalizedSprint = sprint.startsWith("s") || sprint.startsWith("S") ? sprint.toLowerCase() : `s${sprint}`;
|
|
53
|
+
generatedFile = `${repoName.toLowerCase()}-${normalizedSprint}.json`;
|
|
54
|
+
});
|
|
55
|
+
return { step: "Generate", generatedFile };
|
|
56
|
+
}
|
|
57
|
+
function detectRepoName(repoPath) {
|
|
58
|
+
const targetPath = process.cwd();
|
|
59
|
+
try {
|
|
60
|
+
const gitRepoUrl = exec.safeExecSyncOrThrow(
|
|
61
|
+
"git",
|
|
62
|
+
["config", "--get", "remote.origin.url"],
|
|
63
|
+
{
|
|
64
|
+
cwd: targetPath
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
if (gitRepoUrl) {
|
|
68
|
+
let repoName = gitRepoUrl.replace(/\.git$/, "");
|
|
69
|
+
const lastSlashIndex = repoName.lastIndexOf("/");
|
|
70
|
+
if (lastSlashIndex >= 0) {
|
|
71
|
+
repoName = repoName.substring(lastSlashIndex + 1);
|
|
72
|
+
}
|
|
73
|
+
if (repoName) {
|
|
74
|
+
return repoName;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
79
|
+
return path__default.default.basename(targetPath);
|
|
80
|
+
}
|
|
81
|
+
async function stepUpload(options, generatedFile) {
|
|
82
|
+
if (options.skipUpload) {
|
|
83
|
+
console.log(chalk__default.default.yellow("\u23ED\uFE0F Skipping upload: --skip-upload specified"));
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
if (!hasTmsConfig(options.tmsUrl, options.tmsToken, options.projectId)) {
|
|
87
|
+
console.log(chalk__default.default.yellow("\u26A0\uFE0F Skipping upload: Missing TMS configuration"));
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const tmsUrl = options.tmsUrl;
|
|
91
|
+
const tmsToken = options.tmsToken;
|
|
92
|
+
const projectId = options.projectId;
|
|
93
|
+
console.log(chalk__default.default.blue("\n\u{1F4E4} Step 2: Uploading to TMS..."));
|
|
94
|
+
let sourceFile;
|
|
95
|
+
if (generatedFile) {
|
|
96
|
+
sourceFile = `${options.outputDir}/${generatedFile}`;
|
|
97
|
+
} else if (options.sprint) {
|
|
98
|
+
const repoName = detectRepoName();
|
|
99
|
+
const normalizedSprint = options.sprint.startsWith("s") || options.sprint.startsWith("S") ? options.sprint.toLowerCase() : `s${options.sprint}`;
|
|
100
|
+
sourceFile = `${options.outputDir}/${repoName.toLowerCase()}-${normalizedSprint}.json`;
|
|
101
|
+
} else {
|
|
102
|
+
throw new Error(
|
|
103
|
+
"Cannot determine source file for upload. Please provide --sprint option or ensure generate step completed successfully."
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (options.dryRun) {
|
|
107
|
+
simulateStep("upload to TMS");
|
|
108
|
+
} else {
|
|
109
|
+
await executeStep("upload to TMS", async () => {
|
|
110
|
+
await upload.uploadCommand({
|
|
111
|
+
tmsUrl,
|
|
112
|
+
tmsToken,
|
|
113
|
+
projectId,
|
|
114
|
+
sourceFile,
|
|
115
|
+
targetLanguages: options.languages,
|
|
116
|
+
dryRun: false
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return "Upload";
|
|
121
|
+
}
|
|
122
|
+
async function stepDownload(options) {
|
|
123
|
+
if (options.skipDownload) {
|
|
124
|
+
console.log(
|
|
125
|
+
chalk__default.default.yellow("\u23ED\uFE0F Skipping download: --skip-download specified")
|
|
126
|
+
);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
if (!hasTmsConfig(options.tmsUrl, options.tmsToken, options.projectId)) {
|
|
130
|
+
console.log(
|
|
131
|
+
chalk__default.default.yellow("\u26A0\uFE0F Skipping download: Missing TMS configuration")
|
|
132
|
+
);
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
const tmsUrl = options.tmsUrl;
|
|
136
|
+
const tmsToken = options.tmsToken;
|
|
137
|
+
const projectId = options.projectId;
|
|
138
|
+
console.log(chalk__default.default.blue("\n\u{1F4E5} Step 3: Downloading from TMS..."));
|
|
139
|
+
if (options.dryRun) {
|
|
140
|
+
simulateStep("download from TMS");
|
|
141
|
+
} else {
|
|
142
|
+
await executeStep("download from TMS", async () => {
|
|
143
|
+
await download.downloadCommand({
|
|
144
|
+
tmsUrl,
|
|
145
|
+
tmsToken,
|
|
146
|
+
projectId,
|
|
147
|
+
outputDir: options.outputDir,
|
|
148
|
+
languages: options.languages,
|
|
149
|
+
format: "json",
|
|
150
|
+
includeCompleted: true,
|
|
151
|
+
includeDraft: false
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return "Download";
|
|
156
|
+
}
|
|
157
|
+
async function stepDeploy(options) {
|
|
158
|
+
if (options.skipDeploy) {
|
|
159
|
+
console.log(chalk__default.default.yellow("\u23ED\uFE0F Skipping deploy: --skip-deploy specified"));
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
console.log(chalk__default.default.blue("\n\u{1F680} Step 4: Deploying to application..."));
|
|
163
|
+
if (options.dryRun) {
|
|
164
|
+
simulateStep("deploy to application");
|
|
165
|
+
} else {
|
|
166
|
+
await executeStep("deploy to application", async () => {
|
|
167
|
+
await deploy.deployCommand({
|
|
168
|
+
sourceDir: options.outputDir});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return "Deploy";
|
|
172
|
+
}
|
|
173
|
+
function displaySummary(steps, options) {
|
|
174
|
+
console.log(chalk__default.default.green("\n\u2705 i18n workflow completed successfully!"));
|
|
175
|
+
console.log(chalk__default.default.gray(` Steps executed: ${steps.join(" \u2192 ")}`));
|
|
176
|
+
if (options.dryRun) {
|
|
177
|
+
console.log(
|
|
178
|
+
chalk__default.default.blue("\u{1F50D} This was a dry run - no actual changes were made")
|
|
179
|
+
);
|
|
180
|
+
} else {
|
|
181
|
+
console.log(chalk__default.default.gray(` Source directory: ${options.sourceDir}`));
|
|
182
|
+
console.log(chalk__default.default.gray(` Output directory: ${options.outputDir}`));
|
|
183
|
+
console.log(chalk__default.default.gray(` Locales directory: ${options.localesDir}`));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async function syncCommand(opts) {
|
|
187
|
+
console.log(chalk__default.default.blue("\u{1F504} Running complete i18n workflow..."));
|
|
188
|
+
const config$1 = await config.loadI18nConfig();
|
|
189
|
+
const mergedOpts = await config.mergeConfigWithOptions(config$1, opts);
|
|
190
|
+
const options = {
|
|
191
|
+
sourceDir: String(mergedOpts.sourceDir || "src"),
|
|
192
|
+
outputDir: String(mergedOpts.outputDir || "i18n"),
|
|
193
|
+
localesDir: String(mergedOpts.localesDir || "src/locales"),
|
|
194
|
+
sprint: mergedOpts.sprint && typeof mergedOpts.sprint === "string" ? mergedOpts.sprint : void 0,
|
|
195
|
+
tmsUrl: mergedOpts.tmsUrl && typeof mergedOpts.tmsUrl === "string" ? mergedOpts.tmsUrl : void 0,
|
|
196
|
+
tmsToken: mergedOpts.tmsToken && typeof mergedOpts.tmsToken === "string" ? mergedOpts.tmsToken : void 0,
|
|
197
|
+
projectId: mergedOpts.projectId && typeof mergedOpts.projectId === "string" ? mergedOpts.projectId : void 0,
|
|
198
|
+
languages: mergedOpts.languages && typeof mergedOpts.languages === "string" ? mergedOpts.languages : void 0,
|
|
199
|
+
skipUpload: Boolean(mergedOpts.skipUpload ?? false),
|
|
200
|
+
skipDownload: Boolean(mergedOpts.skipDownload ?? false),
|
|
201
|
+
skipDeploy: Boolean(mergedOpts.skipDeploy ?? false),
|
|
202
|
+
dryRun: Boolean(mergedOpts.dryRun ?? false)
|
|
203
|
+
};
|
|
204
|
+
try {
|
|
205
|
+
const generateResult = await stepGenerate(
|
|
206
|
+
options.sourceDir,
|
|
207
|
+
options.outputDir,
|
|
208
|
+
options.sprint,
|
|
209
|
+
options.dryRun
|
|
210
|
+
);
|
|
211
|
+
const allSteps = [
|
|
212
|
+
generateResult.step,
|
|
213
|
+
await stepUpload(options, generateResult.generatedFile),
|
|
214
|
+
await stepDownload(options),
|
|
215
|
+
await stepDeploy(options)
|
|
216
|
+
];
|
|
217
|
+
const steps = allSteps.filter((step) => Boolean(step));
|
|
218
|
+
displaySummary(steps, options);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
console.error(chalk__default.default.red("\u274C Error in i18n workflow:"), error);
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
exports.syncCommand = syncCommand;
|
|
226
|
+
//# sourceMappingURL=sync.cjs.js.map
|