@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.
@@ -0,0 +1,418 @@
1
+ 'use strict';
2
+
3
+ var ts = require('typescript');
4
+
5
+ function _interopNamespaceCompat(e) {
6
+ if (e && typeof e === 'object' && 'default' in e) return e;
7
+ var n = Object.create(null);
8
+ if (e) {
9
+ Object.keys(e).forEach(function (k) {
10
+ if (k !== 'default') {
11
+ var d = Object.getOwnPropertyDescriptor(e, k);
12
+ Object.defineProperty(n, k, d.get ? d : {
13
+ enumerable: true,
14
+ get: function () { return e[k]; }
15
+ });
16
+ }
17
+ });
18
+ }
19
+ n.default = e;
20
+ return Object.freeze(n);
21
+ }
22
+
23
+ var ts__namespace = /*#__PURE__*/_interopNamespaceCompat(ts);
24
+
25
+ function extractTranslationKeys(content, filePath) {
26
+ const keys = {};
27
+ let pluginId = null;
28
+ if (filePath.endsWith(".d.ts")) {
29
+ return { keys: extractKeysWithRegex(content), pluginId: null };
30
+ }
31
+ try {
32
+ const sourceFile = ts__namespace.createSourceFile(
33
+ filePath,
34
+ content,
35
+ ts__namespace.ScriptTarget.Latest,
36
+ true
37
+ );
38
+ const invalidKeys = [];
39
+ const unwrapTypeAssertion = (node) => {
40
+ return ts__namespace.isAsExpression(node) ? node.expression : node;
41
+ };
42
+ const extractPropertyKeyName = (propertyName) => {
43
+ if (ts__namespace.isIdentifier(propertyName)) {
44
+ return propertyName.text;
45
+ }
46
+ if (ts__namespace.isStringLiteral(propertyName)) {
47
+ return propertyName.text;
48
+ }
49
+ return null;
50
+ };
51
+ const isValidKey = (key) => {
52
+ if (!key || key.trim() === "") {
53
+ return false;
54
+ }
55
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/.test(
56
+ key
57
+ );
58
+ };
59
+ const trackInvalidKey = (key) => {
60
+ if (!invalidKeys.includes(key)) {
61
+ invalidKeys.push(key);
62
+ }
63
+ };
64
+ const extractTemplateText = (template) => {
65
+ let templateText = "";
66
+ for (const part of template.templateSpans) {
67
+ if (part.literal) {
68
+ templateText += part.literal.text;
69
+ }
70
+ }
71
+ if (template.head) {
72
+ templateText = template.head.text + templateText;
73
+ }
74
+ return templateText;
75
+ };
76
+ const extractValueFromInitializer = (initializer) => {
77
+ const unwrapped = unwrapTypeAssertion(initializer);
78
+ if (ts__namespace.isStringLiteral(unwrapped)) {
79
+ return unwrapped.text;
80
+ }
81
+ if (ts__namespace.isTemplateExpression(unwrapped)) {
82
+ return extractTemplateText(unwrapped);
83
+ }
84
+ if (ts__namespace.isNoSubstitutionTemplateLiteral(unwrapped)) {
85
+ return unwrapped.text;
86
+ }
87
+ return null;
88
+ };
89
+ const extractFromObjectLiteral = (node, prefix = "") => {
90
+ const objectNode = unwrapTypeAssertion(node);
91
+ if (!ts__namespace.isObjectLiteralExpression(objectNode)) {
92
+ return;
93
+ }
94
+ for (const property of objectNode.properties) {
95
+ if (!ts__namespace.isPropertyAssignment(property) || !property.name) {
96
+ continue;
97
+ }
98
+ const keyName = extractPropertyKeyName(property.name);
99
+ if (!keyName) {
100
+ continue;
101
+ }
102
+ const fullKey = prefix ? `${prefix}.${keyName}` : keyName;
103
+ if (!isValidKey(fullKey)) {
104
+ trackInvalidKey(fullKey);
105
+ continue;
106
+ }
107
+ const initializer = property.initializer;
108
+ if (!initializer) {
109
+ continue;
110
+ }
111
+ const unwrappedInitializer = unwrapTypeAssertion(initializer);
112
+ const value = extractValueFromInitializer(unwrappedInitializer);
113
+ if (value !== null) {
114
+ keys[fullKey] = value;
115
+ continue;
116
+ }
117
+ if (ts__namespace.isObjectLiteralExpression(unwrappedInitializer)) {
118
+ extractFromObjectLiteral(unwrappedInitializer, fullKey);
119
+ }
120
+ }
121
+ };
122
+ const extractMessagesFromProperty = (property, propertyName) => {
123
+ if (!ts__namespace.isPropertyAssignment(property)) {
124
+ return;
125
+ }
126
+ const propName = extractPropertyKeyName(property.name);
127
+ if (propName !== propertyName) {
128
+ return;
129
+ }
130
+ const messagesNode = unwrapTypeAssertion(property.initializer);
131
+ if (ts__namespace.isObjectLiteralExpression(messagesNode)) {
132
+ extractFromObjectLiteral(messagesNode);
133
+ }
134
+ };
135
+ const extractFromCreateTranslationRef = (node) => {
136
+ const args = node.arguments;
137
+ if (args.length === 0 || !ts__namespace.isObjectLiteralExpression(args[0])) {
138
+ return null;
139
+ }
140
+ let extractedPluginId = null;
141
+ for (const property of args[0].properties) {
142
+ if (ts__namespace.isPropertyAssignment(property) && ts__namespace.isIdentifier(property.name) && property.name.text === "id" && ts__namespace.isStringLiteral(property.initializer)) {
143
+ extractedPluginId = property.initializer.text;
144
+ }
145
+ if (property.name) {
146
+ const propName = extractPropertyKeyName(property.name);
147
+ if (propName === "messages") {
148
+ extractMessagesFromProperty(property, "messages");
149
+ }
150
+ }
151
+ }
152
+ return extractedPluginId;
153
+ };
154
+ const extractFromCreateTranslationResource = (node) => {
155
+ const args = node.arguments;
156
+ if (args.length === 0 || !ts__namespace.isObjectLiteralExpression(args[0])) {
157
+ return;
158
+ }
159
+ for (const property of args[0].properties) {
160
+ if (ts__namespace.isPropertyAssignment(property) && ts__namespace.isIdentifier(property.name) && property.name.text === "translations" && ts__namespace.isObjectLiteralExpression(property.initializer)) {
161
+ extractFromObjectLiteral(property.initializer);
162
+ }
163
+ }
164
+ };
165
+ const extractFromCreateTranslationMessages = (node) => {
166
+ const args = node.arguments;
167
+ if (args.length === 0 || !ts__namespace.isObjectLiteralExpression(args[0])) {
168
+ return;
169
+ }
170
+ for (const property of args[0].properties) {
171
+ extractMessagesFromProperty(property, "messages");
172
+ }
173
+ };
174
+ const extractFromDefineMessages = (node) => {
175
+ const args = node.arguments;
176
+ if (args.length === 0 || !ts__namespace.isObjectLiteralExpression(args[0])) {
177
+ return;
178
+ }
179
+ for (const property of args[0].properties) {
180
+ if (ts__namespace.isPropertyAssignment(property) && property.initializer && ts__namespace.isObjectLiteralExpression(property.initializer)) {
181
+ const keyName = extractPropertyKeyName(property.name);
182
+ if (!keyName) {
183
+ continue;
184
+ }
185
+ for (const msgProperty of property.initializer.properties) {
186
+ if (ts__namespace.isPropertyAssignment(msgProperty) && msgProperty.name && ts__namespace.isIdentifier(msgProperty.name)) {
187
+ const propName = msgProperty.name.text;
188
+ if ((propName === "defaultMessage" || propName === "id") && ts__namespace.isStringLiteral(msgProperty.initializer)) {
189
+ const value = msgProperty.initializer.text;
190
+ if (isValidKey(keyName)) {
191
+ keys[keyName] = value;
192
+ }
193
+ break;
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ };
200
+ const isMessagesVariableName = (varName) => {
201
+ return varName.includes("Messages") || varName.includes("messages") || varName.includes("translations");
202
+ };
203
+ const extractFromVariableStatement = (node) => {
204
+ const isExported = node.modifiers?.some(
205
+ (m) => m.kind === ts__namespace.SyntaxKind.ExportKeyword
206
+ );
207
+ if (!isExported) {
208
+ return;
209
+ }
210
+ for (const declaration of node.declarationList.declarations) {
211
+ if (!declaration.initializer || !ts__namespace.isObjectLiteralExpression(declaration.initializer)) {
212
+ continue;
213
+ }
214
+ const varName = ts__namespace.isIdentifier(declaration.name) ? declaration.name.text : "";
215
+ if (isMessagesVariableName(varName)) {
216
+ extractFromObjectLiteral(declaration.initializer);
217
+ }
218
+ }
219
+ };
220
+ const extractFromTranslationCall = (args) => {
221
+ if (args.length === 0 || !ts__namespace.isStringLiteral(args[0])) {
222
+ return;
223
+ }
224
+ const key = args[0].text;
225
+ if (!isValidKey(key)) {
226
+ if (!invalidKeys.includes(key)) {
227
+ invalidKeys.push(key);
228
+ }
229
+ return;
230
+ }
231
+ const value = args.length > 1 && ts__namespace.isStringLiteral(args[1]) ? args[1].text : key;
232
+ keys[key] = value;
233
+ };
234
+ const extractFromTFunction = (node) => {
235
+ extractFromTranslationCall(node.arguments);
236
+ };
237
+ const isI18nTCall = (node) => {
238
+ return ts__namespace.isPropertyAccessExpression(node.expression) && ts__namespace.isIdentifier(node.expression.expression) && node.expression.expression.text === "i18n" && ts__namespace.isIdentifier(node.expression.name) && node.expression.name.text === "t";
239
+ };
240
+ const extractFromI18nT = (node) => {
241
+ if (!isI18nTCall(node)) {
242
+ return;
243
+ }
244
+ extractFromTranslationCall(node.arguments);
245
+ };
246
+ const isUseTranslationTCall = (node) => {
247
+ if (!ts__namespace.isPropertyAccessExpression(node.expression)) {
248
+ return false;
249
+ }
250
+ const propertyAccess = node.expression;
251
+ if (!ts__namespace.isCallExpression(propertyAccess.expression)) {
252
+ return false;
253
+ }
254
+ const innerCall = propertyAccess.expression;
255
+ return ts__namespace.isIdentifier(innerCall.expression) && innerCall.expression.text === "useTranslation" && ts__namespace.isIdentifier(propertyAccess.name) && propertyAccess.name.text === "t";
256
+ };
257
+ const extractFromUseTranslationT = (node) => {
258
+ if (!isUseTranslationTCall(node)) {
259
+ return;
260
+ }
261
+ extractFromTranslationCall(node.arguments);
262
+ };
263
+ const extractFromJsxTrans = (node) => {
264
+ const tagName = ts__namespace.isJsxElement(node) ? node.openingElement.tagName : node.tagName;
265
+ if (!ts__namespace.isIdentifier(tagName) || tagName.text !== "Trans") {
266
+ return;
267
+ }
268
+ const attributes = ts__namespace.isJsxElement(node) ? node.openingElement.attributes : node.attributes;
269
+ if (!ts__namespace.isJsxAttributes(attributes)) {
270
+ return;
271
+ }
272
+ attributes.properties.forEach((attr) => {
273
+ if (ts__namespace.isJsxAttribute(attr) && ts__namespace.isIdentifier(attr.name) && attr.name.text === "i18nKey" && attr.initializer && ts__namespace.isStringLiteral(attr.initializer)) {
274
+ const key = attr.initializer.text;
275
+ keys[key] = key;
276
+ }
277
+ });
278
+ };
279
+ const isCallExpressionWithName = (node, functionName) => {
280
+ return ts__namespace.isCallExpression(node) && ts__namespace.isIdentifier(node.expression) && node.expression.text === functionName;
281
+ };
282
+ const extractFromTranslationRefType = (messagesType) => {
283
+ for (const member of messagesType.members) {
284
+ if (!ts__namespace.isPropertySignature(member) || !member.name) {
285
+ continue;
286
+ }
287
+ const keyName = extractPropertyKeyName(member.name);
288
+ if (!keyName || !member.type) {
289
+ continue;
290
+ }
291
+ if (!ts__namespace.isLiteralTypeNode(member.type)) {
292
+ continue;
293
+ }
294
+ const literalType = member.type;
295
+ if (!literalType.literal || !ts__namespace.isStringLiteral(literalType.literal)) {
296
+ continue;
297
+ }
298
+ const stringValue = literalType.literal.text;
299
+ if (isValidKey(keyName)) {
300
+ keys[keyName] = stringValue;
301
+ } else {
302
+ trackInvalidKey(keyName);
303
+ }
304
+ }
305
+ };
306
+ const extractFromTranslationRefDeclarations = (node) => {
307
+ for (const decl of node.declarationList.declarations) {
308
+ if (!decl.type || !ts__namespace.isTypeReferenceNode(decl.type)) {
309
+ continue;
310
+ }
311
+ const typeRef = decl.type;
312
+ if (!ts__namespace.isIdentifier(typeRef.typeName) || typeRef.typeName.text !== "TranslationRef" || !typeRef.typeArguments || typeRef.typeArguments.length < 2) {
313
+ continue;
314
+ }
315
+ const messagesType = typeRef.typeArguments[1];
316
+ if (ts__namespace.isTypeLiteralNode(messagesType)) {
317
+ extractFromTranslationRefType(messagesType);
318
+ }
319
+ }
320
+ };
321
+ const handleCallExpression = (node) => {
322
+ if (isCallExpressionWithName(node, "createTranslationRef")) {
323
+ const extractedPluginId = extractFromCreateTranslationRef(node);
324
+ if (extractedPluginId && !pluginId) {
325
+ pluginId = extractedPluginId;
326
+ }
327
+ } else if (isCallExpressionWithName(node, "createTranslationResource")) {
328
+ extractFromCreateTranslationResource(node);
329
+ } else if (isCallExpressionWithName(node, "createTranslationMessages")) {
330
+ extractFromCreateTranslationMessages(node);
331
+ } else if (isCallExpressionWithName(node, "defineMessages")) {
332
+ extractFromDefineMessages(node);
333
+ } else if (isCallExpressionWithName(node, "t")) {
334
+ extractFromTFunction(node);
335
+ } else if (isI18nTCall(node)) {
336
+ extractFromI18nT(node);
337
+ } else if (isUseTranslationTCall(node)) {
338
+ extractFromUseTranslationT(node);
339
+ }
340
+ };
341
+ const handleVariableStatement = (node) => {
342
+ extractFromVariableStatement(node);
343
+ extractFromTranslationRefDeclarations(node);
344
+ };
345
+ const handleJsxNode = (node) => {
346
+ extractFromJsxTrans(node);
347
+ };
348
+ const visit = (node) => {
349
+ if (ts__namespace.isCallExpression(node)) {
350
+ handleCallExpression(node);
351
+ } else if (ts__namespace.isVariableStatement(node)) {
352
+ handleVariableStatement(node);
353
+ } else if (ts__namespace.isJsxElement(node) || ts__namespace.isJsxSelfClosingElement(node)) {
354
+ handleJsxNode(node);
355
+ }
356
+ ts__namespace.forEachChild(node, visit);
357
+ };
358
+ visit(sourceFile);
359
+ if (invalidKeys.length > 0) {
360
+ console.warn(
361
+ `\u26A0\uFE0F Skipped ${invalidKeys.length} invalid key(s) in ${filePath}: ${invalidKeys.slice(0, 5).join(", ")}${invalidKeys.length > 5 ? "..." : ""}`
362
+ );
363
+ }
364
+ } catch (error) {
365
+ console.warn(
366
+ `\u26A0\uFE0F Warning: AST parsing failed for ${filePath}, falling back to regex: ${error}`
367
+ );
368
+ return { keys: extractKeysWithRegex(content), pluginId: null };
369
+ }
370
+ return { keys, pluginId };
371
+ }
372
+ function isValidKeyRegex(key) {
373
+ if (!key || key.trim() === "") {
374
+ return false;
375
+ }
376
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/.test(key);
377
+ }
378
+ function extractKeysWithRegex(content) {
379
+ const keys = {};
380
+ const patterns = [
381
+ // TranslationRef type declarations: readonly "key": "value"
382
+ // Pattern from .d.ts files: readonly "starredEntities.noStarredEntitiesMessage": "Click the star..."
383
+ /readonly\s+["']([^"']+)["']\s*:\s*["']([^"']*?)["']/g,
384
+ // t('key', 'value') - with second parameter
385
+ /t\s*\(\s*['"`]([^'"`]+?)['"`]\s*,\s*['"`]([^'"`]*?)['"`]\s*\)/g,
386
+ // t('key') - without second parameter
387
+ /t\s*\(\s*['"`]([^'"`]+?)['"`]\s*\)/g,
388
+ // i18n.t('key', 'value') - with second parameter
389
+ /i18n\s*\.\s*t\s*\(\s*['"`]([^'"`]+?)['"`]\s*,\s*['"`]([^'"`]*?)['"`]\s*\)/g,
390
+ // i18n.t('key') - without second parameter
391
+ /i18n\s*\.\s*t\s*\(\s*['"`]([^'"`]+?)['"`]\s*\)/g,
392
+ // useTranslation().t('key', 'value') - with second parameter
393
+ /useTranslation\s*\(\s*\)\s*\.\s*t\s*\(\s*['"`]([^'"`]+?)['"`]\s*,\s*['"`]([^'"`]*?)['"`]\s*\)/g,
394
+ // useTranslation().t('key') - without second parameter
395
+ /useTranslation\s*\(\s*\)\s*\.\s*t\s*\(\s*['"`]([^'"`]+?)['"`]\s*\)/g,
396
+ // Trans i18nKey="key"
397
+ /i18nKey\s*=\s*['"`]([^'"`]+?)['"`]/g
398
+ ];
399
+ for (const pattern of patterns) {
400
+ let match;
401
+ while ((match = pattern.exec(content)) !== null) {
402
+ const key = match[1];
403
+ if (!isValidKeyRegex(key)) {
404
+ continue;
405
+ }
406
+ const value = match[2] || key;
407
+ if (value && value !== key) {
408
+ keys[key] = value;
409
+ } else if (!keys[key]) {
410
+ keys[key] = key;
411
+ }
412
+ }
413
+ }
414
+ return keys;
415
+ }
416
+
417
+ exports.extractTranslationKeys = extractTranslationKeys;
418
+ //# sourceMappingURL=extractKeys.cjs.js.map
@@ -0,0 +1,138 @@
1
+ 'use strict';
2
+
3
+ var chalk = require('chalk');
4
+
5
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
6
+
7
+ var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
8
+
9
+ async function formatStatusReport(status, format, includeStats) {
10
+ switch (format.toLowerCase()) {
11
+ case "table":
12
+ return formatTableReport(status, includeStats);
13
+ case "json":
14
+ return formatJsonReport(status, includeStats);
15
+ default:
16
+ throw new Error(`Unsupported format: ${format}`);
17
+ }
18
+ }
19
+ function addHeader(lines) {
20
+ lines.push(chalk__default.default.blue("\u{1F4CA} Translation Status Report"));
21
+ lines.push(chalk__default.default.gray("\u2550".repeat(50)));
22
+ }
23
+ function addSummary(lines, status) {
24
+ lines.push(chalk__default.default.yellow("\n\u{1F4C8} Summary:"));
25
+ lines.push(` Total Keys: ${status.totalKeys}`);
26
+ lines.push(` Languages: ${status.languages.length}`);
27
+ lines.push(` Overall Completion: ${status.overallCompletion.toFixed(1)}%`);
28
+ }
29
+ function addLanguageBreakdown(lines, status) {
30
+ if (status.languages.length === 0) {
31
+ return;
32
+ }
33
+ lines.push(chalk__default.default.yellow("\n\u{1F30D} Language Status:"));
34
+ lines.push(chalk__default.default.gray(" Language | Translated | Total | Completion"));
35
+ lines.push(chalk__default.default.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
36
+ for (const language of status.languages) {
37
+ const stats = status.languageStats[language];
38
+ const completion = stats.completion.toFixed(1);
39
+ const completionBar = getCompletionBar(stats.completion);
40
+ lines.push(
41
+ ` ${language.padEnd(12)} | ${stats.translated.toString().padStart(10)} | ${stats.total.toString().padStart(5)} | ${completion.padStart(8)}% ${completionBar}`
42
+ );
43
+ }
44
+ }
45
+ function addMissingKeys(lines, status) {
46
+ if (status.missingKeys.length === 0) {
47
+ return;
48
+ }
49
+ lines.push(chalk__default.default.red(`
50
+ \u274C Missing Keys (${status.missingKeys.length}):`));
51
+ for (const key of status.missingKeys.slice(0, 10)) {
52
+ lines.push(chalk__default.default.gray(` ${key}`));
53
+ }
54
+ if (status.missingKeys.length > 10) {
55
+ lines.push(chalk__default.default.gray(` ... and ${status.missingKeys.length - 10} more`));
56
+ }
57
+ }
58
+ function addExtraKeys(lines, status) {
59
+ const languagesWithExtraKeys = status.languages.filter(
60
+ (lang) => status.extraKeys[lang] && status.extraKeys[lang].length > 0
61
+ );
62
+ if (languagesWithExtraKeys.length === 0) {
63
+ return;
64
+ }
65
+ lines.push(chalk__default.default.yellow(`
66
+ \u26A0\uFE0F Extra Keys:`));
67
+ for (const language of languagesWithExtraKeys) {
68
+ const extraKeys = status.extraKeys[language];
69
+ lines.push(chalk__default.default.gray(` ${language}: ${extraKeys.length} extra keys`));
70
+ for (const key of extraKeys.slice(0, 5)) {
71
+ lines.push(chalk__default.default.gray(` ${key}`));
72
+ }
73
+ if (extraKeys.length > 5) {
74
+ lines.push(chalk__default.default.gray(` ... and ${extraKeys.length - 5} more`));
75
+ }
76
+ }
77
+ }
78
+ function addDetailedStats(lines, status) {
79
+ lines.push(chalk__default.default.yellow("\n\u{1F4CA} Detailed Statistics:"));
80
+ lines.push(` Source Files: ${status.sourceFiles.length}`);
81
+ lines.push(
82
+ ` Total Translations: ${status.languages.reduce(
83
+ (sum, lang) => sum + (status.languageStats[lang]?.translated || 0),
84
+ 0
85
+ )}`
86
+ );
87
+ lines.push(
88
+ ` Average Completion: ${(status.languages.reduce(
89
+ (sum, lang) => sum + (status.languageStats[lang]?.completion || 0),
90
+ 0
91
+ ) / status.languages.length).toFixed(1)}%`
92
+ );
93
+ }
94
+ function formatTableReport(status, includeStats) {
95
+ const lines = [];
96
+ addHeader(lines);
97
+ addSummary(lines, status);
98
+ addLanguageBreakdown(lines, status);
99
+ addMissingKeys(lines, status);
100
+ addExtraKeys(lines, status);
101
+ if (includeStats) {
102
+ addDetailedStats(lines, status);
103
+ }
104
+ return lines.join("\n");
105
+ }
106
+ function formatJsonReport(status, includeStats) {
107
+ const summary = {
108
+ totalKeys: status.totalKeys,
109
+ languages: status.languages.length,
110
+ overallCompletion: status.overallCompletion
111
+ };
112
+ if (includeStats) {
113
+ summary.sourceFiles = status.sourceFiles.length;
114
+ summary.totalTranslations = status.languages.reduce(
115
+ (sum, lang) => sum + (status.languageStats[lang]?.translated || 0),
116
+ 0
117
+ );
118
+ summary.averageCompletion = status.languages.reduce(
119
+ (sum, lang) => sum + (status.languageStats[lang]?.completion || 0),
120
+ 0
121
+ ) / status.languages.length;
122
+ }
123
+ const report = {
124
+ summary,
125
+ languages: status.languageStats,
126
+ missingKeys: status.missingKeys,
127
+ extraKeys: status.extraKeys
128
+ };
129
+ return JSON.stringify(report, null, 2);
130
+ }
131
+ function getCompletionBar(completion) {
132
+ const filled = Math.floor(completion / 10);
133
+ const empty = 10 - filled;
134
+ return "\u2588".repeat(filled) + "\u2591".repeat(empty);
135
+ }
136
+
137
+ exports.formatStatusReport = formatStatusReport;
138
+ //# sourceMappingURL=formatReport.cjs.js.map
@@ -0,0 +1,94 @@
1
+ 'use strict';
2
+
3
+ var path = require('node:path');
4
+ var fs = require('fs-extra');
5
+
6
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
7
+
8
+ var path__default = /*#__PURE__*/_interopDefaultCompat(path);
9
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
10
+
11
+ async function generateTranslationFiles(keys, outputPath, format) {
12
+ const outputDir = path__default.default.dirname(outputPath);
13
+ await fs__default.default.ensureDir(outputDir);
14
+ switch (format.toLowerCase()) {
15
+ case "json":
16
+ await generateJsonFile(keys, outputPath);
17
+ break;
18
+ case "po":
19
+ await generatePoFile(keys, outputPath);
20
+ break;
21
+ default:
22
+ throw new Error(`Unsupported format: ${format}`);
23
+ }
24
+ }
25
+ function isNestedStructure(data) {
26
+ const keys = Object.keys(data);
27
+ if (keys.length === 0) return true;
28
+ const firstKey = keys[0];
29
+ const firstValue = data[firstKey];
30
+ return typeof firstValue === "object" && firstValue !== null && "en" in firstValue;
31
+ }
32
+ async function generateJsonFile(keys, outputPath) {
33
+ const normalizeValue = (value) => {
34
+ return value.replaceAll(/'/g, "'").replaceAll(/'/g, "'").replaceAll(/"/g, '"').replaceAll(/"/g, '"');
35
+ };
36
+ if (isNestedStructure(keys)) {
37
+ const normalizedData = {};
38
+ for (const [pluginName, pluginData] of Object.entries(keys)) {
39
+ normalizedData[pluginName] = {
40
+ en: {}
41
+ };
42
+ for (const [key, value] of Object.entries(pluginData.en)) {
43
+ normalizedData[pluginName].en[key] = normalizeValue(value);
44
+ }
45
+ }
46
+ await fs__default.default.writeJson(outputPath, normalizedData, { spaces: 2 });
47
+ } else {
48
+ const normalizedKeys = {};
49
+ for (const [key, value] of Object.entries(keys)) {
50
+ normalizedKeys[key] = normalizeValue(value);
51
+ }
52
+ const data = {
53
+ metadata: {
54
+ generated: (/* @__PURE__ */ new Date()).toISOString(),
55
+ version: "1.0",
56
+ totalKeys: Object.keys(normalizedKeys).length
57
+ },
58
+ translations: normalizedKeys
59
+ };
60
+ await fs__default.default.writeJson(outputPath, data, { spaces: 2 });
61
+ }
62
+ }
63
+ async function generatePoFile(keys, outputPath) {
64
+ const lines = [];
65
+ let flatKeys;
66
+ if (isNestedStructure(keys)) {
67
+ flatKeys = {};
68
+ for (const [pluginName, pluginData] of Object.entries(keys)) {
69
+ for (const [key, value] of Object.entries(pluginData.en)) {
70
+ flatKeys[`${pluginName}.${key}`] = value;
71
+ }
72
+ }
73
+ } else {
74
+ flatKeys = keys;
75
+ }
76
+ lines.push('msgid ""');
77
+ lines.push('msgstr ""');
78
+ lines.push(String.raw`"Content-Type: text/plain; charset=UTF-8\n"`);
79
+ lines.push(String.raw`"Generated: ${(/* @__PURE__ */ new Date()).toISOString()}\n"`);
80
+ lines.push(String.raw`"Total-Keys: ${Object.keys(flatKeys).length}\n"`);
81
+ lines.push("");
82
+ for (const [key, value] of Object.entries(flatKeys)) {
83
+ lines.push(`msgid "${escapePoString(key)}"`);
84
+ lines.push(`msgstr "${escapePoString(value)}"`);
85
+ lines.push("");
86
+ }
87
+ await fs__default.default.writeFile(outputPath, lines.join("\n"), "utf-8");
88
+ }
89
+ function escapePoString(str) {
90
+ return str.replaceAll(/\\/g, "\\\\").replaceAll(/"/g, '\\"').replaceAll(/\n/g, "\\n").replaceAll(/\r/g, "\\r").replaceAll(/\t/g, "\\t");
91
+ }
92
+
93
+ exports.generateTranslationFiles = generateTranslationFiles;
94
+ //# sourceMappingURL=generateFiles.cjs.js.map