@langapi/mcp-server 1.0.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 +551 -0
- package/bin/langapi-mcp.js +11 -0
- package/dist/api/client.d.ts +24 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +145 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/types.d.ts +56 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +6 -0
- package/dist/api/types.js.map +1 -0
- package/dist/config/env.d.ts +18 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +29 -0
- package/dist/config/env.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/locale-detection/index.d.ts +41 -0
- package/dist/locale-detection/index.d.ts.map +1 -0
- package/dist/locale-detection/index.js +188 -0
- package/dist/locale-detection/index.js.map +1 -0
- package/dist/locale-detection/patterns.d.ts +21 -0
- package/dist/locale-detection/patterns.d.ts.map +1 -0
- package/dist/locale-detection/patterns.js +135 -0
- package/dist/locale-detection/patterns.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +24 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/get-diff.d.ts +23 -0
- package/dist/tools/get-diff.d.ts.map +1 -0
- package/dist/tools/get-diff.js +88 -0
- package/dist/tools/get-diff.js.map +1 -0
- package/dist/tools/get-translation-status.d.ts +47 -0
- package/dist/tools/get-translation-status.d.ts.map +1 -0
- package/dist/tools/get-translation-status.js +176 -0
- package/dist/tools/get-translation-status.js.map +1 -0
- package/dist/tools/list-local-locales.d.ts +39 -0
- package/dist/tools/list-local-locales.d.ts.map +1 -0
- package/dist/tools/list-local-locales.js +52 -0
- package/dist/tools/list-local-locales.js.map +1 -0
- package/dist/tools/sync-translations.d.ts +35 -0
- package/dist/tools/sync-translations.d.ts.map +1 -0
- package/dist/tools/sync-translations.js +629 -0
- package/dist/tools/sync-translations.js.map +1 -0
- package/dist/utils/format-preserve.d.ts +25 -0
- package/dist/utils/format-preserve.d.ts.map +1 -0
- package/dist/utils/format-preserve.js +56 -0
- package/dist/utils/format-preserve.js.map +1 -0
- package/dist/utils/json-parser.d.ts +33 -0
- package/dist/utils/json-parser.d.ts.map +1 -0
- package/dist/utils/json-parser.js +92 -0
- package/dist/utils/json-parser.js.map +1 -0
- package/dist/utils/sync-cache.d.ts +40 -0
- package/dist/utils/sync-cache.d.ts.map +1 -0
- package/dist/utils/sync-cache.js +153 -0
- package/dist/utils/sync-cache.js.map +1 -0
- package/dist/utils/sync-cache.test.d.ts +2 -0
- package/dist/utils/sync-cache.test.d.ts.map +1 -0
- package/dist/utils/sync-cache.test.js +205 -0
- package/dist/utils/sync-cache.test.js.map +1 -0
- package/dist/utils/validation.d.ts +37 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +67 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-specific patterns for detecting i18n locale files
|
|
3
|
+
*/
|
|
4
|
+
export const FRAMEWORK_PATTERNS = {
|
|
5
|
+
"next-intl": {
|
|
6
|
+
configFiles: [
|
|
7
|
+
"next.config.js",
|
|
8
|
+
"next.config.mjs",
|
|
9
|
+
"next.config.ts",
|
|
10
|
+
"i18n.ts",
|
|
11
|
+
"i18n.js",
|
|
12
|
+
"src/i18n.ts",
|
|
13
|
+
"src/i18n.js",
|
|
14
|
+
],
|
|
15
|
+
localeGlobs: [
|
|
16
|
+
"messages/*.json",
|
|
17
|
+
"messages/*/*.json",
|
|
18
|
+
"locales/*.json",
|
|
19
|
+
"locales/*/*.json",
|
|
20
|
+
"src/messages/*.json",
|
|
21
|
+
"src/locales/*.json",
|
|
22
|
+
],
|
|
23
|
+
configPattern: /next-intl|createNextIntlPlugin|NextIntlClientProvider/,
|
|
24
|
+
},
|
|
25
|
+
i18next: {
|
|
26
|
+
configFiles: [
|
|
27
|
+
"i18n.js",
|
|
28
|
+
"i18n.ts",
|
|
29
|
+
"i18next.config.js",
|
|
30
|
+
"i18next.config.ts",
|
|
31
|
+
"next-i18next.config.js",
|
|
32
|
+
"src/i18n/index.ts",
|
|
33
|
+
"src/i18n/index.js",
|
|
34
|
+
],
|
|
35
|
+
localeGlobs: [
|
|
36
|
+
"public/locales/*/*.json",
|
|
37
|
+
"locales/*/*.json",
|
|
38
|
+
"src/locales/*/*.json",
|
|
39
|
+
"translations/*/*.json",
|
|
40
|
+
],
|
|
41
|
+
configPattern: /i18next|next-i18next|react-i18next/,
|
|
42
|
+
},
|
|
43
|
+
"react-intl": {
|
|
44
|
+
configFiles: ["src/i18n/index.ts", "src/i18n/index.js", "src/i18n.ts"],
|
|
45
|
+
localeGlobs: [
|
|
46
|
+
"src/lang/*.json",
|
|
47
|
+
"src/locales/*.json",
|
|
48
|
+
"lang/*.json",
|
|
49
|
+
"compiled-lang/*.json",
|
|
50
|
+
],
|
|
51
|
+
configPattern: /react-intl|IntlProvider|formatMessage/,
|
|
52
|
+
},
|
|
53
|
+
generic: {
|
|
54
|
+
configFiles: [],
|
|
55
|
+
localeGlobs: [
|
|
56
|
+
"locales/*.json",
|
|
57
|
+
"translations/*.json",
|
|
58
|
+
"i18n/*.json",
|
|
59
|
+
"lang/*.json",
|
|
60
|
+
"messages/*.json",
|
|
61
|
+
"src/locales/*.json",
|
|
62
|
+
"src/translations/*.json",
|
|
63
|
+
"src/i18n/*.json",
|
|
64
|
+
"public/locales/*.json",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Common language codes
|
|
70
|
+
*/
|
|
71
|
+
export const COMMON_LANGUAGE_CODES = [
|
|
72
|
+
"en",
|
|
73
|
+
"de",
|
|
74
|
+
"fr",
|
|
75
|
+
"es",
|
|
76
|
+
"it",
|
|
77
|
+
"pt",
|
|
78
|
+
"nl",
|
|
79
|
+
"pl",
|
|
80
|
+
"ru",
|
|
81
|
+
"ja",
|
|
82
|
+
"ko",
|
|
83
|
+
"zh",
|
|
84
|
+
"ar",
|
|
85
|
+
"hi",
|
|
86
|
+
"tr",
|
|
87
|
+
"sv",
|
|
88
|
+
"da",
|
|
89
|
+
"no",
|
|
90
|
+
"fi",
|
|
91
|
+
"cs",
|
|
92
|
+
"hu",
|
|
93
|
+
"ro",
|
|
94
|
+
"bg",
|
|
95
|
+
"uk",
|
|
96
|
+
"he",
|
|
97
|
+
"th",
|
|
98
|
+
"vi",
|
|
99
|
+
"id",
|
|
100
|
+
"ms",
|
|
101
|
+
"el",
|
|
102
|
+
"sk",
|
|
103
|
+
"hr",
|
|
104
|
+
"sl",
|
|
105
|
+
"lt",
|
|
106
|
+
"lv",
|
|
107
|
+
"et",
|
|
108
|
+
// With regions
|
|
109
|
+
"en-US",
|
|
110
|
+
"en-GB",
|
|
111
|
+
"en-AU",
|
|
112
|
+
"pt-BR",
|
|
113
|
+
"pt-PT",
|
|
114
|
+
"zh-CN",
|
|
115
|
+
"zh-TW",
|
|
116
|
+
"es-ES",
|
|
117
|
+
"es-MX",
|
|
118
|
+
"fr-FR",
|
|
119
|
+
"fr-CA",
|
|
120
|
+
"de-DE",
|
|
121
|
+
"de-AT",
|
|
122
|
+
"de-CH",
|
|
123
|
+
];
|
|
124
|
+
/**
|
|
125
|
+
* Check if a string looks like a language code
|
|
126
|
+
*/
|
|
127
|
+
export function isLikelyLanguageCode(str) {
|
|
128
|
+
// Check exact match first
|
|
129
|
+
if (COMMON_LANGUAGE_CODES.includes(str)) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
// Check pattern: 2 lowercase letters, optionally followed by - and more
|
|
133
|
+
return /^[a-z]{2}(-[A-Z]{2})?$/.test(str);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/locale-detection/patterns.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,MAAM,CAAC,MAAM,kBAAkB,GAAqC;IAClE,WAAW,EAAE;QACX,WAAW,EAAE;YACX,gBAAgB;YAChB,iBAAiB;YACjB,gBAAgB;YAChB,SAAS;YACT,SAAS;YACT,aAAa;YACb,aAAa;SACd;QACD,WAAW,EAAE;YACX,iBAAiB;YACjB,mBAAmB;YACnB,gBAAgB;YAChB,kBAAkB;YAClB,qBAAqB;YACrB,oBAAoB;SACrB;QACD,aAAa,EAAE,uDAAuD;KACvE;IACD,OAAO,EAAE;QACP,WAAW,EAAE;YACX,SAAS;YACT,SAAS;YACT,mBAAmB;YACnB,mBAAmB;YACnB,wBAAwB;YACxB,mBAAmB;YACnB,mBAAmB;SACpB;QACD,WAAW,EAAE;YACX,yBAAyB;YACzB,kBAAkB;YAClB,sBAAsB;YACtB,uBAAuB;SACxB;QACD,aAAa,EAAE,oCAAoC;KACpD;IACD,YAAY,EAAE;QACZ,WAAW,EAAE,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,aAAa,CAAC;QACtE,WAAW,EAAE;YACX,iBAAiB;YACjB,oBAAoB;YACpB,aAAa;YACb,sBAAsB;SACvB;QACD,aAAa,EAAE,uCAAuC;KACvD;IACD,OAAO,EAAE;QACP,WAAW,EAAE,EAAE;QACf,WAAW,EAAE;YACX,gBAAgB;YAChB,qBAAqB;YACrB,aAAa;YACb,aAAa;YACb,iBAAiB;YACjB,oBAAoB;YACpB,yBAAyB;YACzB,iBAAiB;YACjB,uBAAuB;SACxB;KACF;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,eAAe;IACf,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;CACR,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,0BAA0B;IAC1B,IAAI,qBAAqB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,wEAAwE;IACxE,OAAO,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5C,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE;;GAEG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAaxC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server setup for LangAPI
|
|
3
|
+
*/
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { registerListLocalLocales } from "./tools/list-local-locales.js";
|
|
6
|
+
import { registerGetTranslationStatus } from "./tools/get-translation-status.js";
|
|
7
|
+
import { registerSyncTranslations } from "./tools/sync-translations.js";
|
|
8
|
+
import { registerGetDiff } from "./tools/get-diff.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create and configure the MCP server
|
|
11
|
+
*/
|
|
12
|
+
export function createServer() {
|
|
13
|
+
const server = new McpServer({
|
|
14
|
+
name: "langapi-mcp-server",
|
|
15
|
+
version: "1.0.0",
|
|
16
|
+
});
|
|
17
|
+
// Register all tools
|
|
18
|
+
registerListLocalLocales(server);
|
|
19
|
+
registerGetTranslationStatus(server);
|
|
20
|
+
registerSyncTranslations(server);
|
|
21
|
+
registerGetDiff(server);
|
|
22
|
+
return server;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,qBAAqB;IACrB,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IACrC,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* get_diff MCP Tool
|
|
3
|
+
* Compare source locale against sync cache to identify new/changed/removed keys
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
declare const GetDiffSchema: z.ZodObject<{
|
|
8
|
+
source_lang: z.ZodString;
|
|
9
|
+
project_path: z.ZodOptional<z.ZodString>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
source_lang: string;
|
|
12
|
+
project_path?: string | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
source_lang: string;
|
|
15
|
+
project_path?: string | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export type GetDiffInput = z.infer<typeof GetDiffSchema>;
|
|
18
|
+
/**
|
|
19
|
+
* Register the get_diff tool with the MCP server
|
|
20
|
+
*/
|
|
21
|
+
export declare function registerGetDiff(server: McpServer): void;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=get-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-diff.d.ts","sourceRoot":"","sources":["../../src/tools/get-diff.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,QAAA,MAAM,aAAa;;;;;;;;;EAMjB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAuCzD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiFvD"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* get_diff MCP Tool
|
|
3
|
+
* Compare source locale against sync cache to identify new/changed/removed keys
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { readFile } from "fs/promises";
|
|
7
|
+
import { detectLocales } from "../locale-detection/index.js";
|
|
8
|
+
import { flattenJson, parseJsonSafe } from "../utils/json-parser.js";
|
|
9
|
+
import { languageCodeSchema } from "../utils/validation.js";
|
|
10
|
+
import { readSyncCache, getFullDiff } from "../utils/sync-cache.js";
|
|
11
|
+
// Input schema
|
|
12
|
+
const GetDiffSchema = z.object({
|
|
13
|
+
source_lang: languageCodeSchema.describe("Source language code (e.g., 'en', 'pt-BR')"),
|
|
14
|
+
project_path: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Root path of the project. Defaults to current working directory."),
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Register the get_diff tool with the MCP server
|
|
21
|
+
*/
|
|
22
|
+
export function registerGetDiff(server) {
|
|
23
|
+
server.tool("get_diff", "Compare current source locale content against the sync cache to see what's new, changed, unchanged, or removed since the last sync.", GetDiffSchema.shape, async (args) => {
|
|
24
|
+
const input = GetDiffSchema.parse(args);
|
|
25
|
+
const projectPath = input.project_path || process.cwd();
|
|
26
|
+
// Detect locales
|
|
27
|
+
const detection = await detectLocales(projectPath, false);
|
|
28
|
+
// Find source locale
|
|
29
|
+
const sourceLocale = detection.locales.find((l) => l.lang === input.source_lang);
|
|
30
|
+
if (!sourceLocale) {
|
|
31
|
+
const output = {
|
|
32
|
+
success: false,
|
|
33
|
+
error: {
|
|
34
|
+
code: "SOURCE_NOT_FOUND",
|
|
35
|
+
message: `Source language '${input.source_lang}' not found in project`,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: JSON.stringify(output, null, 2) }],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Read and parse source files
|
|
43
|
+
const sourceContent = {};
|
|
44
|
+
for (const file of sourceLocale.files) {
|
|
45
|
+
const content = await readFile(file.path, "utf-8");
|
|
46
|
+
const parsed = parseJsonSafe(content);
|
|
47
|
+
if (parsed) {
|
|
48
|
+
Object.assign(sourceContent, parsed);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Flatten source content
|
|
52
|
+
const flatContent = flattenJson(sourceContent);
|
|
53
|
+
// Read cache
|
|
54
|
+
const cachedContent = await readSyncCache(projectPath, input.source_lang);
|
|
55
|
+
// Get full diff
|
|
56
|
+
const diff = getFullDiff(flatContent, cachedContent);
|
|
57
|
+
const totalCached = cachedContent ? Object.keys(cachedContent).length : 0;
|
|
58
|
+
const output = {
|
|
59
|
+
success: true,
|
|
60
|
+
cache_exists: cachedContent !== null,
|
|
61
|
+
diff: {
|
|
62
|
+
new_keys: diff.newKeys,
|
|
63
|
+
changed_keys: diff.changedKeys.map((c) => ({
|
|
64
|
+
key: c.key,
|
|
65
|
+
old_value: c.oldValue,
|
|
66
|
+
new_value: c.newValue,
|
|
67
|
+
})),
|
|
68
|
+
unchanged_keys: diff.unchangedKeys,
|
|
69
|
+
removed_keys: diff.removedKeys,
|
|
70
|
+
},
|
|
71
|
+
summary: {
|
|
72
|
+
total_current: flatContent.length,
|
|
73
|
+
total_cached: totalCached,
|
|
74
|
+
new_count: diff.newKeys.length,
|
|
75
|
+
changed_count: diff.changedKeys.length,
|
|
76
|
+
unchanged_count: diff.unchangedKeys.length,
|
|
77
|
+
removed_count: diff.removedKeys.length,
|
|
78
|
+
},
|
|
79
|
+
message: cachedContent
|
|
80
|
+
? `Found ${diff.newKeys.length} new, ${diff.changedKeys.length} changed, ${diff.unchangedKeys.length} unchanged, ${diff.removedKeys.length} removed keys.`
|
|
81
|
+
: `No sync cache found. All ${flatContent.length} keys will be treated as new on first sync.`,
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text", text: JSON.stringify(output, null, 2) }],
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=get-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-diff.js","sourceRoot":"","sources":["../../src/tools/get-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* get_translation_status MCP Tool
|
|
3
|
+
* Compare source locale against targets to identify missing/outdated keys
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
declare const GetTranslationStatusSchema: z.ZodObject<{
|
|
8
|
+
source_lang: z.ZodString;
|
|
9
|
+
target_langs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
10
|
+
project_path: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
source_lang: string;
|
|
13
|
+
project_path?: string | undefined;
|
|
14
|
+
target_langs?: string[] | undefined;
|
|
15
|
+
}, {
|
|
16
|
+
source_lang: string;
|
|
17
|
+
project_path?: string | undefined;
|
|
18
|
+
target_langs?: string[] | undefined;
|
|
19
|
+
}>;
|
|
20
|
+
export type GetTranslationStatusInput = z.infer<typeof GetTranslationStatusSchema>;
|
|
21
|
+
interface TargetStatus {
|
|
22
|
+
lang: string;
|
|
23
|
+
status: "synced" | "outdated" | "missing";
|
|
24
|
+
keys: {
|
|
25
|
+
total: number;
|
|
26
|
+
missing: string[];
|
|
27
|
+
extra: string[];
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
interface CostEstimate {
|
|
31
|
+
words_to_translate: number;
|
|
32
|
+
credits_required: number;
|
|
33
|
+
current_balance?: number;
|
|
34
|
+
balance_after_sync?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface GetTranslationStatusOutput {
|
|
37
|
+
source_lang: string;
|
|
38
|
+
source_keys: number;
|
|
39
|
+
targets: TargetStatus[];
|
|
40
|
+
cost_estimate: CostEstimate | null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Register the get_translation_status tool with the MCP server
|
|
44
|
+
*/
|
|
45
|
+
export declare function registerGetTranslationStatus(server: McpServer): void;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=get-translation-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-translation-status.d.ts","sourceRoot":"","sources":["../../src/tools/get-translation-status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,QAAA,MAAM,0BAA0B;;;;;;;;;;;;EAY9B,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAGnF,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC1C,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;CACH;AAED,UAAU,YAAY;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;CACpC;AAkBD;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwKpE"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* get_translation_status MCP Tool
|
|
3
|
+
* Compare source locale against targets to identify missing/outdated keys
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { readFile } from "fs/promises";
|
|
7
|
+
import { detectLocales } from "../locale-detection/index.js";
|
|
8
|
+
import { getAllKeys, parseJsonSafe, flattenJson } from "../utils/json-parser.js";
|
|
9
|
+
import { LangAPIClient } from "../api/client.js";
|
|
10
|
+
import { languageCodeSchema } from "../utils/validation.js";
|
|
11
|
+
// Input schema
|
|
12
|
+
const GetTranslationStatusSchema = z.object({
|
|
13
|
+
source_lang: languageCodeSchema.describe("Source language code (e.g., 'en', 'pt-BR')"),
|
|
14
|
+
target_langs: z
|
|
15
|
+
.array(languageCodeSchema)
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Target language codes. If not provided, all detected locales except source will be used."),
|
|
18
|
+
project_path: z
|
|
19
|
+
.string()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("Root path of the project. Defaults to current working directory."),
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Count words in translation values (excluding template variables)
|
|
25
|
+
*/
|
|
26
|
+
function countWords(text) {
|
|
27
|
+
// Remove template variables like {{name}}, {count}, %s, %d, ${var}
|
|
28
|
+
const cleaned = text
|
|
29
|
+
.replace(/\{\{[^}]+\}\}/g, "")
|
|
30
|
+
.replace(/\{[^}]+\}/g, "")
|
|
31
|
+
.replace(/%[sd]/g, "")
|
|
32
|
+
.replace(/\$\{[^}]+\}/g, "");
|
|
33
|
+
// Count words
|
|
34
|
+
const words = cleaned.trim().split(/\s+/).filter((w) => w.length > 0);
|
|
35
|
+
return words.length;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register the get_translation_status tool with the MCP server
|
|
39
|
+
*/
|
|
40
|
+
export function registerGetTranslationStatus(server) {
|
|
41
|
+
server.tool("get_translation_status", "Compare source locale against target locales to identify missing/outdated keys and estimate translation costs.", GetTranslationStatusSchema.shape, async (args) => {
|
|
42
|
+
const input = GetTranslationStatusSchema.parse(args);
|
|
43
|
+
const projectPath = input.project_path || process.cwd();
|
|
44
|
+
// Detect locales
|
|
45
|
+
const detection = await detectLocales(projectPath, true);
|
|
46
|
+
// Find source locale
|
|
47
|
+
const sourceLocale = detection.locales.find((l) => l.lang === input.source_lang);
|
|
48
|
+
if (!sourceLocale) {
|
|
49
|
+
throw new Error(`Source language '${input.source_lang}' not found in project`);
|
|
50
|
+
}
|
|
51
|
+
// Read and parse source files
|
|
52
|
+
const sourceContent = {};
|
|
53
|
+
for (const file of sourceLocale.files) {
|
|
54
|
+
const content = await readFile(file.path, "utf-8");
|
|
55
|
+
const parsed = parseJsonSafe(content);
|
|
56
|
+
if (parsed) {
|
|
57
|
+
Object.assign(sourceContent, parsed);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const sourceKeys = getAllKeys(sourceContent);
|
|
61
|
+
const sourceKeySet = new Set(sourceKeys);
|
|
62
|
+
// Determine target languages
|
|
63
|
+
let targetLangs = input.target_langs;
|
|
64
|
+
if (!targetLangs || targetLangs.length === 0) {
|
|
65
|
+
targetLangs = detection.locales
|
|
66
|
+
.filter((l) => l.lang !== input.source_lang)
|
|
67
|
+
.map((l) => l.lang);
|
|
68
|
+
}
|
|
69
|
+
// Compare with each target
|
|
70
|
+
const targets = [];
|
|
71
|
+
let totalMissingKeys = [];
|
|
72
|
+
for (const targetLang of targetLangs) {
|
|
73
|
+
const targetLocale = detection.locales.find((l) => l.lang === targetLang);
|
|
74
|
+
if (!targetLocale) {
|
|
75
|
+
// Target language doesn't exist
|
|
76
|
+
targets.push({
|
|
77
|
+
lang: targetLang,
|
|
78
|
+
status: "missing",
|
|
79
|
+
keys: {
|
|
80
|
+
total: 0,
|
|
81
|
+
missing: sourceKeys,
|
|
82
|
+
extra: [],
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
totalMissingKeys.push(...sourceKeys);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Read and parse target files
|
|
89
|
+
const targetContent = {};
|
|
90
|
+
for (const file of targetLocale.files) {
|
|
91
|
+
try {
|
|
92
|
+
const content = await readFile(file.path, "utf-8");
|
|
93
|
+
const parsed = parseJsonSafe(content);
|
|
94
|
+
if (parsed) {
|
|
95
|
+
Object.assign(targetContent, parsed);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Ignore read errors
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const targetKeys = getAllKeys(targetContent);
|
|
103
|
+
const targetKeySet = new Set(targetKeys);
|
|
104
|
+
// Find missing and extra keys
|
|
105
|
+
const missing = sourceKeys.filter((k) => !targetKeySet.has(k));
|
|
106
|
+
const extra = targetKeys.filter((k) => !sourceKeySet.has(k));
|
|
107
|
+
const status = missing.length === 0 && extra.length === 0
|
|
108
|
+
? "synced"
|
|
109
|
+
: missing.length > 0
|
|
110
|
+
? "outdated"
|
|
111
|
+
: "synced";
|
|
112
|
+
targets.push({
|
|
113
|
+
lang: targetLang,
|
|
114
|
+
status,
|
|
115
|
+
keys: {
|
|
116
|
+
total: targetKeys.length,
|
|
117
|
+
missing,
|
|
118
|
+
extra,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
totalMissingKeys.push(...missing);
|
|
122
|
+
}
|
|
123
|
+
// Estimate cost locally
|
|
124
|
+
let costEstimate = null;
|
|
125
|
+
// Calculate words to translate from source content
|
|
126
|
+
const flatSource = flattenJson(sourceContent);
|
|
127
|
+
const missingKeySet = new Set(totalMissingKeys);
|
|
128
|
+
const itemsToTranslate = flatSource.filter((item) => missingKeySet.has(item.key));
|
|
129
|
+
const wordsToTranslate = itemsToTranslate.reduce((sum, item) => sum + countWords(item.value), 0);
|
|
130
|
+
// credits = words * number of target languages
|
|
131
|
+
const creditsRequired = wordsToTranslate * targetLangs.length;
|
|
132
|
+
costEstimate = {
|
|
133
|
+
words_to_translate: wordsToTranslate,
|
|
134
|
+
credits_required: creditsRequired,
|
|
135
|
+
};
|
|
136
|
+
// Get accurate estimate from server if API key is configured
|
|
137
|
+
if (LangAPIClient.canCreate()) {
|
|
138
|
+
try {
|
|
139
|
+
const client = LangAPIClient.create();
|
|
140
|
+
const response = await client.sync({
|
|
141
|
+
source_lang: input.source_lang,
|
|
142
|
+
target_langs: targetLangs,
|
|
143
|
+
content: flatSource,
|
|
144
|
+
dry_run: true,
|
|
145
|
+
});
|
|
146
|
+
if (response.success && "delta" in response) {
|
|
147
|
+
// This is a SyncDryRunResponse
|
|
148
|
+
costEstimate = {
|
|
149
|
+
words_to_translate: response.cost.wordsToTranslate,
|
|
150
|
+
credits_required: response.cost.creditsRequired,
|
|
151
|
+
current_balance: response.cost.currentBalance,
|
|
152
|
+
balance_after_sync: response.cost.balanceAfterSync,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Fall back to local estimate
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const output = {
|
|
161
|
+
source_lang: input.source_lang,
|
|
162
|
+
source_keys: sourceKeys.length,
|
|
163
|
+
targets,
|
|
164
|
+
cost_estimate: costEstimate,
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
content: [
|
|
168
|
+
{
|
|
169
|
+
type: "text",
|
|
170
|
+
text: JSON.stringify(output, null, 2),
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=get-translation-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-translation-status.js","sourceRoot":"","sources":["../../src/tools/get-translation-status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,eAAe;AACf,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,WAAW,EAAE,kBAAkB,CAAC,QAAQ,CAAC,4CAA4C,CAAC;IACtF,YAAY,EAAE,CAAC;SACZ,KAAK,CAAC,kBAAkB,CAAC;SACzB,QAAQ,EAAE;SACV,QAAQ,CACP,0FAA0F,CAC3F;IACH,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,kEAAkE,CAAC;CAChF,CAAC,CAAC;AA6BH;;GAEG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,mEAAmE;IACnE,MAAM,OAAO,GAAG,IAAI;SACjB,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;SAC7B,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAE/B,cAAc;IACd,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtE,OAAO,KAAK,CAAC,MAAM,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,4BAA4B,CAAC,MAAiB;IAC5D,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,gHAAgH,EAChH,0BAA0B,CAAC,KAAK,EAChC,KAAK,EAAE,IAAI,EAA+D,EAAE;QAC1E,MAAM,KAAK,GAAG,0BAA0B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,KAAK,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAExD,iBAAiB;QACjB,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAEzD,qBAAqB;QACrB,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,CACpC,CAAC;QACF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,oBAAoB,KAAK,CAAC,WAAW,wBAAwB,CAAC,CAAC;QACjF,CAAC;QAED,8BAA8B;QAC9B,MAAM,aAAa,GAA4B,EAAE,CAAC;QAClD,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YACtC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;QAC7C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QAEzC,6BAA6B;QAC7B,IAAI,WAAW,GAAG,KAAK,CAAC,YAAY,CAAC;QACrC,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,WAAW,GAAG,SAAS,CAAC,OAAO;iBAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,CAAC;iBAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAED,2BAA2B;QAC3B,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,IAAI,gBAAgB,GAAa,EAAE,CAAC;QAEpC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;YAE1E,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,gCAAgC;gBAChC,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,SAAS;oBACjB,IAAI,EAAE;wBACJ,KAAK,EAAE,CAAC;wBACR,OAAO,EAAE,UAAU;wBACnB,KAAK,EAAE,EAAE;qBACV;iBACF,CAAC,CAAC;gBACH,gBAAgB,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;gBACrC,SAAS;YACX,CAAC;YAED,8BAA8B;YAC9B,MAAM,aAAa,GAA4B,EAAE,CAAC;YAClD,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC;gBACtC,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;oBACnD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;oBACtC,IAAI,MAAM,EAAE,CAAC;wBACX,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;oBACvC,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,qBAAqB;gBACvB,CAAC;YACH,CAAC;YAED,MAAM,UAAU,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;YAC7C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;YAEzC,8BAA8B;YAC9B,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/D,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAE7D,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBACxC,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;oBACpB,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,QAAQ,CAAC;YAEf,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,UAAU;gBAChB,MAAM;gBACN,IAAI,EAAE;oBACJ,KAAK,EAAE,UAAU,CAAC,MAAM;oBACxB,OAAO;oBACP,KAAK;iBACN;aACF,CAAC,CAAC;YAEH,gBAAgB,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;QACpC,CAAC;QAED,wBAAwB;QACxB,IAAI,YAAY,GAAwB,IAAI,CAAC;QAE7C,mDAAmD;QACnD,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC;QAC9C,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAChD,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAClD,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAC5B,CAAC;QACF,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAC9C,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAC3C,CAAC,CACF,CAAC;QAEF,+CAA+C;QAC/C,MAAM,eAAe,GAAG,gBAAgB,GAAG,WAAW,CAAC,MAAM,CAAC;QAE9D,YAAY,GAAG;YACb,kBAAkB,EAAE,gBAAgB;YACpC,gBAAgB,EAAE,eAAe;SAClC,CAAC;QAEF,6DAA6D;QAC7D,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;oBACjC,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,YAAY,EAAE,WAAW;oBACzB,OAAO,EAAE,UAAU;oBACnB,OAAO,EAAE,IAAI;iBACd,CAAC,CAAC;gBAEH,IAAI,QAAQ,CAAC,OAAO,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC5C,+BAA+B;oBAC/B,YAAY,GAAG;wBACb,kBAAkB,EAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB;wBAClD,gBAAgB,EAAE,QAAQ,CAAC,IAAI,CAAC,eAAe;wBAC/C,eAAe,EAAE,QAAQ,CAAC,IAAI,CAAC,cAAc;wBAC7C,kBAAkB,EAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB;qBACnD,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,8BAA8B;YAChC,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAA+B;YACzC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,WAAW,EAAE,UAAU,CAAC,MAAM;YAC9B,OAAO;YACP,aAAa,EAAE,YAAY;SAC5B,CAAC;QAEF,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;iBACtC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_local_locales MCP Tool
|
|
3
|
+
* Scans project for locale JSON files and detects i18n framework
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
declare const ListLocalLocalesSchema: z.ZodObject<{
|
|
8
|
+
project_path: z.ZodOptional<z.ZodString>;
|
|
9
|
+
include_key_count: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
include_key_count: boolean;
|
|
12
|
+
project_path?: string | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
project_path?: string | undefined;
|
|
15
|
+
include_key_count?: boolean | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export type ListLocalLocalesInput = z.infer<typeof ListLocalLocalesSchema>;
|
|
18
|
+
export interface ListLocalLocalesOutput {
|
|
19
|
+
framework: string;
|
|
20
|
+
confidence: "high" | "medium" | "low";
|
|
21
|
+
source_lang: string | null;
|
|
22
|
+
locales_path: string | null;
|
|
23
|
+
locales: Array<{
|
|
24
|
+
lang: string;
|
|
25
|
+
files: Array<{
|
|
26
|
+
path: string;
|
|
27
|
+
namespace: string | null;
|
|
28
|
+
key_count: number;
|
|
29
|
+
}>;
|
|
30
|
+
total_keys: number;
|
|
31
|
+
}>;
|
|
32
|
+
config_file: string | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Register the list_local_locales tool with the MCP server
|
|
36
|
+
*/
|
|
37
|
+
export declare function registerListLocalLocales(server: McpServer): void;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=list-local-locales.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-local-locales.d.ts","sourceRoot":"","sources":["../../src/tools/list-local-locales.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,QAAA,MAAM,sBAAsB;;;;;;;;;EAW1B,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAG3E,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,KAAK,CAAC;YACX,IAAI,EAAE,MAAM,CAAC;YACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;YACzB,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC,CAAC;QACH,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsChE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_local_locales MCP Tool
|
|
3
|
+
* Scans project for locale JSON files and detects i18n framework
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { detectLocales } from "../locale-detection/index.js";
|
|
7
|
+
// Input schema
|
|
8
|
+
const ListLocalLocalesSchema = z.object({
|
|
9
|
+
project_path: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Root path of the project to scan. Defaults to current working directory."),
|
|
13
|
+
include_key_count: z
|
|
14
|
+
.boolean()
|
|
15
|
+
.default(true)
|
|
16
|
+
.describe("Whether to count keys in each locale file"),
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Register the list_local_locales tool with the MCP server
|
|
20
|
+
*/
|
|
21
|
+
export function registerListLocalLocales(server) {
|
|
22
|
+
server.tool("list_local_locales", "Scan project for locale JSON files, detect i18n framework (next-intl, i18next, react-intl, generic), and return structured information about available translations.", ListLocalLocalesSchema.shape, async (args) => {
|
|
23
|
+
const input = ListLocalLocalesSchema.parse(args);
|
|
24
|
+
const projectPath = input.project_path || process.cwd();
|
|
25
|
+
const result = await detectLocales(projectPath, input.include_key_count);
|
|
26
|
+
const output = {
|
|
27
|
+
framework: result.framework,
|
|
28
|
+
confidence: result.confidence,
|
|
29
|
+
source_lang: result.sourceLang,
|
|
30
|
+
locales_path: result.localesPath,
|
|
31
|
+
locales: result.locales.map((locale) => ({
|
|
32
|
+
lang: locale.lang,
|
|
33
|
+
files: locale.files.map((file) => ({
|
|
34
|
+
path: file.relativePath,
|
|
35
|
+
namespace: file.namespace,
|
|
36
|
+
key_count: file.keyCount,
|
|
37
|
+
})),
|
|
38
|
+
total_keys: locale.totalKeys,
|
|
39
|
+
})),
|
|
40
|
+
config_file: result.configFile,
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: JSON.stringify(output, null, 2),
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=list-local-locales.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-local-locales.js","sourceRoot":"","sources":["../../src/tools/list-local-locales.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,eAAe;AACf,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,0EAA0E,CAC3E;IACH,iBAAiB,EAAE,CAAC;SACjB,OAAO,EAAE;SACT,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CAAC,2CAA2C,CAAC;CACzD,CAAC,CAAC;AAsBH;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,sKAAsK,EACtK,sBAAsB,CAAC,KAAK,EAC5B,KAAK,EAAE,IAAI,EAA+D,EAAE;QAC1E,MAAM,KAAK,GAAG,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,KAAK,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAExD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAEzE,MAAM,MAAM,GAA2B;YACrC,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,WAAW,EAAE,MAAM,CAAC,UAAU;YAC9B,YAAY,EAAE,MAAM,CAAC,WAAW;YAChC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBACvC,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBACjC,IAAI,EAAE,IAAI,CAAC,YAAY;oBACvB,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,SAAS,EAAE,IAAI,CAAC,QAAQ;iBACzB,CAAC,CAAC;gBACH,UAAU,EAAE,MAAM,CAAC,SAAS;aAC7B,CAAC,CAAC;YACH,WAAW,EAAE,MAAM,CAAC,UAAU;SAC/B,CAAC;QAEF,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;iBACtC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|