@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.
Files changed (67) hide show
  1. package/README.md +551 -0
  2. package/bin/langapi-mcp.js +11 -0
  3. package/dist/api/client.d.ts +24 -0
  4. package/dist/api/client.d.ts.map +1 -0
  5. package/dist/api/client.js +145 -0
  6. package/dist/api/client.js.map +1 -0
  7. package/dist/api/types.d.ts +56 -0
  8. package/dist/api/types.d.ts.map +1 -0
  9. package/dist/api/types.js +6 -0
  10. package/dist/api/types.js.map +1 -0
  11. package/dist/config/env.d.ts +18 -0
  12. package/dist/config/env.d.ts.map +1 -0
  13. package/dist/config/env.js +29 -0
  14. package/dist/config/env.js.map +1 -0
  15. package/dist/index.d.ts +15 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +25 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/locale-detection/index.d.ts +41 -0
  20. package/dist/locale-detection/index.d.ts.map +1 -0
  21. package/dist/locale-detection/index.js +188 -0
  22. package/dist/locale-detection/index.js.map +1 -0
  23. package/dist/locale-detection/patterns.d.ts +21 -0
  24. package/dist/locale-detection/patterns.d.ts.map +1 -0
  25. package/dist/locale-detection/patterns.js +135 -0
  26. package/dist/locale-detection/patterns.js.map +1 -0
  27. package/dist/server.d.ts +9 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +24 -0
  30. package/dist/server.js.map +1 -0
  31. package/dist/tools/get-diff.d.ts +23 -0
  32. package/dist/tools/get-diff.d.ts.map +1 -0
  33. package/dist/tools/get-diff.js +88 -0
  34. package/dist/tools/get-diff.js.map +1 -0
  35. package/dist/tools/get-translation-status.d.ts +47 -0
  36. package/dist/tools/get-translation-status.d.ts.map +1 -0
  37. package/dist/tools/get-translation-status.js +176 -0
  38. package/dist/tools/get-translation-status.js.map +1 -0
  39. package/dist/tools/list-local-locales.d.ts +39 -0
  40. package/dist/tools/list-local-locales.d.ts.map +1 -0
  41. package/dist/tools/list-local-locales.js +52 -0
  42. package/dist/tools/list-local-locales.js.map +1 -0
  43. package/dist/tools/sync-translations.d.ts +35 -0
  44. package/dist/tools/sync-translations.d.ts.map +1 -0
  45. package/dist/tools/sync-translations.js +629 -0
  46. package/dist/tools/sync-translations.js.map +1 -0
  47. package/dist/utils/format-preserve.d.ts +25 -0
  48. package/dist/utils/format-preserve.d.ts.map +1 -0
  49. package/dist/utils/format-preserve.js +56 -0
  50. package/dist/utils/format-preserve.js.map +1 -0
  51. package/dist/utils/json-parser.d.ts +33 -0
  52. package/dist/utils/json-parser.d.ts.map +1 -0
  53. package/dist/utils/json-parser.js +92 -0
  54. package/dist/utils/json-parser.js.map +1 -0
  55. package/dist/utils/sync-cache.d.ts +40 -0
  56. package/dist/utils/sync-cache.d.ts.map +1 -0
  57. package/dist/utils/sync-cache.js +153 -0
  58. package/dist/utils/sync-cache.js.map +1 -0
  59. package/dist/utils/sync-cache.test.d.ts +2 -0
  60. package/dist/utils/sync-cache.test.d.ts.map +1 -0
  61. package/dist/utils/sync-cache.test.js +205 -0
  62. package/dist/utils/sync-cache.test.js.map +1 -0
  63. package/dist/utils/validation.d.ts +37 -0
  64. package/dist/utils/validation.d.ts.map +1 -0
  65. package/dist/utils/validation.js +67 -0
  66. package/dist/utils/validation.js.map +1 -0
  67. 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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * MCP Server setup for LangAPI
3
+ */
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ /**
6
+ * Create and configure the MCP server
7
+ */
8
+ export declare function createServer(): McpServer;
9
+ //# sourceMappingURL=server.d.ts.map
@@ -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"}