string-catalog-mcp 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 (62) hide show
  1. package/.prettierrc +8 -0
  2. package/README.md +127 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +23 -0
  5. package/dist/mcp/prompts/batch-translate.d.ts +2 -0
  6. package/dist/mcp/prompts/batch-translate.js +88 -0
  7. package/dist/mcp/prompts/index.d.ts +2 -0
  8. package/dist/mcp/prompts/index.js +12 -0
  9. package/dist/mcp/prompts/review-translations.d.ts +2 -0
  10. package/dist/mcp/prompts/review-translations.js +75 -0
  11. package/dist/mcp/prompts/translate-strings.d.ts +2 -0
  12. package/dist/mcp/prompts/translate-strings.js +81 -0
  13. package/dist/mcp/tools/get-catalog-statistics.d.ts +2 -0
  14. package/dist/mcp/tools/get-catalog-statistics.js +25 -0
  15. package/dist/mcp/tools/get-translations-for-key.d.ts +2 -0
  16. package/dist/mcp/tools/get-translations-for-key.js +36 -0
  17. package/dist/mcp/tools/index.d.ts +2 -0
  18. package/dist/mcp/tools/index.js +18 -0
  19. package/dist/mcp/tools/list-all-keys.d.ts +2 -0
  20. package/dist/mcp/tools/list-all-keys.js +44 -0
  21. package/dist/mcp/tools/list-supported-languages.d.ts +2 -0
  22. package/dist/mcp/tools/list-supported-languages.js +30 -0
  23. package/dist/mcp/tools/search-keys.d.ts +2 -0
  24. package/dist/mcp/tools/search-keys.js +32 -0
  25. package/dist/mcp/tools/update-translations.d.ts +2 -0
  26. package/dist/mcp/tools/update-translations.js +78 -0
  27. package/dist/string-catalog.d.ts +53 -0
  28. package/dist/string-catalog.js +220 -0
  29. package/dist/tools/get-catalog-statistics.d.ts +2 -0
  30. package/dist/tools/get-catalog-statistics.js +25 -0
  31. package/dist/tools/get-translations-for-key.d.ts +2 -0
  32. package/dist/tools/get-translations-for-key.js +36 -0
  33. package/dist/tools/index.d.ts +2 -0
  34. package/dist/tools/index.js +18 -0
  35. package/dist/tools/list-all-keys.d.ts +2 -0
  36. package/dist/tools/list-all-keys.js +44 -0
  37. package/dist/tools/list-supported-languages.d.ts +2 -0
  38. package/dist/tools/list-supported-languages.js +30 -0
  39. package/dist/tools/search-keys.d.ts +2 -0
  40. package/dist/tools/search-keys.js +32 -0
  41. package/dist/tools/update-translations.d.ts +2 -0
  42. package/dist/tools/update-translations.js +78 -0
  43. package/dist/types.d.ts +86 -0
  44. package/dist/types.js +6 -0
  45. package/eslint.config.js +23 -0
  46. package/images/mcp.jpeg +0 -0
  47. package/package.json +49 -0
  48. package/src/index.ts +25 -0
  49. package/src/mcp/prompts/batch-translate.ts +91 -0
  50. package/src/mcp/prompts/index.ts +10 -0
  51. package/src/mcp/prompts/review-translations.ts +79 -0
  52. package/src/mcp/prompts/translate-strings.ts +85 -0
  53. package/src/mcp/tools/get-catalog-statistics.ts +29 -0
  54. package/src/mcp/tools/get-translations-for-key.ts +45 -0
  55. package/src/mcp/tools/index.ts +16 -0
  56. package/src/mcp/tools/list-all-keys.ts +52 -0
  57. package/src/mcp/tools/list-supported-languages.ts +38 -0
  58. package/src/mcp/tools/search-keys.ts +40 -0
  59. package/src/mcp/tools/update-translations.ts +89 -0
  60. package/src/string-catalog.ts +232 -0
  61. package/src/types.ts +82 -0
  62. package/tsconfig.json +28 -0
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerListSupportedLanguages = registerListSupportedLanguages;
4
+ const zod_1 = require("zod");
5
+ const string_catalog_1 = require("../../string-catalog");
6
+ function registerListSupportedLanguages(server) {
7
+ server.registerTool('list_supported_languages', {
8
+ description: 'List all supported languages in a given Xcode String Catalog (.xcstrings) file. Returns the source language and all languages that have translations.',
9
+ inputSchema: {
10
+ filePath: zod_1.z.string().describe('Absolute path to the .xcstrings file'),
11
+ },
12
+ }, async ({ filePath }) => {
13
+ const catalog = new string_catalog_1.StringCatalog(filePath);
14
+ const languages = catalog.getSupportedLanguages();
15
+ const sourceLanguage = catalog.getSourceLanguage();
16
+ return {
17
+ content: [
18
+ {
19
+ type: 'text',
20
+ text: JSON.stringify({
21
+ sourceLanguage,
22
+ supportedLanguages: languages,
23
+ count: languages.length,
24
+ }, null, 2),
25
+ },
26
+ ],
27
+ };
28
+ });
29
+ }
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdC1zdXBwb3J0ZWQtbGFuZ3VhZ2VzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21jcC90b29scy9saXN0LXN1cHBvcnRlZC1sYW5ndWFnZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFJQSx3RUFpQ0M7QUFwQ0QsNkJBQXdCO0FBQ3hCLHlEQUFxRDtBQUVyRCxTQUFnQiw4QkFBOEIsQ0FBQyxNQUFpQjtJQUM1RCxNQUFNLENBQUMsWUFBWSxDQUNmLDBCQUEwQixFQUMxQjtRQUNJLFdBQVcsRUFDUCx1SkFBdUo7UUFDM0osV0FBVyxFQUFFO1lBQ1QsUUFBUSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsc0NBQXNDLENBQUM7U0FDeEU7S0FDSixFQUNELEtBQUssRUFBRSxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUU7UUFDbkIsTUFBTSxPQUFPLEdBQUcsSUFBSSw4QkFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzVDLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQ2xELE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBRW5ELE9BQU87WUFDSCxPQUFPLEVBQUU7Z0JBQ0w7b0JBQ0ksSUFBSSxFQUFFLE1BQWU7b0JBQ3JCLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUNoQjt3QkFDSSxjQUFjO3dCQUNkLGtCQUFrQixFQUFFLFNBQVM7d0JBQzdCLEtBQUssRUFBRSxTQUFTLENBQUMsTUFBTTtxQkFDMUIsRUFDRCxJQUFJLEVBQ0osQ0FBQyxDQUNKO2lCQUNKO2FBQ0o7U0FDSixDQUFDO0lBQ04sQ0FBQyxDQUNKLENBQUM7QUFDTixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTWNwU2VydmVyIH0gZnJvbSAnQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay9zZXJ2ZXIvbWNwLmpzJztcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuaW1wb3J0IHsgU3RyaW5nQ2F0YWxvZyB9IGZyb20gJy4uLy4uL3N0cmluZy1jYXRhbG9nJztcblxuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lzdGVyTGlzdFN1cHBvcnRlZExhbmd1YWdlcyhzZXJ2ZXI6IE1jcFNlcnZlcikge1xuICAgIHNlcnZlci5yZWdpc3RlclRvb2woXG4gICAgICAgICdsaXN0X3N1cHBvcnRlZF9sYW5ndWFnZXMnLFxuICAgICAgICB7XG4gICAgICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAgICAgICAnTGlzdCBhbGwgc3VwcG9ydGVkIGxhbmd1YWdlcyBpbiBhIGdpdmVuIFhjb2RlIFN0cmluZyBDYXRhbG9nICgueGNzdHJpbmdzKSBmaWxlLiBSZXR1cm5zIHRoZSBzb3VyY2UgbGFuZ3VhZ2UgYW5kIGFsbCBsYW5ndWFnZXMgdGhhdCBoYXZlIHRyYW5zbGF0aW9ucy4nLFxuICAgICAgICAgICAgaW5wdXRTY2hlbWE6IHtcbiAgICAgICAgICAgICAgICBmaWxlUGF0aDogei5zdHJpbmcoKS5kZXNjcmliZSgnQWJzb2x1dGUgcGF0aCB0byB0aGUgLnhjc3RyaW5ncyBmaWxlJyksXG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBhc3luYyAoeyBmaWxlUGF0aCB9KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjYXRhbG9nID0gbmV3IFN0cmluZ0NhdGFsb2coZmlsZVBhdGgpO1xuICAgICAgICAgICAgY29uc3QgbGFuZ3VhZ2VzID0gY2F0YWxvZy5nZXRTdXBwb3J0ZWRMYW5ndWFnZXMoKTtcbiAgICAgICAgICAgIGNvbnN0IHNvdXJjZUxhbmd1YWdlID0gY2F0YWxvZy5nZXRTb3VyY2VMYW5ndWFnZSgpO1xuXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ3RleHQnIGFzIGNvbnN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgdGV4dDogSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VMYW5ndWFnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VwcG9ydGVkTGFuZ3VhZ2VzOiBsYW5ndWFnZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50OiBsYW5ndWFnZXMubGVuZ3RoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgKTtcbn1cbiJdfQ==
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerSearchKeys(server: McpServer): void;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSearchKeys = registerSearchKeys;
4
+ const zod_1 = require("zod");
5
+ const string_catalog_1 = require("../../string-catalog");
6
+ function registerSearchKeys(server) {
7
+ server.registerTool('search_keys', {
8
+ description: 'Search for localization keys containing a specific substring. Useful for finding keys when you only know part of the key name.',
9
+ inputSchema: {
10
+ filePath: zod_1.z.string().describe('Absolute path to the .xcstrings file'),
11
+ query: zod_1.z
12
+ .string()
13
+ .describe('Substring to search for in key names (case-insensitive)'),
14
+ },
15
+ }, async ({ filePath, query }) => {
16
+ const catalog = new string_catalog_1.StringCatalog(filePath);
17
+ const keys = catalog.searchKeys(query);
18
+ return {
19
+ content: [
20
+ {
21
+ type: 'text',
22
+ text: JSON.stringify({
23
+ query,
24
+ matchingKeys: keys,
25
+ count: keys.length,
26
+ }, null, 2),
27
+ },
28
+ ],
29
+ };
30
+ });
31
+ }
32
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLWtleXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbWNwL3Rvb2xzL3NlYXJjaC1rZXlzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEsZ0RBbUNDO0FBdENELDZCQUF3QjtBQUN4Qix5REFBcUQ7QUFFckQsU0FBZ0Isa0JBQWtCLENBQUMsTUFBaUI7SUFDaEQsTUFBTSxDQUFDLFlBQVksQ0FDZixhQUFhLEVBQ2I7UUFDSSxXQUFXLEVBQ1AsZ0lBQWdJO1FBQ3BJLFdBQVcsRUFBRTtZQUNULFFBQVEsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLHNDQUFzQyxDQUFDO1lBQ3JFLEtBQUssRUFBRSxPQUFDO2lCQUNILE1BQU0sRUFBRTtpQkFDUixRQUFRLENBQUMseURBQXlELENBQUM7U0FDM0U7S0FDSixFQUNELEtBQUssRUFBRSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFO1FBQzFCLE1BQU0sT0FBTyxHQUFHLElBQUksOEJBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1QyxNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXZDLE9BQU87WUFDSCxPQUFPLEVBQUU7Z0JBQ0w7b0JBQ0ksSUFBSSxFQUFFLE1BQWU7b0JBQ3JCLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUNoQjt3QkFDSSxLQUFLO3dCQUNMLFlBQVksRUFBRSxJQUFJO3dCQUNsQixLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU07cUJBQ3JCLEVBQ0QsSUFBSSxFQUNKLENBQUMsQ0FDSjtpQkFDSjthQUNKO1NBQ0osQ0FBQztJQUNOLENBQUMsQ0FDSixDQUFDO0FBQ04sQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE1jcFNlcnZlciB9IGZyb20gJ0Btb2RlbGNvbnRleHRwcm90b2NvbC9zZGsvc2VydmVyL21jcC5qcyc7XG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcbmltcG9ydCB7IFN0cmluZ0NhdGFsb2cgfSBmcm9tICcuLi8uLi9zdHJpbmctY2F0YWxvZyc7XG5cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlclNlYXJjaEtleXMoc2VydmVyOiBNY3BTZXJ2ZXIpIHtcbiAgICBzZXJ2ZXIucmVnaXN0ZXJUb29sKFxuICAgICAgICAnc2VhcmNoX2tleXMnLFxuICAgICAgICB7XG4gICAgICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAgICAgICAnU2VhcmNoIGZvciBsb2NhbGl6YXRpb24ga2V5cyBjb250YWluaW5nIGEgc3BlY2lmaWMgc3Vic3RyaW5nLiBVc2VmdWwgZm9yIGZpbmRpbmcga2V5cyB3aGVuIHlvdSBvbmx5IGtub3cgcGFydCBvZiB0aGUga2V5IG5hbWUuJyxcbiAgICAgICAgICAgIGlucHV0U2NoZW1hOiB7XG4gICAgICAgICAgICAgICAgZmlsZVBhdGg6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ0Fic29sdXRlIHBhdGggdG8gdGhlIC54Y3N0cmluZ3MgZmlsZScpLFxuICAgICAgICAgICAgICAgIHF1ZXJ5OiB6XG4gICAgICAgICAgICAgICAgICAgIC5zdHJpbmcoKVxuICAgICAgICAgICAgICAgICAgICAuZGVzY3JpYmUoJ1N1YnN0cmluZyB0byBzZWFyY2ggZm9yIGluIGtleSBuYW1lcyAoY2FzZS1pbnNlbnNpdGl2ZSknKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jICh7IGZpbGVQYXRoLCBxdWVyeSB9KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjYXRhbG9nID0gbmV3IFN0cmluZ0NhdGFsb2coZmlsZVBhdGgpO1xuICAgICAgICAgICAgY29uc3Qga2V5cyA9IGNhdGFsb2cuc2VhcmNoS2V5cyhxdWVyeSk7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29udGVudDogW1xuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAndGV4dCcgYXMgY29uc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXJ5LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaGluZ0tleXM6IGtleXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50OiBrZXlzLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgMlxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICk7XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerUpdateTranslations(server: McpServer): void;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerUpdateTranslations = registerUpdateTranslations;
4
+ const zod_1 = require("zod");
5
+ const string_catalog_1 = require("../../string-catalog");
6
+ const toolDescription = `Update or add translations to a String Catalog. Accepts an array of translation entries.
7
+
8
+ IMPORTANT: iOS strings support format placeholders that must be preserved in translations:
9
+ - %@ for strings (objects)
10
+ - %d or %lld for integers
11
+ - %f for floating point numbers
12
+ - %1$@, %2$@ etc. for positional arguments (order can be changed in translations)
13
+
14
+ Example input:
15
+ {
16
+ "data": [
17
+ {
18
+ "key": "hello_world",
19
+ "translations": [
20
+ { "language": "en", "value": "Hello World" },
21
+ { "language": "de", "value": "Hallo Welt" },
22
+ { "language": "no", "value": "Hei Verden" }
23
+ ],
24
+ "comment": "Greeting message shown on home screen"
25
+ },
26
+ {
27
+ "key": "items_count",
28
+ "translations": [
29
+ { "language": "en", "value": "%lld items" },
30
+ { "language": "de", "value": "%lld Elemente" }
31
+ ]
32
+ }
33
+ ]
34
+ }`;
35
+ const translationSchema = zod_1.z.object({
36
+ language: zod_1.z.string().describe('Language code (e.g., "en", "de", "no", "vi")'),
37
+ value: zod_1.z
38
+ .string()
39
+ .describe('The translated text. Preserve any format placeholders like %@, %lld, %d'),
40
+ state: zod_1.z
41
+ .enum(['new', 'translated', 'needs_review', 'stale'])
42
+ .optional()
43
+ .describe('Translation state (defaults to "translated")'),
44
+ });
45
+ const translationsSchema = zod_1.z.object({
46
+ key: zod_1.z.string().describe('The localization key'),
47
+ translations: zod_1.z.array(translationSchema).describe('Array of language translations'),
48
+ comment: zod_1.z.string().optional().describe('Optional comment describing the string context'),
49
+ });
50
+ const inputSchema = zod_1.z.object({
51
+ filePath: zod_1.z.string().describe('Absolute path to the .xcstrings file'),
52
+ data: zod_1.z.array(translationsSchema).describe('Array of translation entries to add or update'),
53
+ });
54
+ function registerUpdateTranslations(server) {
55
+ server.registerTool('update_translations', {
56
+ description: toolDescription,
57
+ inputSchema,
58
+ }, async ({ filePath, data }) => {
59
+ const catalog = new string_catalog_1.StringCatalog(filePath);
60
+ const result = catalog.updateTranslations(data);
61
+ catalog.save();
62
+ return {
63
+ content: [
64
+ {
65
+ type: 'text',
66
+ text: JSON.stringify({
67
+ success: true,
68
+ updatedKeys: result.updated,
69
+ createdKeys: result.created,
70
+ totalUpdated: result.updated.length,
71
+ totalCreated: result.created.length,
72
+ }, null, 2),
73
+ },
74
+ ],
75
+ };
76
+ });
77
+ }
78
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLXRyYW5zbGF0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tY3AvdG9vbHMvdXBkYXRlLXRyYW5zbGF0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXdEQSxnRUFnQ0M7QUF2RkQsNkJBQXdCO0FBQ3hCLHlEQUFxRDtBQUVyRCxNQUFNLGVBQWUsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQTRCdEIsQ0FBQztBQUVILE1BQU0saUJBQWlCLEdBQUcsT0FBQyxDQUFDLE1BQU0sQ0FBQztJQUMvQixRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyw4Q0FBOEMsQ0FBQztJQUM3RSxLQUFLLEVBQUUsT0FBQztTQUNILE1BQU0sRUFBRTtTQUNSLFFBQVEsQ0FBQyx5RUFBeUUsQ0FBQztJQUN4RixLQUFLLEVBQUUsT0FBQztTQUNILElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1NBQ3BELFFBQVEsRUFBRTtTQUNWLFFBQVEsQ0FBQyw4Q0FBOEMsQ0FBQztDQUNoRSxDQUFDLENBQUM7QUFFSCxNQUFNLGtCQUFrQixHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDaEMsR0FBRyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsc0JBQXNCLENBQUM7SUFDaEQsWUFBWSxFQUFFLE9BQUMsQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxRQUFRLENBQUMsZ0NBQWdDLENBQUM7SUFDbkYsT0FBTyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsZ0RBQWdELENBQUM7Q0FDNUYsQ0FBQyxDQUFDO0FBRUgsTUFBTSxXQUFXLEdBQUcsT0FBQyxDQUFDLE1BQU0sQ0FBQztJQUN6QixRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxzQ0FBc0MsQ0FBQztJQUNyRSxJQUFJLEVBQUUsT0FBQyxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLFFBQVEsQ0FBQywrQ0FBK0MsQ0FBQztDQUM5RixDQUFDLENBQUM7QUFFSCxTQUFnQiwwQkFBMEIsQ0FBQyxNQUFpQjtJQUN4RCxNQUFNLENBQUMsWUFBWSxDQUNmLHFCQUFxQixFQUNyQjtRQUNJLFdBQVcsRUFBRSxlQUFlO1FBQzVCLFdBQVc7S0FDZCxFQUNELEtBQUssRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO1FBQ3pCLE1BQU0sT0FBTyxHQUFHLElBQUksOEJBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1QyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEQsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO1FBRWYsT0FBTztZQUNILE9BQU8sRUFBRTtnQkFDTDtvQkFDSSxJQUFJLEVBQUUsTUFBZTtvQkFDckIsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQ2hCO3dCQUNJLE9BQU8sRUFBRSxJQUFJO3dCQUNiLFdBQVcsRUFBRSxNQUFNLENBQUMsT0FBTzt3QkFDM0IsV0FBVyxFQUFFLE1BQU0sQ0FBQyxPQUFPO3dCQUMzQixZQUFZLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNO3dCQUNuQyxZQUFZLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNO3FCQUN0QyxFQUNELElBQUksRUFDSixDQUFDLENBQ0o7aUJBQ0o7YUFDSjtTQUNKLENBQUM7SUFDTixDQUFDLENBQ0osQ0FBQztBQUNOLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNY3BTZXJ2ZXIgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9tY3AuanMnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5pbXBvcnQgeyBTdHJpbmdDYXRhbG9nIH0gZnJvbSAnLi4vLi4vc3RyaW5nLWNhdGFsb2cnO1xuXG5jb25zdCB0b29sRGVzY3JpcHRpb24gPSBgVXBkYXRlIG9yIGFkZCB0cmFuc2xhdGlvbnMgdG8gYSBTdHJpbmcgQ2F0YWxvZy4gQWNjZXB0cyBhbiBhcnJheSBvZiB0cmFuc2xhdGlvbiBlbnRyaWVzLlxuXG5JTVBPUlRBTlQ6IGlPUyBzdHJpbmdzIHN1cHBvcnQgZm9ybWF0IHBsYWNlaG9sZGVycyB0aGF0IG11c3QgYmUgcHJlc2VydmVkIGluIHRyYW5zbGF0aW9uczpcbi0gJUAgZm9yIHN0cmluZ3MgKG9iamVjdHMpXG4tICVkIG9yICVsbGQgZm9yIGludGVnZXJzXG4tICVmIGZvciBmbG9hdGluZyBwb2ludCBudW1iZXJzXG4tICUxJEAsICUyJEAgZXRjLiBmb3IgcG9zaXRpb25hbCBhcmd1bWVudHMgKG9yZGVyIGNhbiBiZSBjaGFuZ2VkIGluIHRyYW5zbGF0aW9ucylcblxuRXhhbXBsZSBpbnB1dDpcbntcbiAgXCJkYXRhXCI6IFtcbiAgICB7XG4gICAgICBcImtleVwiOiBcImhlbGxvX3dvcmxkXCIsXG4gICAgICBcInRyYW5zbGF0aW9uc1wiOiBbXG4gICAgICAgIHsgXCJsYW5ndWFnZVwiOiBcImVuXCIsIFwidmFsdWVcIjogXCJIZWxsbyBXb3JsZFwiIH0sXG4gICAgICAgIHsgXCJsYW5ndWFnZVwiOiBcImRlXCIsIFwidmFsdWVcIjogXCJIYWxsbyBXZWx0XCIgfSxcbiAgICAgICAgeyBcImxhbmd1YWdlXCI6IFwibm9cIiwgXCJ2YWx1ZVwiOiBcIkhlaSBWZXJkZW5cIiB9XG4gICAgICBdLFxuICAgICAgXCJjb21tZW50XCI6IFwiR3JlZXRpbmcgbWVzc2FnZSBzaG93biBvbiBob21lIHNjcmVlblwiXG4gICAgfSxcbiAgICB7XG4gICAgICBcImtleVwiOiBcIml0ZW1zX2NvdW50XCIsXG4gICAgICBcInRyYW5zbGF0aW9uc1wiOiBbXG4gICAgICAgIHsgXCJsYW5ndWFnZVwiOiBcImVuXCIsIFwidmFsdWVcIjogXCIlbGxkIGl0ZW1zXCIgfSxcbiAgICAgICAgeyBcImxhbmd1YWdlXCI6IFwiZGVcIiwgXCJ2YWx1ZVwiOiBcIiVsbGQgRWxlbWVudGVcIiB9XG4gICAgICBdXG4gICAgfVxuICBdXG59YDtcblxuY29uc3QgdHJhbnNsYXRpb25TY2hlbWEgPSB6Lm9iamVjdCh7XG4gICAgbGFuZ3VhZ2U6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ0xhbmd1YWdlIGNvZGUgKGUuZy4sIFwiZW5cIiwgXCJkZVwiLCBcIm5vXCIsIFwidmlcIiknKSxcbiAgICB2YWx1ZTogelxuICAgICAgICAuc3RyaW5nKClcbiAgICAgICAgLmRlc2NyaWJlKCdUaGUgdHJhbnNsYXRlZCB0ZXh0LiBQcmVzZXJ2ZSBhbnkgZm9ybWF0IHBsYWNlaG9sZGVycyBsaWtlICVALCAlbGxkLCAlZCcpLFxuICAgIHN0YXRlOiB6XG4gICAgICAgIC5lbnVtKFsnbmV3JywgJ3RyYW5zbGF0ZWQnLCAnbmVlZHNfcmV2aWV3JywgJ3N0YWxlJ10pXG4gICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgIC5kZXNjcmliZSgnVHJhbnNsYXRpb24gc3RhdGUgKGRlZmF1bHRzIHRvIFwidHJhbnNsYXRlZFwiKScpLFxufSk7XG5cbmNvbnN0IHRyYW5zbGF0aW9uc1NjaGVtYSA9IHoub2JqZWN0KHtcbiAgICBrZXk6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ1RoZSBsb2NhbGl6YXRpb24ga2V5JyksXG4gICAgdHJhbnNsYXRpb25zOiB6LmFycmF5KHRyYW5zbGF0aW9uU2NoZW1hKS5kZXNjcmliZSgnQXJyYXkgb2YgbGFuZ3VhZ2UgdHJhbnNsYXRpb25zJyksXG4gICAgY29tbWVudDogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKCdPcHRpb25hbCBjb21tZW50IGRlc2NyaWJpbmcgdGhlIHN0cmluZyBjb250ZXh0JyksXG59KTtcblxuY29uc3QgaW5wdXRTY2hlbWEgPSB6Lm9iamVjdCh7XG4gICAgZmlsZVBhdGg6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ0Fic29sdXRlIHBhdGggdG8gdGhlIC54Y3N0cmluZ3MgZmlsZScpLFxuICAgIGRhdGE6IHouYXJyYXkodHJhbnNsYXRpb25zU2NoZW1hKS5kZXNjcmliZSgnQXJyYXkgb2YgdHJhbnNsYXRpb24gZW50cmllcyB0byBhZGQgb3IgdXBkYXRlJyksXG59KTtcblxuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lzdGVyVXBkYXRlVHJhbnNsYXRpb25zKHNlcnZlcjogTWNwU2VydmVyKSB7XG4gICAgc2VydmVyLnJlZ2lzdGVyVG9vbChcbiAgICAgICAgJ3VwZGF0ZV90cmFuc2xhdGlvbnMnLFxuICAgICAgICB7XG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogdG9vbERlc2NyaXB0aW9uLFxuICAgICAgICAgICAgaW5wdXRTY2hlbWEsXG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jICh7IGZpbGVQYXRoLCBkYXRhIH0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNhdGFsb2cgPSBuZXcgU3RyaW5nQ2F0YWxvZyhmaWxlUGF0aCk7XG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBjYXRhbG9nLnVwZGF0ZVRyYW5zbGF0aW9ucyhkYXRhKTtcbiAgICAgICAgICAgIGNhdGFsb2cuc2F2ZSgpO1xuXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ3RleHQnIGFzIGNvbnN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgdGV4dDogSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVkS2V5czogcmVzdWx0LnVwZGF0ZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZWRLZXlzOiByZXN1bHQuY3JlYXRlZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxVcGRhdGVkOiByZXN1bHQudXBkYXRlZC5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsQ3JlYXRlZDogcmVzdWx0LmNyZWF0ZWQubGVuZ3RoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgKTtcbn1cbiJdfQ==
@@ -0,0 +1,53 @@
1
+ import { TranslationInput, KeyTranslationsResult } from './types';
2
+ /**
3
+ * StringCatalog class for reading and manipulating .xcstrings files
4
+ */
5
+ export declare class StringCatalog {
6
+ private filePath;
7
+ private data;
8
+ constructor(filePath: string);
9
+ private load;
10
+ /**
11
+ * Get the source language of the catalog
12
+ */
13
+ getSourceLanguage(): string;
14
+ /**
15
+ * Get all supported languages in the catalog
16
+ */
17
+ getSupportedLanguages(): string[];
18
+ /**
19
+ * Get all keys in the catalog
20
+ */
21
+ getAllKeys(): string[];
22
+ /**
23
+ * Get translations for a specific key
24
+ */
25
+ getTranslationsForKey(key: string): KeyTranslationsResult | null;
26
+ /**
27
+ * Search for keys containing a specific substring
28
+ */
29
+ searchKeys(query: string): string[];
30
+ /**
31
+ * Update translations for one or more keys
32
+ */
33
+ updateTranslations(translations: TranslationInput[]): {
34
+ updated: string[];
35
+ created: string[];
36
+ };
37
+ /**
38
+ * Save changes to the file
39
+ */
40
+ save(): void;
41
+ /**
42
+ * Get statistics about the catalog
43
+ */
44
+ getStatistics(): {
45
+ totalKeys: number;
46
+ languages: string[];
47
+ translationCoverage: Record<string, {
48
+ translated: number;
49
+ total: number;
50
+ percentage: number;
51
+ }>;
52
+ };
53
+ }
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.StringCatalog = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ /**
40
+ * StringCatalog class for reading and manipulating .xcstrings files
41
+ */
42
+ class StringCatalog {
43
+ filePath;
44
+ data;
45
+ constructor(filePath) {
46
+ this.filePath = path.resolve(filePath);
47
+ this.data = this.load();
48
+ }
49
+ load() {
50
+ if (!fs.existsSync(this.filePath)) {
51
+ throw new Error(`String catalog file not found: ${this.filePath}`);
52
+ }
53
+ const content = fs.readFileSync(this.filePath, 'utf-8');
54
+ return JSON.parse(content);
55
+ }
56
+ /**
57
+ * Get the source language of the catalog
58
+ */
59
+ getSourceLanguage() {
60
+ return this.data.sourceLanguage;
61
+ }
62
+ /**
63
+ * Get all supported languages in the catalog
64
+ */
65
+ getSupportedLanguages() {
66
+ const languages = new Set();
67
+ languages.add(this.data.sourceLanguage);
68
+ for (const key in this.data.strings) {
69
+ const entry = this.data.strings[key];
70
+ if (entry.localizations) {
71
+ for (const lang of Object.keys(entry.localizations)) {
72
+ languages.add(lang);
73
+ }
74
+ }
75
+ }
76
+ return Array.from(languages).sort();
77
+ }
78
+ /**
79
+ * Get all keys in the catalog
80
+ */
81
+ getAllKeys() {
82
+ return Object.keys(this.data.strings).sort();
83
+ }
84
+ /**
85
+ * Get translations for a specific key
86
+ */
87
+ getTranslationsForKey(key) {
88
+ const entry = this.data.strings[key];
89
+ if (!entry) {
90
+ return null;
91
+ }
92
+ const translations = [];
93
+ if (entry.localizations) {
94
+ for (const [language, localization] of Object.entries(entry.localizations)) {
95
+ if (localization.stringUnit) {
96
+ translations.push({
97
+ language,
98
+ value: localization.stringUnit.value,
99
+ state: localization.stringUnit.state,
100
+ });
101
+ }
102
+ else if (localization.variations?.plural) {
103
+ // For plural strings, show the "other" form as the primary value
104
+ const plural = localization.variations.plural;
105
+ const primaryForm = plural.other || plural.one || plural.zero;
106
+ if (primaryForm) {
107
+ translations.push({
108
+ language,
109
+ value: `[plural] ${primaryForm.stringUnit.value}`,
110
+ state: primaryForm.stringUnit.state,
111
+ });
112
+ }
113
+ }
114
+ }
115
+ }
116
+ return {
117
+ key,
118
+ sourceLanguage: this.data.sourceLanguage,
119
+ translations: translations.sort((a, b) => a.language.localeCompare(b.language)),
120
+ };
121
+ }
122
+ /**
123
+ * Search for keys containing a specific substring
124
+ */
125
+ searchKeys(query) {
126
+ const lowerQuery = query.toLowerCase();
127
+ return this.getAllKeys().filter((key) => key.toLowerCase().includes(lowerQuery));
128
+ }
129
+ /**
130
+ * Update translations for one or more keys
131
+ */
132
+ updateTranslations(translations) {
133
+ const updated = [];
134
+ const created = [];
135
+ for (const translation of translations) {
136
+ const { key, translations: langTranslations, comment } = translation;
137
+ const isNew = !this.data.strings[key];
138
+ if (isNew) {
139
+ this.data.strings[key] = {};
140
+ created.push(key);
141
+ }
142
+ else {
143
+ updated.push(key);
144
+ }
145
+ const entry = this.data.strings[key];
146
+ if (comment) {
147
+ entry.comment = comment;
148
+ }
149
+ if (!entry.localizations) {
150
+ entry.localizations = {};
151
+ }
152
+ for (const langTrans of langTranslations) {
153
+ entry.localizations[langTrans.language] = {
154
+ stringUnit: {
155
+ state: langTrans.state || 'translated',
156
+ value: langTrans.value,
157
+ },
158
+ };
159
+ }
160
+ }
161
+ return { updated, created };
162
+ }
163
+ /**
164
+ * Save changes to the file
165
+ */
166
+ save() {
167
+ // Sort keys alphabetically for consistent output
168
+ const sortedStrings = {};
169
+ const keys = Object.keys(this.data.strings).sort();
170
+ for (const key of keys) {
171
+ sortedStrings[key] = this.data.strings[key];
172
+ }
173
+ const output = {
174
+ sourceLanguage: this.data.sourceLanguage,
175
+ strings: sortedStrings,
176
+ };
177
+ if (this.data.version) {
178
+ output.version = this.data.version;
179
+ }
180
+ // Write with 2-space indentation to match Xcode format
181
+ fs.writeFileSync(this.filePath, JSON.stringify(output, null, 2) + '\n', 'utf-8');
182
+ }
183
+ /**
184
+ * Get statistics about the catalog
185
+ */
186
+ getStatistics() {
187
+ const languages = this.getSupportedLanguages();
188
+ const allKeys = this.getAllKeys();
189
+ const totalKeys = allKeys.length;
190
+ const translationCoverage = {};
191
+ for (const lang of languages) {
192
+ let translated = 0;
193
+ for (const key of allKeys) {
194
+ const entry = this.data.strings[key];
195
+ const localization = entry.localizations?.[lang];
196
+ if (localization?.stringUnit?.state === 'translated') {
197
+ translated++;
198
+ }
199
+ else if (localization?.variations?.plural) {
200
+ // Count plural as translated if it has an "other" form
201
+ if (localization.variations.plural.other?.stringUnit?.state === 'translated') {
202
+ translated++;
203
+ }
204
+ }
205
+ }
206
+ translationCoverage[lang] = {
207
+ translated,
208
+ total: totalKeys,
209
+ percentage: totalKeys > 0 ? Math.round((translated / totalKeys) * 100) : 0,
210
+ };
211
+ }
212
+ return {
213
+ totalKeys,
214
+ languages,
215
+ translationCoverage,
216
+ };
217
+ }
218
+ }
219
+ exports.StringCatalog = StringCatalog;
220
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RyaW5nLWNhdGFsb2cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc3RyaW5nLWNhdGFsb2cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQVU3Qjs7R0FFRztBQUNILE1BQWEsYUFBYTtJQUNkLFFBQVEsQ0FBUztJQUNqQixJQUFJLENBQVk7SUFFeEIsWUFBWSxRQUFnQjtRQUN4QixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVPLElBQUk7UUFDUixJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNoQyxNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUN2RSxDQUFDO1FBRUQsTUFBTSxPQUFPLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3hELE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQWMsQ0FBQztJQUM1QyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxpQkFBaUI7UUFDYixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDO0lBQ3BDLENBQUM7SUFFRDs7T0FFRztJQUNILHFCQUFxQjtRQUNqQixNQUFNLFNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBQ3BDLFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUV4QyxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENB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bSAncGF0aCc7XG5pbXBvcnQge1xuICAgIFhDU3RyaW5ncyxcbiAgICBTdHJpbmdFbnRyeSxcbiAgICBUcmFuc2xhdGlvbklucHV0LFxuICAgIEtleVRyYW5zbGF0aW9uc1Jlc3VsdCxcbiAgICBLZXlUcmFuc2xhdGlvbixcbiAgICBMb2NhbGl6YXRpb25TdGF0ZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogU3RyaW5nQ2F0YWxvZyBjbGFzcyBmb3IgcmVhZGluZyBhbmQgbWFuaXB1bGF0aW5nIC54Y3N0cmluZ3MgZmlsZXNcbiAqL1xuZXhwb3J0IGNsYXNzIFN0cmluZ0NhdGFsb2cge1xuICAgIHByaXZhdGUgZmlsZVBhdGg6IHN0cmluZztcbiAgICBwcml2YXRlIGRhdGE6IFhDU3RyaW5ncztcblxuICAgIGNvbnN0cnVjdG9yKGZpbGVQYXRoOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5maWxlUGF0aCA9IHBhdGgucmVzb2x2ZShmaWxlUGF0aCk7XG4gICAgICAgIHRoaXMuZGF0YSA9IHRoaXMubG9hZCgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgbG9hZCgpOiBYQ1N0cmluZ3Mge1xuICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmModGhpcy5maWxlUGF0aCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU3RyaW5nIGNhdGFsb2cgZmlsZSBub3QgZm91bmQ6ICR7dGhpcy5maWxlUGF0aH1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmModGhpcy5maWxlUGF0aCwgJ3V0Zi04Jyk7XG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKGNvbnRlbnQpIGFzIFhDU3RyaW5ncztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIHNvdXJjZSBsYW5ndWFnZSBvZiB0aGUgY2F0YWxvZ1xuICAgICAqL1xuICAgIGdldFNvdXJjZUxhbmd1YWdlKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGEuc291cmNlTGFuZ3VhZ2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBzdXBwb3J0ZWQgbGFuZ3VhZ2VzIGluIHRoZSBjYXRhbG9nXG4gICAgICovXG4gICAgZ2V0U3VwcG9ydGVkTGFuZ3VhZ2VzKCk6IHN0cmluZ1tdIHtcbiAgICAgICAgY29uc3QgbGFuZ3VhZ2VzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgICAgIGxhbmd1YWdlcy5hZGQodGhpcy5kYXRhLnNvdXJjZUxhbmd1YWdlKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiB0aGlzLmRhdGEuc3RyaW5ncykge1xuICAgICAgICAgICAgY29uc3QgZW50cnkgPSB0aGlzLmRhdGEuc3RyaW5nc1trZXldO1xuICAgICAgICAgICAgaWYgKGVudHJ5LmxvY2FsaXphdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGxhbmcgb2YgT2JqZWN0LmtleXMoZW50cnkubG9jYWxpemF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFuZ3VhZ2VzLmFkZChsYW5nKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gQXJyYXkuZnJvbShsYW5ndWFnZXMpLnNvcnQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYWxsIGtleXMgaW4gdGhlIGNhdGFsb2dcbiAgICAgKi9cbiAgICBnZXRBbGxLZXlzKCk6IHN0cmluZ1tdIHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuZGF0YS5zdHJpbmdzKS5zb3J0KCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRyYW5zbGF0aW9ucyBmb3IgYSBzcGVjaWZpYyBrZXlcbiAgICAgKi9cbiAgICBnZXRUcmFuc2xhdGlvbnNGb3JLZXkoa2V5OiBzdHJpbmcpOiBLZXlUcmFuc2xhdGlvbnNSZXN1bHQgfCBudWxsIHtcbiAgICAgICAgY29uc3QgZW50cnkgPSB0aGlzLmRhdGEuc3RyaW5nc1trZXldO1xuICAgICAgICBpZiAoIWVudHJ5KSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHRyYW5zbGF0aW9uczogS2V5VHJhbnNsYXRpb25bXSA9IFtdO1xuXG4gICAgICAgIGlmIChlbnRyeS5sb2NhbGl6YXRpb25zKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtsYW5ndWFnZSwgbG9jYWxpemF0aW9uXSBvZiBPYmplY3QuZW50cmllcyhlbnRyeS5sb2NhbGl6YXRpb25zKSkge1xuICAgICAgICAgICAgICAgIGlmIChsb2NhbGl6YXRpb24uc3RyaW5nVW5pdCkge1xuICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICBsYW5ndWFnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBsb2NhbGl6YXRpb24uc3RyaW5nVW5pdC52YWx1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlOiBsb2NhbGl6YXRpb24uc3RyaW5nVW5pdC5zdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChsb2NhbGl6YXRpb24udmFyaWF0aW9ucz8ucGx1cmFsKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEZvciBwbHVyYWwgc3RyaW5ncywgc2hvdyB0aGUgXCJvdGhlclwiIGZvcm0gYXMgdGhlIHByaW1hcnkgdmFsdWVcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGx1cmFsID0gbG9jYWxpemF0aW9uLnZhcmlhdGlvbnMucGx1cmFsO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwcmltYXJ5Rm9ybSA9IHBsdXJhbC5vdGhlciB8fCBwbHVyYWwub25lIHx8IHBsdXJhbC56ZXJvO1xuICAgICAgICAgICAgICAgICAgICBpZiAocHJpbWFyeUZvcm0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYW5ndWFnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogYFtwbHVyYWxdICR7cHJpbWFyeUZvcm0uc3RyaW5nVW5pdC52YWx1ZX1gLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlOiBwcmltYXJ5Rm9ybS5zdHJpbmdVbml0LnN0YXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgc291cmNlTGFuZ3VhZ2U6IHRoaXMuZGF0YS5zb3VyY2VMYW5ndWFnZSxcbiAgICAgICAgICAgIHRyYW5zbGF0aW9uczogdHJhbnNsYXRpb25zLnNvcnQoKGEsIGIpID0+IGEubGFuZ3VhZ2UubG9jYWxlQ29tcGFyZShiLmxhbmd1YWdlKSksXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VhcmNoIGZvciBrZXlzIGNvbnRhaW5pbmcgYSBzcGVjaWZpYyBzdWJzdHJpbmdcbiAgICAgKi9cbiAgICBzZWFyY2hLZXlzKHF1ZXJ5OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgICAgIGNvbnN0IGxvd2VyUXVlcnkgPSBxdWVyeS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRBbGxLZXlzKCkuZmlsdGVyKChrZXkpID0+IGtleS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKGxvd2VyUXVlcnkpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGUgdHJhbnNsYXRpb25zIGZvciBvbmUgb3IgbW9yZSBrZXlzXG4gICAgICovXG4gICAgdXBkYXRlVHJhbnNsYXRpb25zKHRyYW5zbGF0aW9uczogVHJhbnNsYXRpb25JbnB1dFtdKTogeyB1cGRhdGVkOiBzdHJpbmdbXTsgY3JlYXRlZDogc3RyaW5nW10gfSB7XG4gICAgICAgIGNvbnN0IHVwZGF0ZWQ6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGNvbnN0IGNyZWF0ZWQ6IHN0cmluZ1tdID0gW107XG5cbiAgICAgICAgZm9yIChjb25zdCB0cmFuc2xhdGlvbiBvZiB0cmFuc2xhdGlvbnMpIHtcbiAgICAgICAgICAgIGNvbnN0IHsga2V5LCB0cmFuc2xhdGlvbnM6IGxhbmdUcmFuc2xhdGlvbnMsIGNvbW1lbnQgfSA9IHRyYW5zbGF0aW9uO1xuXG4gICAgICAgICAgICBjb25zdCBpc05ldyA9ICF0aGlzLmRhdGEuc3RyaW5nc1trZXldO1xuXG4gICAgICAgICAgICBpZiAoaXNOZXcpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRhdGEuc3RyaW5nc1trZXldID0ge307XG4gICAgICAgICAgICAgICAgY3JlYXRlZC5wdXNoKGtleSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHVwZGF0ZWQucHVzaChrZXkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBlbnRyeSA9IHRoaXMuZGF0YS5zdHJpbmdzW2tleV07XG5cbiAgICAgICAgICAgIGlmIChjb21tZW50KSB7XG4gICAgICAgICAgICAgICAgZW50cnkuY29tbWVudCA9IGNvbW1lbnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghZW50cnkubG9jYWxpemF0aW9ucykge1xuICAgICAgICAgICAgICAgIGVudHJ5LmxvY2FsaXphdGlvbnMgPSB7fTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZm9yIChjb25zdCBsYW5nVHJhbnMgb2YgbGFuZ1RyYW5zbGF0aW9ucykge1xuICAgICAgICAgICAgICAgIGVudHJ5LmxvY2FsaXphdGlvbnNbbGFuZ1RyYW5zLmxhbmd1YWdlXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgc3RyaW5nVW5pdDoge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGU6IGxhbmdUcmFucy5zdGF0ZSB8fCAndHJhbnNsYXRlZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogbGFuZ1RyYW5zLnZhbHVlLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4geyB1cGRhdGVkLCBjcmVhdGVkIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2F2ZSBjaGFuZ2VzIHRvIHRoZSBmaWxlXG4gICAgICovXG4gICAgc2F2ZSgpOiB2b2lkIHtcbiAgICAgICAgLy8gU29ydCBrZXlzIGFscGhhYmV0aWNhbGx5IGZvciBjb25zaXN0ZW50IG91dHB1dFxuICAgICAgICBjb25zdCBzb3J0ZWRTdHJpbmdzOiB7IFtrZXk6IHN0cmluZ106IFN0cmluZ0VudHJ5IH0gPSB7fTtcbiAgICAgICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKHRoaXMuZGF0YS5zdHJpbmdzKS5zb3J0KCk7XG5cbiAgICAgICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgICAgICAgc29ydGVkU3RyaW5nc1trZXldID0gdGhpcy5kYXRhLnN0cmluZ3Nba2V5XTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG91dHB1dDogWENTdHJpbmdzID0ge1xuICAgICAgICAgICAgc291cmNlTGFuZ3VhZ2U6IHRoaXMuZGF0YS5zb3VyY2VMYW5ndWFnZSxcbiAgICAgICAgICAgIHN0cmluZ3M6IHNvcnRlZFN0cmluZ3MsXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKHRoaXMuZGF0YS52ZXJzaW9uKSB7XG4gICAgICAgICAgICBvdXRwdXQudmVyc2lvbiA9IHRoaXMuZGF0YS52ZXJzaW9uO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gV3JpdGUgd2l0aCAyLXNwYWNlIGluZGVudGF0aW9uIHRvIG1hdGNoIFhjb2RlIGZvcm1hdFxuICAgICAgICBmcy53cml0ZUZpbGVTeW5jKHRoaXMuZmlsZVBhdGgsIEpTT04uc3RyaW5naWZ5KG91dHB1dCwgbnVsbCwgMikgKyAnXFxuJywgJ3V0Zi04Jyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHN0YXRpc3RpY3MgYWJvdXQgdGhlIGNhdGFsb2dcbiAgICAgKi9cbiAgICBnZXRTdGF0aXN0aWNzKCk6IHtcbiAgICAgICAgdG90YWxLZXlzOiBudW1iZXI7XG4gICAgICAgIGxhbmd1YWdlczogc3RyaW5nW107XG4gICAgICAgIHRyYW5zbGF0aW9uQ292ZXJhZ2U6IFJlY29yZDxcbiAgICAgICAgICAgIHN0cmluZyxcbiAgICAgICAgICAgIHsgdHJhbnNsYXRlZDogbnVtYmVyOyB0b3RhbDogbnVtYmVyOyBwZXJjZW50YWdlOiBudW1iZXIgfVxuICAgICAgICA+O1xuICAgIH0ge1xuICAgICAgICBjb25zdCBsYW5ndWFnZXMgPSB0aGlzLmdldFN1cHBvcnRlZExhbmd1YWdlcygpO1xuICAgICAgICBjb25zdCBhbGxLZXlzID0gdGhpcy5nZXRBbGxLZXlzKCk7XG4gICAgICAgIGNvbnN0IHRvdGFsS2V5cyA9IGFsbEtleXMubGVuZ3RoO1xuXG4gICAgICAgIGNvbnN0IHRyYW5zbGF0aW9uQ292ZXJhZ2U6IFJlY29yZDxcbiAgICAgICAgICAgIHN0cmluZyxcbiAgICAgICAgICAgIHsgdHJhbnNsYXRlZDogbnVtYmVyOyB0b3RhbDogbnVtYmVyOyBwZXJjZW50YWdlOiBudW1iZXIgfVxuICAgICAgICA+ID0ge307XG5cbiAgICAgICAgZm9yIChjb25zdCBsYW5nIG9mIGxhbmd1YWdlcykge1xuICAgICAgICAgICAgbGV0IHRyYW5zbGF0ZWQgPSAwO1xuXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiBhbGxLZXlzKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZW50cnkgPSB0aGlzLmRhdGEuc3RyaW5nc1trZXldO1xuICAgICAgICAgICAgICAgIGNvbnN0IGxvY2FsaXphdGlvbiA9IGVudHJ5LmxvY2FsaXphdGlvbnM/LltsYW5nXTtcblxuICAgICAgICAgICAgICAgIGlmIChsb2NhbGl6YXRpb24/LnN0cmluZ1VuaXQ/LnN0YXRlID09PSAndHJhbnNsYXRlZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNsYXRlZCsrO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobG9jYWxpemF0aW9uPy52YXJpYXRpb25zPy5wbHVyYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQ291bnQgcGx1cmFsIGFzIHRyYW5zbGF0ZWQgaWYgaXQgaGFzIGFuIFwib3RoZXJcIiBmb3JtXG4gICAgICAgICAgICAgICAgICAgIGlmIChsb2NhbGl6YXRpb24udmFyaWF0aW9ucy5wbHVyYWwub3RoZXI/LnN0cmluZ1VuaXQ/LnN0YXRlID09PSAndHJhbnNsYXRlZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZWQrKztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdHJhbnNsYXRpb25Db3ZlcmFnZVtsYW5nXSA9IHtcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGVkLFxuICAgICAgICAgICAgICAgIHRvdGFsOiB0b3RhbEtleXMsXG4gICAgICAgICAgICAgICAgcGVyY2VudGFnZTogdG90YWxLZXlzID4gMCA/IE1hdGgucm91bmQoKHRyYW5zbGF0ZWQgLyB0b3RhbEtleXMpICogMTAwKSA6IDAsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHRvdGFsS2V5cyxcbiAgICAgICAgICAgIGxhbmd1YWdlcyxcbiAgICAgICAgICAgIHRyYW5zbGF0aW9uQ292ZXJhZ2UsXG4gICAgICAgIH07XG4gICAgfVxufVxuIl19
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerGetCatalogStatistics(server: McpServer): void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerGetCatalogStatistics = registerGetCatalogStatistics;
4
+ const zod_1 = require("zod");
5
+ const string_catalog_1 = require("../string-catalog");
6
+ function registerGetCatalogStatistics(server) {
7
+ server.registerTool('get_catalog_statistics', {
8
+ description: 'Get statistics about a String Catalog including total keys, supported languages, and translation coverage percentage for each language.',
9
+ inputSchema: {
10
+ filePath: zod_1.z.string().describe('Absolute path to the .xcstrings file'),
11
+ },
12
+ }, async ({ filePath }) => {
13
+ const catalog = new string_catalog_1.StringCatalog(filePath);
14
+ const stats = catalog.getStatistics();
15
+ return {
16
+ content: [
17
+ {
18
+ type: 'text',
19
+ text: JSON.stringify(stats, null, 2),
20
+ },
21
+ ],
22
+ };
23
+ });
24
+ }
25
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LWNhdGFsb2ctc3RhdGlzdGljcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90b29scy9nZXQtY2F0YWxvZy1zdGF0aXN0aWNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEsb0VBd0JDO0FBM0JELDZCQUF3QjtBQUN4QixzREFBa0Q7QUFFbEQsU0FBZ0IsNEJBQTRCLENBQUMsTUFBaUI7SUFDMUQsTUFBTSxDQUFDLFlBQVksQ0FDZix3QkFBd0IsRUFDeEI7UUFDSSxXQUFXLEVBQ1AseUlBQXlJO1FBQzdJLFdBQVcsRUFBRTtZQUNULFFBQVEsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLHNDQUFzQyxDQUFDO1NBQ3hFO0tBQ0osRUFDRCxLQUFLLEVBQUUsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFO1FBQ25CLE1BQU0sT0FBTyxHQUFHLElBQUksOEJBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1QyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUM7UUFFdEMsT0FBTztZQUNILE9BQU8sRUFBRTtnQkFDTDtvQkFDSSxJQUFJLEVBQUUsTUFBZTtvQkFDckIsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7aUJBQ3ZDO2FBQ0o7U0FDSixDQUFDO0lBQ04sQ0FBQyxDQUNKLENBQUM7QUFDTixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTWNwU2VydmVyIH0gZnJvbSAnQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay9zZXJ2ZXIvbWNwLmpzJztcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuaW1wb3J0IHsgU3RyaW5nQ2F0YWxvZyB9IGZyb20gJy4uL3N0cmluZy1jYXRhbG9nJztcblxuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lzdGVyR2V0Q2F0YWxvZ1N0YXRpc3RpY3Moc2VydmVyOiBNY3BTZXJ2ZXIpIHtcbiAgICBzZXJ2ZXIucmVnaXN0ZXJUb29sKFxuICAgICAgICAnZ2V0X2NhdGFsb2dfc3RhdGlzdGljcycsXG4gICAgICAgIHtcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICAgICAgICdHZXQgc3RhdGlzdGljcyBhYm91dCBhIFN0cmluZyBDYXRhbG9nIGluY2x1ZGluZyB0b3RhbCBrZXlzLCBzdXBwb3J0ZWQgbGFuZ3VhZ2VzLCBhbmQgdHJhbnNsYXRpb24gY292ZXJhZ2UgcGVyY2VudGFnZSBmb3IgZWFjaCBsYW5ndWFnZS4nLFxuICAgICAgICAgICAgaW5wdXRTY2hlbWE6IHtcbiAgICAgICAgICAgICAgICBmaWxlUGF0aDogei5zdHJpbmcoKS5kZXNjcmliZSgnQWJzb2x1dGUgcGF0aCB0byB0aGUgLnhjc3RyaW5ncyBmaWxlJyksXG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBhc3luYyAoeyBmaWxlUGF0aCB9KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjYXRhbG9nID0gbmV3IFN0cmluZ0NhdGFsb2coZmlsZVBhdGgpO1xuICAgICAgICAgICAgY29uc3Qgc3RhdHMgPSBjYXRhbG9nLmdldFN0YXRpc3RpY3MoKTtcblxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBjb250ZW50OiBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICd0ZXh0JyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRleHQ6IEpTT04uc3RyaW5naWZ5KHN0YXRzLCBudWxsLCAyKSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICk7XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerGetTranslationsForKey(server: McpServer): void;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerGetTranslationsForKey = registerGetTranslationsForKey;
4
+ const zod_1 = require("zod");
5
+ const string_catalog_1 = require("../string-catalog");
6
+ function registerGetTranslationsForKey(server) {
7
+ server.registerTool('get_translations_for_key', {
8
+ description: 'Get all translations for a specific key in a String Catalog. Shows the translated text in each supported language along with the translation state.',
9
+ inputSchema: {
10
+ filePath: zod_1.z.string().describe('Absolute path to the .xcstrings file'),
11
+ key: zod_1.z.string().describe('The localization key to look up'),
12
+ },
13
+ }, async ({ filePath, key }) => {
14
+ const catalog = new string_catalog_1.StringCatalog(filePath);
15
+ const result = catalog.getTranslationsForKey(key);
16
+ if (!result) {
17
+ return {
18
+ content: [
19
+ {
20
+ type: 'text',
21
+ text: JSON.stringify({ error: `Key "${key}" not found in catalog` }, null, 2),
22
+ },
23
+ ],
24
+ };
25
+ }
26
+ return {
27
+ content: [
28
+ {
29
+ type: 'text',
30
+ text: JSON.stringify(result, null, 2),
31
+ },
32
+ ],
33
+ };
34
+ });
35
+ }
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LXRyYW5zbGF0aW9ucy1mb3Ita2V5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rvb2xzL2dldC10cmFuc2xhdGlvbnMtZm9yLWtleS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUlBLHNFQXdDQztBQTNDRCw2QkFBd0I7QUFDeEIsc0RBQWtEO0FBRWxELFNBQWdCLDZCQUE2QixDQUFDLE1BQWlCO0lBQzNELE1BQU0sQ0FBQyxZQUFZLENBQ2YsMEJBQTBCLEVBQzFCO1FBQ0ksV0FBVyxFQUNQLHFKQUFxSjtRQUN6SixXQUFXLEVBQUU7WUFDVCxRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxzQ0FBc0MsQ0FBQztZQUNyRSxHQUFHLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxpQ0FBaUMsQ0FBQztTQUM5RDtLQUNKLEVBQ0QsS0FBSyxFQUFFLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUU7UUFDeEIsTUFBTSxPQUFPLEdBQUcsSUFBSSw4QkFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzVDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUVsRCxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDVixPQUFPO2dCQUNILE9BQU8sRUFBRTtvQkFDTDt3QkFDSSxJQUFJLEVBQUUsTUFBZTt3QkFDckIsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQ2hCLEVBQUUsS0FBSyxFQUFFLFFBQVEsR0FBRyx3QkFBd0IsRUFBRSxFQUM5QyxJQUFJLEVBQ0osQ0FBQyxDQUNKO3FCQUNKO2lCQUNKO2FBQ0osQ0FBQztRQUNOLENBQUM7UUFFRCxPQUFPO1lBQ0gsT0FBTyxFQUFFO2dCQUNMO29CQUNJLElBQUksRUFBRSxNQUFlO29CQUNyQixJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztpQkFDeEM7YUFDSjtTQUNKLENBQUM7SUFDTixDQUFDLENBQ0osQ0FBQztBQUNOLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNY3BTZXJ2ZXIgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9tY3AuanMnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5pbXBvcnQgeyBTdHJpbmdDYXRhbG9nIH0gZnJvbSAnLi4vc3RyaW5nLWNhdGFsb2cnO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJHZXRUcmFuc2xhdGlvbnNGb3JLZXkoc2VydmVyOiBNY3BTZXJ2ZXIpIHtcbiAgICBzZXJ2ZXIucmVnaXN0ZXJUb29sKFxuICAgICAgICAnZ2V0X3RyYW5zbGF0aW9uc19mb3Jfa2V5JyxcbiAgICAgICAge1xuICAgICAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgICAgICAgJ0dldCBhbGwgdHJhbnNsYXRpb25zIGZvciBhIHNwZWNpZmljIGtleSBpbiBhIFN0cmluZyBDYXRhbG9nLiBTaG93cyB0aGUgdHJhbnNsYXRlZCB0ZXh0IGluIGVhY2ggc3VwcG9ydGVkIGxhbmd1YWdlIGFsb25nIHdpdGggdGhlIHRyYW5zbGF0aW9uIHN0YXRlLicsXG4gICAgICAgICAgICBpbnB1dFNjaGVtYToge1xuICAgICAgICAgICAgICAgIGZpbGVQYXRoOiB6LnN0cmluZygpLmRlc2NyaWJlKCdBYnNvbHV0ZSBwYXRoIHRvIHRoZSAueGNzdHJpbmdzIGZpbGUnKSxcbiAgICAgICAgICAgICAgICBrZXk6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ1RoZSBsb2NhbGl6YXRpb24ga2V5IHRvIGxvb2sgdXAnKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jICh7IGZpbGVQYXRoLCBrZXkgfSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgY2F0YWxvZyA9IG5ldyBTdHJpbmdDYXRhbG9nKGZpbGVQYXRoKTtcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGNhdGFsb2cuZ2V0VHJhbnNsYXRpb25zRm9yS2V5KGtleSk7XG5cbiAgICAgICAgICAgIGlmICghcmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGVudDogW1xuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICd0ZXh0JyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyBlcnJvcjogYEtleSBcIiR7a2V5fVwiIG5vdCBmb3VuZCBpbiBjYXRhbG9nYCB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBjb250ZW50OiBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICd0ZXh0JyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRleHQ6IEpTT04uc3RyaW5naWZ5KHJlc3VsdCwgbnVsbCwgMiksXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICApO1xufVxuIl19
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerAllTools(server: McpServer): void;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerAllTools = registerAllTools;
4
+ const list_supported_languages_1 = require("./list-supported-languages");
5
+ const get_translations_for_key_1 = require("./get-translations-for-key");
6
+ const search_keys_1 = require("./search-keys");
7
+ const update_translations_1 = require("./update-translations");
8
+ const get_catalog_statistics_1 = require("./get-catalog-statistics");
9
+ const list_all_keys_1 = require("./list-all-keys");
10
+ function registerAllTools(server) {
11
+ (0, list_supported_languages_1.registerListSupportedLanguages)(server);
12
+ (0, get_translations_for_key_1.registerGetTranslationsForKey)(server);
13
+ (0, search_keys_1.registerSearchKeys)(server);
14
+ (0, update_translations_1.registerUpdateTranslations)(server);
15
+ (0, get_catalog_statistics_1.registerGetCatalogStatistics)(server);
16
+ (0, list_all_keys_1.registerListAllKeys)(server);
17
+ }
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdG9vbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFRQSw0Q0FPQztBQWRELHlFQUE0RTtBQUM1RSx5RUFBMkU7QUFDM0UsK0NBQW1EO0FBQ25ELCtEQUFtRTtBQUNuRSxxRUFBd0U7QUFDeEUsbURBQXNEO0FBRXRELFNBQWdCLGdCQUFnQixDQUFDLE1BQWlCO0lBQzlDLElBQUEseURBQThCLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFDdkMsSUFBQSx3REFBNkIsRUFBQyxNQUFNLENBQUMsQ0FBQztJQUN0QyxJQUFBLGdDQUFrQixFQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzNCLElBQUEsZ0RBQTBCLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFDbkMsSUFBQSxxREFBNEIsRUFBQyxNQUFNLENBQUMsQ0FBQztJQUNyQyxJQUFBLG1DQUFtQixFQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQ2hDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNY3BTZXJ2ZXIgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9tY3AuanMnO1xuaW1wb3J0IHsgcmVnaXN0ZXJMaXN0U3VwcG9ydGVkTGFuZ3VhZ2VzIH0gZnJvbSAnLi9saXN0LXN1cHBvcnRlZC1sYW5ndWFnZXMnO1xuaW1wb3J0IHsgcmVnaXN0ZXJHZXRUcmFuc2xhdGlvbnNGb3JLZXkgfSBmcm9tICcuL2dldC10cmFuc2xhdGlvbnMtZm9yLWtleSc7XG5pbXBvcnQgeyByZWdpc3RlclNlYXJjaEtleXMgfSBmcm9tICcuL3NlYXJjaC1rZXlzJztcbmltcG9ydCB7IHJlZ2lzdGVyVXBkYXRlVHJhbnNsYXRpb25zIH0gZnJvbSAnLi91cGRhdGUtdHJhbnNsYXRpb25zJztcbmltcG9ydCB7IHJlZ2lzdGVyR2V0Q2F0YWxvZ1N0YXRpc3RpY3MgfSBmcm9tICcuL2dldC1jYXRhbG9nLXN0YXRpc3RpY3MnO1xuaW1wb3J0IHsgcmVnaXN0ZXJMaXN0QWxsS2V5cyB9IGZyb20gJy4vbGlzdC1hbGwta2V5cyc7XG5cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlckFsbFRvb2xzKHNlcnZlcjogTWNwU2VydmVyKSB7XG4gICAgcmVnaXN0ZXJMaXN0U3VwcG9ydGVkTGFuZ3VhZ2VzKHNlcnZlcik7XG4gICAgcmVnaXN0ZXJHZXRUcmFuc2xhdGlvbnNGb3JLZXkoc2VydmVyKTtcbiAgICByZWdpc3RlclNlYXJjaEtleXMoc2VydmVyKTtcbiAgICByZWdpc3RlclVwZGF0ZVRyYW5zbGF0aW9ucyhzZXJ2ZXIpO1xuICAgIHJlZ2lzdGVyR2V0Q2F0YWxvZ1N0YXRpc3RpY3Moc2VydmVyKTtcbiAgICByZWdpc3Rlckxpc3RBbGxLZXlzKHNlcnZlcik7XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerListAllKeys(server: McpServer): void;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerListAllKeys = registerListAllKeys;
4
+ const zod_1 = require("zod");
5
+ const string_catalog_1 = require("../string-catalog");
6
+ function registerListAllKeys(server) {
7
+ server.registerTool('list_all_keys', {
8
+ description: 'List all localization keys in a String Catalog. Returns keys sorted alphabetically.',
9
+ inputSchema: {
10
+ filePath: zod_1.z.string().describe('Absolute path to the .xcstrings file'),
11
+ limit: zod_1.z
12
+ .number()
13
+ .optional()
14
+ .default(100)
15
+ .describe('Maximum number of keys to return (default: 100)'),
16
+ offset: zod_1.z
17
+ .number()
18
+ .optional()
19
+ .default(0)
20
+ .describe('Number of keys to skip (for pagination, default: 0)'),
21
+ },
22
+ }, async ({ filePath, limit: limitArg, offset: offsetArg }) => {
23
+ const limit = limitArg ?? 100;
24
+ const offset = offsetArg ?? 0;
25
+ const catalog = new string_catalog_1.StringCatalog(filePath);
26
+ const allKeys = catalog.getAllKeys();
27
+ const paginatedKeys = allKeys.slice(offset, offset + limit);
28
+ return {
29
+ content: [
30
+ {
31
+ type: 'text',
32
+ text: JSON.stringify({
33
+ keys: paginatedKeys,
34
+ total: allKeys.length,
35
+ offset,
36
+ limit,
37
+ hasMore: offset + limit < allKeys.length,
38
+ }, null, 2),
39
+ },
40
+ ],
41
+ };
42
+ });
43
+ }
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdC1hbGwta2V5cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90b29scy9saXN0LWFsbC1rZXlzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEsa0RBK0NDO0FBbERELDZCQUF3QjtBQUN4QixzREFBa0Q7QUFFbEQsU0FBZ0IsbUJBQW1CLENBQUMsTUFBaUI7SUFDakQsTUFBTSxDQUFDLFlBQVksQ0FDZixlQUFlLEVBQ2Y7UUFDSSxXQUFXLEVBQ1AscUZBQXFGO1FBQ3pGLFdBQVcsRUFBRTtZQUNULFFBQVEsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLHNDQUFzQyxDQUFDO1lBQ3JFLEtBQUssRUFBRSxPQUFDO2lCQUNILE1BQU0sRUFBRTtpQkFDUixRQUFRLEVBQUU7aUJBQ1YsT0FBTyxDQUFDLEdBQUcsQ0FBQztpQkFDWixRQUFRLENBQUMsaURBQWlELENBQUM7WUFDaEUsTUFBTSxFQUFFLE9BQUM7aUJBQ0osTUFBTSxFQUFFO2lCQUNSLFFBQVEsRUFBRTtpQkFDVixPQUFPLENBQUMsQ0FBQyxDQUFDO2lCQUNWLFFBQVEsQ0FBQyxxREFBcUQsQ0FBQztTQUN2RTtLQUNKLEVBQ0QsS0FBSyxFQUFFLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUU7UUFDdkQsTUFBTSxLQUFLLEdBQUcsUUFBUSxJQUFJLEdBQUcsQ0FBQztRQUM5QixNQUFNLE1BQU0sR0FBRyxTQUFTLElBQUksQ0FBQyxDQUFDO1FBQzlCLE1BQU0sT0FBTyxHQUFHLElBQUksOEJBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1QyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDckMsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsTUFBTSxHQUFHLEtBQUssQ0FBQyxDQUFDO1FBRTVELE9BQU87WUFDSCxPQUFPLEVBQUU7Z0JBQ0w7b0JBQ0ksSUFBSSxFQUFFLE1BQWU7b0JBQ3JCLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUNoQjt3QkFDSSxJQUFJLEVBQUUsYUFBYTt3QkFDbkIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxNQUFNO3dCQUNyQixNQUFNO3dCQUNOLEtBQUs7d0JBQ0wsT0FBTyxFQUFFLE1BQU0sR0FBRyxLQUFLLEdBQUcsT0FBTyxDQUFDLE1BQU07cUJBQzNDLEVBQ0QsSUFBSSxFQUNKLENBQUMsQ0FDSjtpQkFDSjthQUNKO1NBQ0osQ0FBQztJQUNOLENBQUMsQ0FDSixDQUFDO0FBQ04sQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE1jcFNlcnZlciB9IGZyb20gJ0Btb2RlbGNvbnRleHRwcm90b2NvbC9zZGsvc2VydmVyL21jcC5qcyc7XG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcbmltcG9ydCB7IFN0cmluZ0NhdGFsb2cgfSBmcm9tICcuLi9zdHJpbmctY2F0YWxvZyc7XG5cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3Rlckxpc3RBbGxLZXlzKHNlcnZlcjogTWNwU2VydmVyKSB7XG4gICAgc2VydmVyLnJlZ2lzdGVyVG9vbChcbiAgICAgICAgJ2xpc3RfYWxsX2tleXMnLFxuICAgICAgICB7XG4gICAgICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAgICAgICAnTGlzdCBhbGwgbG9jYWxpemF0aW9uIGtleXMgaW4gYSBTdHJpbmcgQ2F0YWxvZy4gUmV0dXJucyBrZXlzIHNvcnRlZCBhbHBoYWJldGljYWxseS4nLFxuICAgICAgICAgICAgaW5wdXRTY2hlbWE6IHtcbiAgICAgICAgICAgICAgICBmaWxlUGF0aDogei5zdHJpbmcoKS5kZXNjcmliZSgnQWJzb2x1dGUgcGF0aCB0byB0aGUgLnhjc3RyaW5ncyBmaWxlJyksXG4gICAgICAgICAgICAgICAgbGltaXQ6IHpcbiAgICAgICAgICAgICAgICAgICAgLm51bWJlcigpXG4gICAgICAgICAgICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0KDEwMClcbiAgICAgICAgICAgICAgICAgICAgLmRlc2NyaWJlKCdNYXhpbXVtIG51bWJlciBvZiBrZXlzIHRvIHJldHVybiAoZGVmYXVsdDogMTAwKScpLFxuICAgICAgICAgICAgICAgIG9mZnNldDogelxuICAgICAgICAgICAgICAgICAgICAubnVtYmVyKClcbiAgICAgICAgICAgICAgICAgICAgLm9wdGlvbmFsKClcbiAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQoMClcbiAgICAgICAgICAgICAgICAgICAgLmRlc2NyaWJlKCdOdW1iZXIgb2Yga2V5cyB0byBza2lwIChmb3IgcGFnaW5hdGlvbiwgZGVmYXVsdDogMCknKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jICh7IGZpbGVQYXRoLCBsaW1pdDogbGltaXRBcmcsIG9mZnNldDogb2Zmc2V0QXJnIH0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGxpbWl0ID0gbGltaXRBcmcgPz8gMTAwO1xuICAgICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gb2Zmc2V0QXJnID8/IDA7XG4gICAgICAgICAgICBjb25zdCBjYXRhbG9nID0gbmV3IFN0cmluZ0NhdGFsb2coZmlsZVBhdGgpO1xuICAgICAgICAgICAgY29uc3QgYWxsS2V5cyA9IGNhdGFsb2cuZ2V0QWxsS2V5cygpO1xuICAgICAgICAgICAgY29uc3QgcGFnaW5hdGVkS2V5cyA9IGFsbEtleXMuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBsaW1pdCk7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29udGVudDogW1xuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAndGV4dCcgYXMgY29uc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleXM6IHBhZ2luYXRlZEtleXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsOiBhbGxLZXlzLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzTW9yZTogb2Zmc2V0ICsgbGltaXQgPCBhbGxLZXlzLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgMlxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICk7XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerListSupportedLanguages(server: McpServer): void;