@scoutello/i18n-magic 0.53.0 → 0.55.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/README.md +236 -266
- package/dist/lib/utils.d.ts +32 -4
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +183 -73
- package/dist/lib/utils.js.map +1 -1
- package/dist/mcp-server.js +174 -16
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/utils.ts +234 -89
- package/src/mcp-server.ts +198 -16
package/src/mcp-server.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
ListToolsRequestSchema,
|
|
6
6
|
} from "@modelcontextprotocol/sdk/types.js"
|
|
7
7
|
import { z } from "zod"
|
|
8
|
-
import { addTranslationKey, getMissingKeys, loadConfig, loadLocalesFile } from "./lib/utils.js"
|
|
8
|
+
import { addTranslationKey, addTranslationKeys, getMissingKeys, loadConfig, loadLocalesFile } from "./lib/utils.js"
|
|
9
9
|
import type { Configuration } from "./lib/types.js"
|
|
10
10
|
import path from "path"
|
|
11
11
|
import fs from "fs"
|
|
@@ -67,7 +67,17 @@ function resolveProjectRoot(): string {
|
|
|
67
67
|
// Zod schema for the add_translation_key tool parameters
|
|
68
68
|
const AddTranslationKeySchema = z.object({
|
|
69
69
|
key: z.string().describe("The translation key to add (e.g., \"welcomeMessage\")"),
|
|
70
|
-
value: z.string().describe("The
|
|
70
|
+
value: z.string().describe("The text value for this translation key"),
|
|
71
|
+
language: z.string().optional().describe("The language code of the provided value (e.g., \"en\", \"de\", \"fr\"). Defaults to \"en\" (English) if not specified."),
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Zod schema for the add_translation_keys (batch) tool parameters
|
|
75
|
+
const AddTranslationKeysSchema = z.object({
|
|
76
|
+
keys: z.array(z.object({
|
|
77
|
+
key: z.string().describe("The translation key to add (e.g., \"welcomeMessage\")"),
|
|
78
|
+
value: z.string().describe("The text value for this translation key"),
|
|
79
|
+
language: z.string().optional().describe("The language code of the provided value (e.g., \"en\", \"de\", \"fr\"). Defaults to \"en\" (English) if not specified."),
|
|
80
|
+
})).describe("Array of translation keys to add in batch. Use this for adding multiple keys at once for better performance."),
|
|
71
81
|
})
|
|
72
82
|
|
|
73
83
|
// Zod schema for the list_untranslated_keys tool parameters
|
|
@@ -94,7 +104,8 @@ const GetTranslationKeySchema = z.object({
|
|
|
94
104
|
// Zod schema for the update_translation_key tool parameters
|
|
95
105
|
const UpdateTranslationKeySchema = z.object({
|
|
96
106
|
key: z.string().describe("The translation key to update (e.g., \"welcomeMessage\")"),
|
|
97
|
-
value: z.string().describe("The new
|
|
107
|
+
value: z.string().describe("The new text value for this translation key"),
|
|
108
|
+
language: z.string().optional().describe("The language code of the provided value (e.g., \"en\", \"de\", \"fr\"). Defaults to \"en\" (English) if not specified."),
|
|
98
109
|
namespace: z
|
|
99
110
|
.string()
|
|
100
111
|
.optional()
|
|
@@ -182,7 +193,7 @@ class I18nMagicServer {
|
|
|
182
193
|
tools: [
|
|
183
194
|
{
|
|
184
195
|
name: "add_translation_key",
|
|
185
|
-
description: "Add a new translation key with
|
|
196
|
+
description: "Add a new translation key with a text value. You can optionally specify the language of the value you're providing (defaults to English). For adding multiple keys at once, use add_translation_keys instead for better performance.",
|
|
186
197
|
inputSchema: {
|
|
187
198
|
type: "object",
|
|
188
199
|
properties: {
|
|
@@ -194,12 +205,49 @@ class I18nMagicServer {
|
|
|
194
205
|
value: {
|
|
195
206
|
type: "string",
|
|
196
207
|
description:
|
|
197
|
-
"The
|
|
208
|
+
"The text value for this translation key",
|
|
209
|
+
},
|
|
210
|
+
language: {
|
|
211
|
+
type: "string",
|
|
212
|
+
description:
|
|
213
|
+
"The language code of the provided value (e.g., \"en\" for English, \"de\" for German, \"fr\" for French). Defaults to \"en\" if not specified.",
|
|
198
214
|
},
|
|
199
215
|
},
|
|
200
216
|
required: ["key", "value"],
|
|
201
217
|
},
|
|
202
218
|
},
|
|
219
|
+
{
|
|
220
|
+
name: "add_translation_keys",
|
|
221
|
+
description: "Add multiple translation keys in batch. This is optimized for performance - when adding 2 or more keys, prefer this over multiple add_translation_key calls. It performs a single codebase scan, batches file I/O operations, and batches translations for much better performance.",
|
|
222
|
+
inputSchema: {
|
|
223
|
+
type: "object",
|
|
224
|
+
properties: {
|
|
225
|
+
keys: {
|
|
226
|
+
type: "array",
|
|
227
|
+
description: "Array of translation keys to add in batch",
|
|
228
|
+
items: {
|
|
229
|
+
type: "object",
|
|
230
|
+
properties: {
|
|
231
|
+
key: {
|
|
232
|
+
type: "string",
|
|
233
|
+
description: "The translation key to add (e.g., \"welcomeMessage\")",
|
|
234
|
+
},
|
|
235
|
+
value: {
|
|
236
|
+
type: "string",
|
|
237
|
+
description: "The text value for this translation key",
|
|
238
|
+
},
|
|
239
|
+
language: {
|
|
240
|
+
type: "string",
|
|
241
|
+
description: "The language code of the provided value (e.g., \"en\" for English, \"de\" for German, \"fr\" for French). Defaults to \"en\" if not specified.",
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
required: ["key", "value"],
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
required: ["keys"],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
203
251
|
{
|
|
204
252
|
name: "list_untranslated_keys",
|
|
205
253
|
description:
|
|
@@ -240,7 +288,7 @@ class I18nMagicServer {
|
|
|
240
288
|
{
|
|
241
289
|
name: "update_translation_key",
|
|
242
290
|
description:
|
|
243
|
-
"Update an existing translation key with a new
|
|
291
|
+
"Update an existing translation key with a new text value. You can optionally specify the language of the value you're providing (defaults to English). This will update the key across all locales (translating automatically to other languages) and all namespaces where the key exists. Use this when you need to fix typos, improve wording, or change the text of an existing translation. If you're not sure if a key exists, use get_translation_key or search_translations first.",
|
|
244
292
|
inputSchema: {
|
|
245
293
|
type: "object",
|
|
246
294
|
properties: {
|
|
@@ -252,7 +300,12 @@ class I18nMagicServer {
|
|
|
252
300
|
value: {
|
|
253
301
|
type: "string",
|
|
254
302
|
description:
|
|
255
|
-
"The new
|
|
303
|
+
"The new text value for this translation key",
|
|
304
|
+
},
|
|
305
|
+
language: {
|
|
306
|
+
type: "string",
|
|
307
|
+
description:
|
|
308
|
+
"The language code of the provided value (e.g., \"en\" for English, \"de\" for German, \"fr\" for French). Defaults to \"en\" if not specified.",
|
|
256
309
|
},
|
|
257
310
|
namespace: {
|
|
258
311
|
type: "string",
|
|
@@ -311,6 +364,7 @@ class I18nMagicServer {
|
|
|
311
364
|
result = await addTranslationKey({
|
|
312
365
|
key: params.key,
|
|
313
366
|
value: params.value,
|
|
367
|
+
language: params.language || "en",
|
|
314
368
|
config,
|
|
315
369
|
})
|
|
316
370
|
} finally {
|
|
@@ -325,14 +379,15 @@ class I18nMagicServer {
|
|
|
325
379
|
text: JSON.stringify(
|
|
326
380
|
{
|
|
327
381
|
success: true,
|
|
328
|
-
message: `Successfully added translation key "${result.key}" to affected namespaces: ${result.namespace} (${result.locale})`,
|
|
382
|
+
message: `Successfully added translation key "${result.key}" to affected namespaces: ${result.namespace} (locales: ${result.locale})`,
|
|
329
383
|
key: result.key,
|
|
330
384
|
value: result.value,
|
|
385
|
+
providedLanguage: params.language || "en",
|
|
331
386
|
namespace: result.namespace,
|
|
332
|
-
|
|
387
|
+
locales: result.locale,
|
|
333
388
|
nextStep: result.locale.includes(',')
|
|
334
|
-
? "
|
|
335
|
-
: "
|
|
389
|
+
? "Key was automatically translated to multiple locales"
|
|
390
|
+
: "Run 'i18n-magic sync' to translate this key to other locales",
|
|
336
391
|
diagnostics: logMessages.join('\n'),
|
|
337
392
|
},
|
|
338
393
|
null,
|
|
@@ -385,6 +440,131 @@ class I18nMagicServer {
|
|
|
385
440
|
}
|
|
386
441
|
}
|
|
387
442
|
|
|
443
|
+
if (request.params.name === "add_translation_keys") {
|
|
444
|
+
try {
|
|
445
|
+
// Validate parameters
|
|
446
|
+
const params = AddTranslationKeysSchema.parse(request.params.arguments)
|
|
447
|
+
|
|
448
|
+
if (!params.keys || params.keys.length === 0) {
|
|
449
|
+
return {
|
|
450
|
+
content: [
|
|
451
|
+
{
|
|
452
|
+
type: "text",
|
|
453
|
+
text: JSON.stringify(
|
|
454
|
+
{
|
|
455
|
+
success: false,
|
|
456
|
+
error: "No keys provided. The 'keys' array must contain at least one key-value pair.",
|
|
457
|
+
},
|
|
458
|
+
null,
|
|
459
|
+
2,
|
|
460
|
+
),
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
isError: true,
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Ensure config is loaded
|
|
468
|
+
const config = await this.ensureConfig()
|
|
469
|
+
|
|
470
|
+
// Capture console.log output for diagnostics
|
|
471
|
+
const originalConsoleLog = console.log
|
|
472
|
+
const logMessages: string[] = []
|
|
473
|
+
console.log = (...args: any[]) => {
|
|
474
|
+
const message = args.map(arg =>
|
|
475
|
+
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
|
|
476
|
+
).join(' ')
|
|
477
|
+
logMessages.push(message)
|
|
478
|
+
// Also log to stderr for debugging
|
|
479
|
+
console.error(`[i18n-magic] ${message}`)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
let result
|
|
483
|
+
try {
|
|
484
|
+
// Add the translation keys in batch
|
|
485
|
+
result = await addTranslationKeys({
|
|
486
|
+
keys: params.keys.map(k => ({
|
|
487
|
+
key: k.key,
|
|
488
|
+
value: k.value,
|
|
489
|
+
language: k.language || "en",
|
|
490
|
+
})),
|
|
491
|
+
config,
|
|
492
|
+
})
|
|
493
|
+
} finally {
|
|
494
|
+
// Restore console.log
|
|
495
|
+
console.log = originalConsoleLog
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return {
|
|
499
|
+
content: [
|
|
500
|
+
{
|
|
501
|
+
type: "text",
|
|
502
|
+
text: JSON.stringify(
|
|
503
|
+
{
|
|
504
|
+
success: true,
|
|
505
|
+
message: `Successfully added ${result.results.length} translation key(s) in batch`,
|
|
506
|
+
results: result.results,
|
|
507
|
+
performance: result.performance,
|
|
508
|
+
summary: {
|
|
509
|
+
totalKeys: result.results.length,
|
|
510
|
+
totalTime: `${result.performance.totalTime.toFixed(2)}ms`,
|
|
511
|
+
averageTimePerKey: `${(result.performance.totalTime / result.results.length).toFixed(2)}ms`,
|
|
512
|
+
scanTime: `${result.performance.scanTime.toFixed(2)}ms`,
|
|
513
|
+
translationTime: `${result.performance.translationTime.toFixed(2)}ms`,
|
|
514
|
+
fileIOTime: `${result.performance.fileIOTime.toFixed(2)}ms`,
|
|
515
|
+
},
|
|
516
|
+
diagnostics: logMessages.join('\n'),
|
|
517
|
+
},
|
|
518
|
+
null,
|
|
519
|
+
2,
|
|
520
|
+
),
|
|
521
|
+
},
|
|
522
|
+
],
|
|
523
|
+
}
|
|
524
|
+
} catch (error) {
|
|
525
|
+
const errorMessage =
|
|
526
|
+
error instanceof Error ? error.message : "Unknown error occurred"
|
|
527
|
+
|
|
528
|
+
// Get more detailed error information
|
|
529
|
+
let errorDetails = errorMessage
|
|
530
|
+
if (error instanceof Error) {
|
|
531
|
+
// Check if there's a cause
|
|
532
|
+
const cause = (error as any).cause
|
|
533
|
+
if (cause instanceof Error) {
|
|
534
|
+
errorDetails = `${errorMessage}\nCause: ${cause.message}\nStack: ${cause.stack}`
|
|
535
|
+
} else if (cause) {
|
|
536
|
+
errorDetails = `${errorMessage}\nCause: ${JSON.stringify(cause)}`
|
|
537
|
+
}
|
|
538
|
+
// Include stack trace
|
|
539
|
+
if (error.stack) {
|
|
540
|
+
errorDetails = `${errorDetails}\nStack: ${error.stack}`
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Log detailed error to stderr for debugging
|
|
545
|
+
console.error(`[i18n-magic MCP] Error adding translation keys in batch:`)
|
|
546
|
+
console.error(errorDetails)
|
|
547
|
+
|
|
548
|
+
return {
|
|
549
|
+
content: [
|
|
550
|
+
{
|
|
551
|
+
type: "text",
|
|
552
|
+
text: JSON.stringify(
|
|
553
|
+
{
|
|
554
|
+
success: false,
|
|
555
|
+
error: errorMessage,
|
|
556
|
+
details: errorDetails,
|
|
557
|
+
},
|
|
558
|
+
null,
|
|
559
|
+
2,
|
|
560
|
+
),
|
|
561
|
+
},
|
|
562
|
+
],
|
|
563
|
+
isError: true,
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
388
568
|
if (request.params.name === "list_untranslated_keys") {
|
|
389
569
|
try {
|
|
390
570
|
// Validate parameters
|
|
@@ -681,20 +861,21 @@ class I18nMagicServer {
|
|
|
681
861
|
}
|
|
682
862
|
|
|
683
863
|
// Build translation cache with new value
|
|
864
|
+
const inputLanguage = params.language || "en"
|
|
684
865
|
const translationCache: Record<string, string> = {
|
|
685
|
-
|
|
866
|
+
[inputLanguage]: params.value,
|
|
686
867
|
}
|
|
687
868
|
|
|
688
869
|
// Translate to all other locales
|
|
689
|
-
const
|
|
690
|
-
if (
|
|
870
|
+
const otherLocales = config.locales.filter((l) => l !== inputLanguage)
|
|
871
|
+
if (otherLocales.length > 0 && config.openai) {
|
|
691
872
|
const { translateKey } = await import("./lib/utils.js")
|
|
692
873
|
|
|
693
874
|
await Promise.all(
|
|
694
|
-
|
|
875
|
+
otherLocales.map(async (locale) => {
|
|
695
876
|
const translation = await translateKey({
|
|
696
877
|
context: config.context || "",
|
|
697
|
-
inputLanguage:
|
|
878
|
+
inputLanguage: inputLanguage,
|
|
698
879
|
outputLanguage: locale,
|
|
699
880
|
object: {
|
|
700
881
|
[params.key]: params.value,
|
|
@@ -730,6 +911,7 @@ class I18nMagicServer {
|
|
|
730
911
|
message: `Successfully updated translation key "${params.key}" in ${targetNamespaces.length} namespace(s) and ${config.locales.length} locale(s)`,
|
|
731
912
|
key: params.key,
|
|
732
913
|
newValue: params.value,
|
|
914
|
+
providedLanguage: params.language || "en",
|
|
733
915
|
namespaces: targetNamespaces,
|
|
734
916
|
locales: config.locales,
|
|
735
917
|
diagnostics: logMessages.join('\n'),
|