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.
- package/.prettierrc +8 -0
- package/README.md +127 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +23 -0
- package/dist/mcp/prompts/batch-translate.d.ts +2 -0
- package/dist/mcp/prompts/batch-translate.js +88 -0
- package/dist/mcp/prompts/index.d.ts +2 -0
- package/dist/mcp/prompts/index.js +12 -0
- package/dist/mcp/prompts/review-translations.d.ts +2 -0
- package/dist/mcp/prompts/review-translations.js +75 -0
- package/dist/mcp/prompts/translate-strings.d.ts +2 -0
- package/dist/mcp/prompts/translate-strings.js +81 -0
- package/dist/mcp/tools/get-catalog-statistics.d.ts +2 -0
- package/dist/mcp/tools/get-catalog-statistics.js +25 -0
- package/dist/mcp/tools/get-translations-for-key.d.ts +2 -0
- package/dist/mcp/tools/get-translations-for-key.js +36 -0
- package/dist/mcp/tools/index.d.ts +2 -0
- package/dist/mcp/tools/index.js +18 -0
- package/dist/mcp/tools/list-all-keys.d.ts +2 -0
- package/dist/mcp/tools/list-all-keys.js +44 -0
- package/dist/mcp/tools/list-supported-languages.d.ts +2 -0
- package/dist/mcp/tools/list-supported-languages.js +30 -0
- package/dist/mcp/tools/search-keys.d.ts +2 -0
- package/dist/mcp/tools/search-keys.js +32 -0
- package/dist/mcp/tools/update-translations.d.ts +2 -0
- package/dist/mcp/tools/update-translations.js +78 -0
- package/dist/string-catalog.d.ts +53 -0
- package/dist/string-catalog.js +220 -0
- package/dist/tools/get-catalog-statistics.d.ts +2 -0
- package/dist/tools/get-catalog-statistics.js +25 -0
- package/dist/tools/get-translations-for-key.d.ts +2 -0
- package/dist/tools/get-translations-for-key.js +36 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +18 -0
- package/dist/tools/list-all-keys.d.ts +2 -0
- package/dist/tools/list-all-keys.js +44 -0
- package/dist/tools/list-supported-languages.d.ts +2 -0
- package/dist/tools/list-supported-languages.js +30 -0
- package/dist/tools/search-keys.d.ts +2 -0
- package/dist/tools/search-keys.js +32 -0
- package/dist/tools/update-translations.d.ts +2 -0
- package/dist/tools/update-translations.js +78 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.js +6 -0
- package/eslint.config.js +23 -0
- package/images/mcp.jpeg +0 -0
- package/package.json +49 -0
- package/src/index.ts +25 -0
- package/src/mcp/prompts/batch-translate.ts +91 -0
- package/src/mcp/prompts/index.ts +10 -0
- package/src/mcp/prompts/review-translations.ts +79 -0
- package/src/mcp/prompts/translate-strings.ts +85 -0
- package/src/mcp/tools/get-catalog-statistics.ts +29 -0
- package/src/mcp/tools/get-translations-for-key.ts +45 -0
- package/src/mcp/tools/index.ts +16 -0
- package/src/mcp/tools/list-all-keys.ts +52 -0
- package/src/mcp/tools/list-supported-languages.ts +38 -0
- package/src/mcp/tools/search-keys.ts +40 -0
- package/src/mcp/tools/update-translations.ts +89 -0
- package/src/string-catalog.ts +232 -0
- package/src/types.ts +82 -0
- package/tsconfig.json +28 -0
package/.prettierrc
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# string-catalog-mcp
|
|
2
|
+
|
|
3
|
+
An MCP server for working with Xcode String Catalog (.xcstrings) files. It lets AI assistants read, search, and update your iOS/macOS localization strings.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm install
|
|
11
|
+
pnpm build
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage with Claude Code
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm run mcp:add
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or manually add to your MCP config:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"string-catalog-mcp": {
|
|
26
|
+
"command": "node",
|
|
27
|
+
"args": ["/path/to/string-catalog-mcp/dist/index.js"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Available Tools
|
|
36
|
+
|
|
37
|
+
### list_supported_languages
|
|
38
|
+
|
|
39
|
+
List all languages in a string catalog with the source language identified.
|
|
40
|
+
|
|
41
|
+
> "What languages are supported in my Localizable.xcstrings file?"
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### get_catalog_statistics
|
|
46
|
+
|
|
47
|
+
Get translation coverage breakdown per language, including total keys and completion percentages.
|
|
48
|
+
|
|
49
|
+
> "Show me the translation statistics for my string catalog"
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### get_translations_for_key
|
|
54
|
+
|
|
55
|
+
Get all translations for a specific key across all supported languages.
|
|
56
|
+
|
|
57
|
+
> "Show me all translations for the 'welcome_message' key"
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
### search_keys
|
|
62
|
+
|
|
63
|
+
Search for localization keys containing a specific substring (case-insensitive).
|
|
64
|
+
|
|
65
|
+
> "Find all keys that contain 'error' in my string catalog"
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### list_all_keys
|
|
70
|
+
|
|
71
|
+
List all localization keys in the catalog (supports pagination for large catalogs).
|
|
72
|
+
|
|
73
|
+
> "List all the localization keys in my project"
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### update_translations
|
|
78
|
+
|
|
79
|
+
Add or update translations in the string catalog. Accepts a structured JSON payload with support for iOS format placeholders (`%@`, `%d`, `%lld`, `%f`, `%1$@`).
|
|
80
|
+
|
|
81
|
+
> "Add German and French translations for the 'hello_world' key"
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Available Prompts
|
|
86
|
+
|
|
87
|
+
### translate-strings
|
|
88
|
+
|
|
89
|
+
Generate translations for specific keys with guidance on format placeholders.
|
|
90
|
+
|
|
91
|
+
> "Use the translate-strings prompt to translate 'welcome_message' and 'goodbye' into German, French, and Japanese"
|
|
92
|
+
|
|
93
|
+
### batch-translate
|
|
94
|
+
|
|
95
|
+
Translate all untranslated or stale strings in a catalog for specified languages.
|
|
96
|
+
|
|
97
|
+
> "Use batch-translate to add German translations for all missing strings in my catalog"
|
|
98
|
+
|
|
99
|
+
### review-translations
|
|
100
|
+
|
|
101
|
+
Review existing translations for quality, consistency, and proper placeholder usage.
|
|
102
|
+
|
|
103
|
+
> "Review my German translations for quality issues"
|
|
104
|
+
|
|
105
|
+
## Common Workflows
|
|
106
|
+
|
|
107
|
+
### Add a new language to your app
|
|
108
|
+
|
|
109
|
+
1. "What languages are supported in my Localizable.xcstrings?"
|
|
110
|
+
2. "Use batch-translate to add Spanish translations to /path/to/Localizable.xcstrings"
|
|
111
|
+
|
|
112
|
+
### Translate specific strings
|
|
113
|
+
|
|
114
|
+
1. "Search for keys containing 'settings' in my string catalog"
|
|
115
|
+
2. "Show me translations for the 'settings_title' key"
|
|
116
|
+
3. "Translate 'settings_title' and 'settings_description' into German and French"
|
|
117
|
+
|
|
118
|
+
### Review translation quality
|
|
119
|
+
|
|
120
|
+
1. "Show me translation statistics for my catalog"
|
|
121
|
+
2. "Review German translations for placeholder issues and consistency"
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const index_1 = require("./mcp/tools/index");
|
|
7
|
+
const index_2 = require("./mcp/prompts/index");
|
|
8
|
+
const server = new mcp_js_1.McpServer({
|
|
9
|
+
name: 'string-catalog-mcp',
|
|
10
|
+
version: '1.0.0',
|
|
11
|
+
});
|
|
12
|
+
(0, index_1.registerAllTools)(server);
|
|
13
|
+
(0, index_2.registerAllPrompts)(server);
|
|
14
|
+
async function main() {
|
|
15
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
16
|
+
await server.connect(transport);
|
|
17
|
+
console.error('String Catalog MCP Server running on stdio');
|
|
18
|
+
}
|
|
19
|
+
main().catch((error) => {
|
|
20
|
+
console.error('Fatal error:', error);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEsb0VBQW9FO0FBQ3BFLHdFQUFpRjtBQUNqRiw2Q0FBcUQ7QUFDckQsK0NBQXlEO0FBRXpELE1BQU0sTUFBTSxHQUFHLElBQUksa0JBQVMsQ0FBQztJQUN6QixJQUFJLEVBQUUsb0JBQW9CO0lBQzFCLE9BQU8sRUFBRSxPQUFPO0NBQ25CLENBQUMsQ0FBQztBQUVILElBQUEsd0JBQWdCLEVBQUMsTUFBTSxDQUFDLENBQUM7QUFDekIsSUFBQSwwQkFBa0IsRUFBQyxNQUFNLENBQUMsQ0FBQztBQUUzQixLQUFLLFVBQVUsSUFBSTtJQUNmLE1BQU0sU0FBUyxHQUFHLElBQUksK0JBQW9CLEVBQUUsQ0FBQztJQUM3QyxNQUFNLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDaEMsT0FBTyxDQUFDLEtBQUssQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFDO0FBQ2hFLENBQUM7QUFFRCxJQUFJLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtJQUNuQixPQUFPLENBQUMsS0FBSyxDQUFDLGNBQWMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNyQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ3BCLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuXG5pbXBvcnQgeyBNY3BTZXJ2ZXIgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9tY3AuanMnO1xuaW1wb3J0IHsgU3RkaW9TZXJ2ZXJUcmFuc3BvcnQgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9zdGRpby5qcyc7XG5pbXBvcnQgeyByZWdpc3RlckFsbFRvb2xzIH0gZnJvbSAnLi9tY3AvdG9vbHMvaW5kZXgnO1xuaW1wb3J0IHsgcmVnaXN0ZXJBbGxQcm9tcHRzIH0gZnJvbSAnLi9tY3AvcHJvbXB0cy9pbmRleCc7XG5cbmNvbnN0IHNlcnZlciA9IG5ldyBNY3BTZXJ2ZXIoe1xuICAgIG5hbWU6ICdzdHJpbmctY2F0YWxvZy1tY3AnLFxuICAgIHZlcnNpb246ICcxLjAuMCcsXG59KTtcblxucmVnaXN0ZXJBbGxUb29scyhzZXJ2ZXIpO1xucmVnaXN0ZXJBbGxQcm9tcHRzKHNlcnZlcik7XG5cbmFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7XG4gICAgY29uc3QgdHJhbnNwb3J0ID0gbmV3IFN0ZGlvU2VydmVyVHJhbnNwb3J0KCk7XG4gICAgYXdhaXQgc2VydmVyLmNvbm5lY3QodHJhbnNwb3J0KTtcbiAgICBjb25zb2xlLmVycm9yKCdTdHJpbmcgQ2F0YWxvZyBNQ1AgU2VydmVyIHJ1bm5pbmcgb24gc3RkaW8nKTtcbn1cblxubWFpbigpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgIGNvbnNvbGUuZXJyb3IoJ0ZhdGFsIGVycm9yOicsIGVycm9yKTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG59KTtcbiJdfQ==
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerBatchTranslatePrompt = registerBatchTranslatePrompt;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
function registerBatchTranslatePrompt(server) {
|
|
6
|
+
server.registerPrompt('batch-translate', {
|
|
7
|
+
description: 'Translate all untranslated or stale strings in a catalog for specified languages.',
|
|
8
|
+
argsSchema: {
|
|
9
|
+
filePath: zod_1.z.string().describe('Absolute path to the .xcstrings file'),
|
|
10
|
+
targetLanguages: zod_1.z.string().describe('Comma-separated list of target language codes (e.g., "de,fr,ja")'),
|
|
11
|
+
includeStale: zod_1.z.boolean().default(false).describe('Whether to re-translate stale entries'),
|
|
12
|
+
batchSize: zod_1.z.number().default(20).describe('Number of keys to translate per batch (default: 20)'),
|
|
13
|
+
},
|
|
14
|
+
}, async ({ filePath, targetLanguages, includeStale, batchSize }) => {
|
|
15
|
+
const targetLangList = targetLanguages.split(',').map(l => l.trim()).filter(Boolean);
|
|
16
|
+
return {
|
|
17
|
+
messages: [
|
|
18
|
+
{
|
|
19
|
+
role: 'user',
|
|
20
|
+
content: {
|
|
21
|
+
type: 'text',
|
|
22
|
+
text: `# Batch Translation Request
|
|
23
|
+
|
|
24
|
+
## String Catalog File
|
|
25
|
+
${filePath}
|
|
26
|
+
|
|
27
|
+
## Target Languages
|
|
28
|
+
${targetLangList.map(l => `- ${l}`).join('\n')}
|
|
29
|
+
|
|
30
|
+
## Options
|
|
31
|
+
- Include stale translations: ${includeStale ? 'Yes' : 'No'}
|
|
32
|
+
- Batch size: ${batchSize} keys per batch
|
|
33
|
+
|
|
34
|
+
## Workflow
|
|
35
|
+
|
|
36
|
+
### Step 1: Analyze the Catalog
|
|
37
|
+
Use \`get_catalog_statistics\` to understand the current translation coverage.
|
|
38
|
+
|
|
39
|
+
### Step 2: Identify Keys Needing Translation
|
|
40
|
+
Use \`search_keys\` or \`list_all_keys\` to find:
|
|
41
|
+
- Keys with missing translations for target languages
|
|
42
|
+
${includeStale ? '- Keys with stale translations that need updating' : ''}
|
|
43
|
+
|
|
44
|
+
### Step 3: Translate in Batches
|
|
45
|
+
For each batch of up to ${batchSize} keys:
|
|
46
|
+
1. Get the source text using \`get_translations_for_key\`
|
|
47
|
+
2. Translate to all target languages
|
|
48
|
+
3. Prepare the JSON payload for \`update_translations\`
|
|
49
|
+
|
|
50
|
+
## iOS Format Placeholders Reference
|
|
51
|
+
Preserve these placeholders in translations:
|
|
52
|
+
- \`%@\` - String (object)
|
|
53
|
+
- \`%d\` / \`%lld\` - Integer
|
|
54
|
+
- \`%f\` - Float
|
|
55
|
+
- \`%1$@\`, \`%2$@\` - Positional (can reorder for grammar)
|
|
56
|
+
|
|
57
|
+
## Output Format
|
|
58
|
+
For each batch, provide:
|
|
59
|
+
|
|
60
|
+
\`\`\`json
|
|
61
|
+
{
|
|
62
|
+
"data": [
|
|
63
|
+
{
|
|
64
|
+
"key": "key_name",
|
|
65
|
+
"translations": [
|
|
66
|
+
{ "language": "de", "value": "German translation" },
|
|
67
|
+
{ "language": "fr", "value": "French translation" }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
\`\`\`
|
|
73
|
+
|
|
74
|
+
## Instructions
|
|
75
|
+
1. Start by analyzing the catalog
|
|
76
|
+
2. Identify which keys need translation
|
|
77
|
+
3. Process keys in batches
|
|
78
|
+
4. After each batch, use \`update_translations\` to save
|
|
79
|
+
5. Report progress after each batch
|
|
80
|
+
|
|
81
|
+
Begin the batch translation process now.`,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmF0Y2gtdHJhbnNsYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21jcC9wcm9tcHRzL2JhdGNoLXRyYW5zbGF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUdBLG9FQXVGQztBQXpGRCw2QkFBd0I7QUFFeEIsU0FBZ0IsNEJBQTRCLENBQUMsTUFBaUI7SUFDMUQsTUFBTSxDQUFDLGNBQWMsQ0FDakIsaUJBQWlCLEVBQ2pCO1FBQ0ksV0FBVyxFQUFFLG1GQUFtRjtRQUNoRyxVQUFVLEVBQUU7WUFDUixRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxzQ0FBc0MsQ0FBQztZQUNyRSxlQUFlLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxrRUFBa0UsQ0FBQztZQUN4RyxZQUFZLEVBQUUsT0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLENBQUMsdUNBQXVDLENBQUM7WUFDMUYsU0FBUyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLHFEQUFxRCxDQUFDO1NBQ3BHO0tBQ0osRUFDRCxLQUFLLEVBQUUsRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO1FBQzdELE1BQU0sY0FBYyxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRXJGLE9BQU87WUFDSCxRQUFRLEVBQUU7Z0JBQ047b0JBQ0ksSUFBSSxFQUFFLE1BQU07b0JBQ1osT0FBTyxFQUFFO3dCQUNMLElBQUksRUFBRSxNQUFNO3dCQUNaLElBQUksRUFBRTs7O0VBR2hDLFFBQVE7OztFQUdSLGNBQWMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQzs7O2dDQUdkLFlBQVksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJO2dCQUMzQyxTQUFTOzs7Ozs7Ozs7O0VBVXZCLFlBQVksQ0FBQyxDQUFDLENBQUMsbURBQW1ELENBQUMsQ0FBQyxDQUFDLEVBQUU7OzswQkFHL0MsU0FBUzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O3lDQW9DTTtxQkFDaEI7aUJBQ0o7YUFDSjtTQUNKLENBQUM7SUFDTixDQUFDLENBQ0osQ0FBQztBQUNOLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNY3BTZXJ2ZXIgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9tY3AuanMnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlckJhdGNoVHJhbnNsYXRlUHJvbXB0KHNlcnZlcjogTWNwU2VydmVyKSB7XG4gICAgc2VydmVyLnJlZ2lzdGVyUHJvbXB0KFxuICAgICAgICAnYmF0Y2gtdHJhbnNsYXRlJyxcbiAgICAgICAge1xuICAgICAgICAgICAgZGVzY3JpcHRpb246ICdUcmFuc2xhdGUgYWxsIHVudHJhbnNsYXRlZCBvciBzdGFsZSBzdHJpbmdzIGluIGEgY2F0YWxvZyBmb3Igc3BlY2lmaWVkIGxhbmd1YWdlcy4nLFxuICAgICAgICAgICAgYXJnc1NjaGVtYToge1xuICAgICAgICAgICAgICAgIGZpbGVQYXRoOiB6LnN0cmluZygpLmRlc2NyaWJlKCdBYnNvbHV0ZSBwYXRoIHRvIHRoZSAueGNzdHJpbmdzIGZpbGUnKSxcbiAgICAgICAgICAgICAgICB0YXJnZXRMYW5ndWFnZXM6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ0NvbW1hLXNlcGFyYXRlZCBsaXN0IG9mIHRhcmdldCBsYW5ndWFnZSBjb2RlcyAoZS5nLiwgXCJkZSxmcixqYVwiKScpLFxuICAgICAgICAgICAgICAgIGluY2x1ZGVTdGFsZTogei5ib29sZWFuKCkuZGVmYXVsdChmYWxzZSkuZGVzY3JpYmUoJ1doZXRoZXIgdG8gcmUtdHJhbnNsYXRlIHN0YWxlIGVudHJpZXMnKSxcbiAgICAgICAgICAgICAgICBiYXRjaFNpemU6IHoubnVtYmVyKCkuZGVmYXVsdCgyMCkuZGVzY3JpYmUoJ051bWJlciBvZiBrZXlzIHRvIHRyYW5zbGF0ZSBwZXIgYmF0Y2ggKGRlZmF1bHQ6IDIwKScpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgYXN5bmMgKHsgZmlsZVBhdGgsIHRhcmdldExhbmd1YWdlcywgaW5jbHVkZVN0YWxlLCBiYXRjaFNpemUgfSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgdGFyZ2V0TGFuZ0xpc3QgPSB0YXJnZXRMYW5ndWFnZXMuc3BsaXQoJywnKS5tYXAobCA9PiBsLnRyaW0oKSkuZmlsdGVyKEJvb2xlYW4pO1xuXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2VzOiBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJvbGU6ICd1c2VyJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAndGV4dCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dDogYCMgQmF0Y2ggVHJhbnNsYXRpb24gUmVxdWVzdFxuXG4jIyBTdHJpbmcgQ2F0YWxvZyBGaWxlXG4ke2ZpbGVQYXRofVxuXG4jIyBUYXJnZXQgTGFuZ3VhZ2VzXG4ke3RhcmdldExhbmdMaXN0Lm1hcChsID0+IGAtICR7bH1gKS5qb2luKCdcXG4nKX1cblxuIyMgT3B0aW9uc1xuLSBJbmNsdWRlIHN0YWxlIHRyYW5zbGF0aW9uczogJHtpbmNsdWRlU3RhbGUgPyAnWWVzJyA6ICdObyd9XG4tIEJhdGNoIHNpemU6ICR7YmF0Y2hTaXplfSBrZXlzIHBlciBiYXRjaFxuXG4jIyBXb3JrZmxvd1xuXG4jIyMgU3RlcCAxOiBBbmFseXplIHRoZSBDYXRhbG9nXG5Vc2UgXFxgZ2V0X2NhdGFsb2dfc3RhdGlzdGljc1xcYCB0byB1bmRlcnN0YW5kIHRoZSBjdXJyZW50IHRyYW5zbGF0aW9uIGNvdmVyYWdlLlxuXG4jIyMgU3RlcCAyOiBJZGVudGlmeSBLZXlzIE5lZWRpbmcgVHJhbnNsYXRpb25cblVzZSBcXGBzZWFyY2hfa2V5c1xcYCBvciBcXGBsaXN0X2FsbF9rZXlzXFxgIHRvIGZpbmQ6XG4tIEtleXMgd2l0aCBtaXNzaW5nIHRyYW5zbGF0aW9ucyBmb3IgdGFyZ2V0IGxhbmd1YWdlc1xuJHtpbmNsdWRlU3RhbGUgPyAnLSBLZXlzIHdpdGggc3RhbGUgdHJhbnNsYXRpb25zIHRoYXQgbmVlZCB1cGRhdGluZycgOiAnJ31cblxuIyMjIFN0ZXAgMzogVHJhbnNsYXRlIGluIEJhdGNoZXNcbkZvciBlYWNoIGJhdGNoIG9mIHVwIHRvICR7YmF0Y2hTaXplfSBrZXlzOlxuMS4gR2V0IHRoZSBzb3VyY2UgdGV4dCB1c2luZyBcXGBnZXRfdHJhbnNsYXRpb25zX2Zvcl9rZXlcXGBcbjIuIFRyYW5zbGF0ZSB0byBhbGwgdGFyZ2V0IGxhbmd1YWdlc1xuMy4gUHJlcGFyZSB0aGUgSlNPTiBwYXlsb2FkIGZvciBcXGB1cGRhdGVfdHJhbnNsYXRpb25zXFxgXG5cbiMjIGlPUyBGb3JtYXQgUGxhY2Vob2xkZXJzIFJlZmVyZW5jZVxuUHJlc2VydmUgdGhlc2UgcGxhY2Vob2xkZXJzIGluIHRyYW5zbGF0aW9uczpcbi0gXFxgJUBcXGAgLSBTdHJpbmcgKG9iamVjdClcbi0gXFxgJWRcXGAgLyBcXGAlbGxkXFxgIC0gSW50ZWdlclxuLSBcXGAlZlxcYCAtIEZsb2F0XG4tIFxcYCUxJEBcXGAsIFxcYCUyJEBcXGAgLSBQb3NpdGlvbmFsIChjYW4gcmVvcmRlciBmb3IgZ3JhbW1hcilcblxuIyMgT3V0cHV0IEZvcm1hdFxuRm9yIGVhY2ggYmF0Y2gsIHByb3ZpZGU6XG5cblxcYFxcYFxcYGpzb25cbntcbiAgICBcImRhdGFcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgICBcImtleVwiOiBcImtleV9uYW1lXCIsXG4gICAgICAgICAgICBcInRyYW5zbGF0aW9uc1wiOiBbXG4gICAgICAgICAgICAgICAgeyBcImxhbmd1YWdlXCI6IFwiZGVcIiwgXCJ2YWx1ZVwiOiBcIkdlcm1hbiB0cmFuc2xhdGlvblwiIH0sXG4gICAgICAgICAgICAgICAgeyBcImxhbmd1YWdlXCI6IFwiZnJcIiwgXCJ2YWx1ZVwiOiBcIkZyZW5jaCB0cmFuc2xhdGlvblwiIH1cbiAgICAgICAgICAgIF1cbiAgICAgICAgfVxuICAgIF1cbn1cblxcYFxcYFxcYFxuXG4jIyBJbnN0cnVjdGlvbnNcbjEuIFN0YXJ0IGJ5IGFuYWx5emluZyB0aGUgY2F0YWxvZ1xuMi4gSWRlbnRpZnkgd2hpY2gga2V5cyBuZWVkIHRyYW5zbGF0aW9uXG4zLiBQcm9jZXNzIGtleXMgaW4gYmF0Y2hlc1xuNC4gQWZ0ZXIgZWFjaCBiYXRjaCwgdXNlIFxcYHVwZGF0ZV90cmFuc2xhdGlvbnNcXGAgdG8gc2F2ZVxuNS4gUmVwb3J0IHByb2dyZXNzIGFmdGVyIGVhY2ggYmF0Y2hcblxuQmVnaW4gdGhlIGJhdGNoIHRyYW5zbGF0aW9uIHByb2Nlc3Mgbm93LmAsXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgKTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerAllPrompts = registerAllPrompts;
|
|
4
|
+
const translate_strings_1 = require("./translate-strings");
|
|
5
|
+
const review_translations_1 = require("./review-translations");
|
|
6
|
+
const batch_translate_1 = require("./batch-translate");
|
|
7
|
+
function registerAllPrompts(server) {
|
|
8
|
+
(0, translate_strings_1.registerTranslateStringsPrompt)(server);
|
|
9
|
+
(0, review_translations_1.registerReviewTranslationsPrompt)(server);
|
|
10
|
+
(0, batch_translate_1.registerBatchTranslatePrompt)(server);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbWNwL3Byb21wdHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFLQSxnREFJQztBQVJELDJEQUFxRTtBQUNyRSwrREFBeUU7QUFDekUsdURBQWlFO0FBRWpFLFNBQWdCLGtCQUFrQixDQUFDLE1BQWlCO0lBQ2hELElBQUEsa0RBQThCLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFDdkMsSUFBQSxzREFBZ0MsRUFBQyxNQUFNLENBQUMsQ0FBQztJQUN6QyxJQUFBLDhDQUE0QixFQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQ3pDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNY3BTZXJ2ZXIgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9tY3AuanMnO1xuaW1wb3J0IHsgcmVnaXN0ZXJUcmFuc2xhdGVTdHJpbmdzUHJvbXB0IH0gZnJvbSAnLi90cmFuc2xhdGUtc3RyaW5ncyc7XG5pbXBvcnQgeyByZWdpc3RlclJldmlld1RyYW5zbGF0aW9uc1Byb21wdCB9IGZyb20gJy4vcmV2aWV3LXRyYW5zbGF0aW9ucyc7XG5pbXBvcnQgeyByZWdpc3RlckJhdGNoVHJhbnNsYXRlUHJvbXB0IH0gZnJvbSAnLi9iYXRjaC10cmFuc2xhdGUnO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJBbGxQcm9tcHRzKHNlcnZlcjogTWNwU2VydmVyKSB7XG4gICAgcmVnaXN0ZXJUcmFuc2xhdGVTdHJpbmdzUHJvbXB0KHNlcnZlcik7XG4gICAgcmVnaXN0ZXJSZXZpZXdUcmFuc2xhdGlvbnNQcm9tcHQoc2VydmVyKTtcbiAgICByZWdpc3RlckJhdGNoVHJhbnNsYXRlUHJvbXB0KHNlcnZlcik7XG59XG4iXX0=
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerReviewTranslationsPrompt = registerReviewTranslationsPrompt;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
function registerReviewTranslationsPrompt(server) {
|
|
6
|
+
server.registerPrompt('review-translations', {
|
|
7
|
+
description: 'Review existing translations for quality, consistency, and proper placeholder usage.',
|
|
8
|
+
argsSchema: {
|
|
9
|
+
filePath: zod_1.z.string().describe('Absolute path to the .xcstrings file'),
|
|
10
|
+
languages: zod_1.z.string().optional().describe('Comma-separated list of language codes to review (default: all)'),
|
|
11
|
+
focusAreas: zod_1.z.string().optional().describe('Comma-separated areas to focus on (e.g., "placeholders,consistency,tone")'),
|
|
12
|
+
},
|
|
13
|
+
}, async ({ filePath, languages, focusAreas }) => {
|
|
14
|
+
const langSection = languages
|
|
15
|
+
? `\n## Languages to Review\n${languages.split(',').map(l => `- ${l.trim()}`).join('\n')}\n`
|
|
16
|
+
: '\n## Languages to Review\nAll available languages in the catalog.\n';
|
|
17
|
+
const focusSection = focusAreas
|
|
18
|
+
? `\n## Focus Areas\n${focusAreas.split(',').map(f => `- ${f.trim()}`).join('\n')}\n`
|
|
19
|
+
: '';
|
|
20
|
+
return {
|
|
21
|
+
messages: [
|
|
22
|
+
{
|
|
23
|
+
role: 'user',
|
|
24
|
+
content: {
|
|
25
|
+
type: 'text',
|
|
26
|
+
text: `# Translation Review Request
|
|
27
|
+
|
|
28
|
+
## String Catalog File
|
|
29
|
+
${filePath}
|
|
30
|
+
${langSection}${focusSection}
|
|
31
|
+
## Review Checklist
|
|
32
|
+
|
|
33
|
+
### 1. Format Placeholder Verification
|
|
34
|
+
- Ensure all \`%@\`, \`%d\`, \`%lld\`, \`%f\` placeholders are preserved
|
|
35
|
+
- Verify positional arguments (\`%1$@\`, \`%2$@\`) are used correctly
|
|
36
|
+
- Check that placeholder count matches the source string
|
|
37
|
+
|
|
38
|
+
### 2. Translation Quality
|
|
39
|
+
- Verify translations are accurate and natural-sounding
|
|
40
|
+
- Check for grammatical errors
|
|
41
|
+
- Ensure translations fit the context of a mobile app UI
|
|
42
|
+
|
|
43
|
+
### 3. Consistency
|
|
44
|
+
- Similar strings should have consistent translations
|
|
45
|
+
- Terminology should be uniform across the app
|
|
46
|
+
- UI element names should match platform conventions
|
|
47
|
+
|
|
48
|
+
### 4. Cultural Appropriateness
|
|
49
|
+
- Verify idioms are properly localized
|
|
50
|
+
- Check for culturally sensitive content
|
|
51
|
+
- Ensure date/number formats are appropriate
|
|
52
|
+
|
|
53
|
+
### 5. Length Considerations
|
|
54
|
+
- Flag translations that are significantly longer than source
|
|
55
|
+
- Consider UI space constraints for mobile apps
|
|
56
|
+
|
|
57
|
+
## Instructions
|
|
58
|
+
1. Use the \`get_catalog_statistics\` tool to see overall translation coverage
|
|
59
|
+
2. Use the \`list_all_keys\` tool to see available keys
|
|
60
|
+
3. Use the \`get_translations_for_key\` tool to examine specific translations
|
|
61
|
+
4. Report any issues found with specific keys and languages
|
|
62
|
+
5. Suggest corrections using the \`update_translations\` tool format
|
|
63
|
+
|
|
64
|
+
## Output Format
|
|
65
|
+
Provide a structured review report:
|
|
66
|
+
- Summary of findings
|
|
67
|
+
- List of issues by severity (critical, warning, suggestion)
|
|
68
|
+
- Recommended fixes in JSON format for the update_translations tool`,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV2aWV3LXRyYW5zbGF0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tY3AvcHJvbXB0cy9yZXZpZXctdHJhbnNsYXRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBR0EsNEVBMkVDO0FBN0VELDZCQUF3QjtBQUV4QixTQUFnQixnQ0FBZ0MsQ0FBQyxNQUFpQjtJQUM5RCxNQUFNLENBQUMsY0FBYyxDQUNqQixxQkFBcUIsRUFDckI7UUFDSSxXQUFXLEVBQUUsc0ZBQXNGO1FBQ25HLFVBQVUsRUFBRTtZQUNSLFFBQVEsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLHNDQUFzQyxDQUFDO1lBQ3JFLFNBQVMsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLGlFQUFpRSxDQUFDO1lBQzVHLFVBQVUsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLDJFQUEyRSxDQUFDO1NBQzFIO0tBQ0osRUFDRCxLQUFLLEVBQUUsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUU7UUFDMUMsTUFBTSxXQUFXLEdBQUcsU0FBUztZQUN6QixDQUFDLENBQUMsNkJBQTZCLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSTtZQUM1RixDQUFDLENBQUMscUVBQXFFLENBQUM7UUFFNUUsTUFBTSxZQUFZLEdBQUcsVUFBVTtZQUMzQixDQUFDLENBQUMscUJBQXFCLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSTtZQUNyRixDQUFDLENBQUMsRUFBRSxDQUFDO1FBRVQsT0FBTztZQUNILFFBQVEsRUFBRTtnQkFDTjtvQkFDSSxJQUFJLEVBQUUsTUFBTTtvQkFDWixPQUFPLEVBQUU7d0JBQ0wsSUFBSSxFQUFFLE1BQU07d0JBQ1osSUFBSSxFQUFFOzs7RUFHaEMsUUFBUTtFQUNSLFdBQVcsR0FBRyxZQUFZOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztvRUFzQ3dDO3FCQUMzQztpQkFDSjthQUNKO1NBQ0osQ0FBQztJQUNOLENBQUMsQ0FDSixDQUFDO0FBQ04sQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE1jcFNlcnZlciB9IGZyb20gJ0Btb2RlbGNvbnRleHRwcm90b2NvbC9zZGsvc2VydmVyL21jcC5qcyc7XG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcblxuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lzdGVyUmV2aWV3VHJhbnNsYXRpb25zUHJvbXB0KHNlcnZlcjogTWNwU2VydmVyKSB7XG4gICAgc2VydmVyLnJlZ2lzdGVyUHJvbXB0KFxuICAgICAgICAncmV2aWV3LXRyYW5zbGF0aW9ucycsXG4gICAgICAgIHtcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAnUmV2aWV3IGV4aXN0aW5nIHRyYW5zbGF0aW9ucyBmb3IgcXVhbGl0eSwgY29uc2lzdGVuY3ksIGFuZCBwcm9wZXIgcGxhY2Vob2xkZXIgdXNhZ2UuJyxcbiAgICAgICAgICAgIGFyZ3NTY2hlbWE6IHtcbiAgICAgICAgICAgICAgICBmaWxlUGF0aDogei5zdHJpbmcoKS5kZXNjcmliZSgnQWJzb2x1dGUgcGF0aCB0byB0aGUgLnhjc3RyaW5ncyBmaWxlJyksXG4gICAgICAgICAgICAgICAgbGFuZ3VhZ2VzOiB6LnN0cmluZygpLm9wdGlvbmFsKCkuZGVzY3JpYmUoJ0NvbW1hLXNlcGFyYXRlZCBsaXN0IG9mIGxhbmd1YWdlIGNvZGVzIHRvIHJldmlldyAoZGVmYXVsdDogYWxsKScpLFxuICAgICAgICAgICAgICAgIGZvY3VzQXJlYXM6IHouc3RyaW5nKCkub3B0aW9uYWwoKS5kZXNjcmliZSgnQ29tbWEtc2VwYXJhdGVkIGFyZWFzIHRvIGZvY3VzIG9uIChlLmcuLCBcInBsYWNlaG9sZGVycyxjb25zaXN0ZW5jeSx0b25lXCIpJyksXG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBhc3luYyAoeyBmaWxlUGF0aCwgbGFuZ3VhZ2VzLCBmb2N1c0FyZWFzIH0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGxhbmdTZWN0aW9uID0gbGFuZ3VhZ2VzXG4gICAgICAgICAgICAgICAgPyBgXFxuIyMgTGFuZ3VhZ2VzIHRvIFJldmlld1xcbiR7bGFuZ3VhZ2VzLnNwbGl0KCcsJykubWFwKGwgPT4gYC0gJHtsLnRyaW0oKX1gKS5qb2luKCdcXG4nKX1cXG5gXG4gICAgICAgICAgICAgICAgOiAnXFxuIyMgTGFuZ3VhZ2VzIHRvIFJldmlld1xcbkFsbCBhdmFpbGFibGUgbGFuZ3VhZ2VzIGluIHRoZSBjYXRhbG9nLlxcbic7XG5cbiAgICAgICAgICAgIGNvbnN0IGZvY3VzU2VjdGlvbiA9IGZvY3VzQXJlYXNcbiAgICAgICAgICAgICAgICA/IGBcXG4jIyBGb2N1cyBBcmVhc1xcbiR7Zm9jdXNBcmVhcy5zcGxpdCgnLCcpLm1hcChmID0+IGAtICR7Zi50cmltKCl9YCkuam9pbignXFxuJyl9XFxuYFxuICAgICAgICAgICAgICAgIDogJyc7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ3VzZXInLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBgIyBUcmFuc2xhdGlvbiBSZXZpZXcgUmVxdWVzdFxuXG4jIyBTdHJpbmcgQ2F0YWxvZyBGaWxlXG4ke2ZpbGVQYXRofVxuJHtsYW5nU2VjdGlvbn0ke2ZvY3VzU2VjdGlvbn1cbiMjIFJldmlldyBDaGVja2xpc3RcblxuIyMjIDEuIEZvcm1hdCBQbGFjZWhvbGRlciBWZXJpZmljYXRpb25cbi0gRW5zdXJlIGFsbCBcXGAlQFxcYCwgXFxgJWRcXGAsIFxcYCVsbGRcXGAsIFxcYCVmXFxgIHBsYWNlaG9sZGVycyBhcmUgcHJlc2VydmVkXG4tIFZlcmlmeSBwb3NpdGlvbmFsIGFyZ3VtZW50cyAoXFxgJTEkQFxcYCwgXFxgJTIkQFxcYCkgYXJlIHVzZWQgY29ycmVjdGx5XG4tIENoZWNrIHRoYXQgcGxhY2Vob2xkZXIgY291bnQgbWF0Y2hlcyB0aGUgc291cmNlIHN0cmluZ1xuXG4jIyMgMi4gVHJhbnNsYXRpb24gUXVhbGl0eVxuLSBWZXJpZnkgdHJhbnNsYXRpb25zIGFyZSBhY2N1cmF0ZSBhbmQgbmF0dXJhbC1zb3VuZGluZ1xuLSBDaGVjayBmb3IgZ3JhbW1hdGljYWwgZXJyb3JzXG4tIEVuc3VyZSB0cmFuc2xhdGlvbnMgZml0IHRoZSBjb250ZXh0IG9mIGEgbW9iaWxlIGFwcCBVSVxuXG4jIyMgMy4gQ29uc2lzdGVuY3lcbi0gU2ltaWxhciBzdHJpbmdzIHNob3VsZCBoYXZlIGNvbnNpc3RlbnQgdHJhbnNsYXRpb25zXG4tIFRlcm1pbm9sb2d5IHNob3VsZCBiZSB1bmlmb3JtIGFjcm9zcyB0aGUgYXBwXG4tIFVJIGVsZW1lbnQgbmFtZXMgc2hvdWxkIG1hdGNoIHBsYXRmb3JtIGNvbnZlbnRpb25zXG5cbiMjIyA0LiBDdWx0dXJhbCBBcHByb3ByaWF0ZW5lc3Ncbi0gVmVyaWZ5IGlkaW9tcyBhcmUgcHJvcGVybHkgbG9jYWxpemVkXG4tIENoZWNrIGZvciBjdWx0dXJhbGx5IHNlbnNpdGl2ZSBjb250ZW50XG4tIEVuc3VyZSBkYXRlL251bWJlciBmb3JtYXRzIGFyZSBhcHByb3ByaWF0ZVxuXG4jIyMgNS4gTGVuZ3RoIENvbnNpZGVyYXRpb25zXG4tIEZsYWcgdHJhbnNsYXRpb25zIHRoYXQgYXJlIHNpZ25pZmljYW50bHkgbG9uZ2VyIHRoYW4gc291cmNlXG4tIENvbnNpZGVyIFVJIHNwYWNlIGNvbnN0cmFpbnRzIGZvciBtb2JpbGUgYXBwc1xuXG4jIyBJbnN0cnVjdGlvbnNcbjEuIFVzZSB0aGUgXFxgZ2V0X2NhdGFsb2dfc3RhdGlzdGljc1xcYCB0b29sIHRvIHNlZSBvdmVyYWxsIHRyYW5zbGF0aW9uIGNvdmVyYWdlXG4yLiBVc2UgdGhlIFxcYGxpc3RfYWxsX2tleXNcXGAgdG9vbCB0byBzZWUgYXZhaWxhYmxlIGtleXNcbjMuIFVzZSB0aGUgXFxgZ2V0X3RyYW5zbGF0aW9uc19mb3Jfa2V5XFxgIHRvb2wgdG8gZXhhbWluZSBzcGVjaWZpYyB0cmFuc2xhdGlvbnNcbjQuIFJlcG9ydCBhbnkgaXNzdWVzIGZvdW5kIHdpdGggc3BlY2lmaWMga2V5cyBhbmQgbGFuZ3VhZ2VzXG41LiBTdWdnZXN0IGNvcnJlY3Rpb25zIHVzaW5nIHRoZSBcXGB1cGRhdGVfdHJhbnNsYXRpb25zXFxgIHRvb2wgZm9ybWF0XG5cbiMjIE91dHB1dCBGb3JtYXRcblByb3ZpZGUgYSBzdHJ1Y3R1cmVkIHJldmlldyByZXBvcnQ6XG4tIFN1bW1hcnkgb2YgZmluZGluZ3Ncbi0gTGlzdCBvZiBpc3N1ZXMgYnkgc2V2ZXJpdHkgKGNyaXRpY2FsLCB3YXJuaW5nLCBzdWdnZXN0aW9uKVxuLSBSZWNvbW1lbmRlZCBmaXhlcyBpbiBKU09OIGZvcm1hdCBmb3IgdGhlIHVwZGF0ZV90cmFuc2xhdGlvbnMgdG9vbGAsXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgKTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerTranslateStringsPrompt = registerTranslateStringsPrompt;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
function registerTranslateStringsPrompt(server) {
|
|
6
|
+
server.registerPrompt('translate-strings', {
|
|
7
|
+
description: 'Generate translations for iOS string catalog keys. Provides guidance on format placeholders and returns structured JSON for the update_translations tool.',
|
|
8
|
+
argsSchema: {
|
|
9
|
+
keys: zod_1.z.string().describe('Comma-separated list of keys to translate (e.g., "hello_world,goodbye,welcome_message")'),
|
|
10
|
+
sourceLanguage: zod_1.z.string().default('en').describe('Source language code (default: en)'),
|
|
11
|
+
targetLanguages: zod_1.z.string().describe('Comma-separated list of target language codes (e.g., "de,fr,ja,zh-Hans")'),
|
|
12
|
+
context: zod_1.z.string().optional().describe('Optional context about where these strings are used in the app'),
|
|
13
|
+
},
|
|
14
|
+
}, async ({ keys, sourceLanguage, targetLanguages, context }) => {
|
|
15
|
+
const keyList = keys.split(',').map(k => k.trim()).filter(Boolean);
|
|
16
|
+
const targetLangList = targetLanguages.split(',').map(l => l.trim()).filter(Boolean);
|
|
17
|
+
const contextSection = context
|
|
18
|
+
? `\n## Context\nThese strings are used in: ${context}\n`
|
|
19
|
+
: '';
|
|
20
|
+
return {
|
|
21
|
+
messages: [
|
|
22
|
+
{
|
|
23
|
+
role: 'user',
|
|
24
|
+
content: {
|
|
25
|
+
type: 'text',
|
|
26
|
+
text: `# Translation Request for iOS String Catalog
|
|
27
|
+
|
|
28
|
+
## Keys to Translate
|
|
29
|
+
${keyList.map(k => `- "${k}"`).join('\n')}
|
|
30
|
+
|
|
31
|
+
## Source Language
|
|
32
|
+
${sourceLanguage}
|
|
33
|
+
|
|
34
|
+
## Target Languages
|
|
35
|
+
${targetLangList.map(l => `- ${l}`).join('\n')}
|
|
36
|
+
${contextSection}
|
|
37
|
+
## iOS Format Placeholders
|
|
38
|
+
When translating, preserve these iOS format placeholders exactly as they appear:
|
|
39
|
+
- \`%@\` - String placeholder (objects)
|
|
40
|
+
- \`%d\` or \`%lld\` - Integer placeholder
|
|
41
|
+
- \`%f\` - Floating point number placeholder
|
|
42
|
+
- \`%1$@\`, \`%2$@\` - Positional arguments (order CAN be changed to fit natural language grammar)
|
|
43
|
+
|
|
44
|
+
## Example
|
|
45
|
+
If source is: "Hello %@, you have %lld items"
|
|
46
|
+
German could be: "Hallo %@, Sie haben %lld Artikel"
|
|
47
|
+
Japanese could be: "%@さん、%lld個のアイテムがあります"
|
|
48
|
+
|
|
49
|
+
## Instructions
|
|
50
|
+
1. Translate each key into all target languages
|
|
51
|
+
2. Preserve all format placeholders
|
|
52
|
+
3. Ensure translations sound natural in each language
|
|
53
|
+
4. Consider cultural context and localization best practices
|
|
54
|
+
|
|
55
|
+
## Required Output Format
|
|
56
|
+
Return the translations as JSON that can be used with the \`update_translations\` tool:
|
|
57
|
+
|
|
58
|
+
\`\`\`json
|
|
59
|
+
{
|
|
60
|
+
"data": [
|
|
61
|
+
{
|
|
62
|
+
"key": "key_name",
|
|
63
|
+
"translations": [
|
|
64
|
+
{ "language": "en", "value": "English text" },
|
|
65
|
+
{ "language": "de", "value": "German text" },
|
|
66
|
+
{ "language": "fr", "value": "French text" }
|
|
67
|
+
],
|
|
68
|
+
"comment": "Optional: describe where this string is used"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
\`\`\`
|
|
73
|
+
|
|
74
|
+
Please translate the keys now.`,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlLXN0cmluZ3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbWNwL3Byb21wdHMvdHJhbnNsYXRlLXN0cmluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFHQSx3RUFpRkM7QUFuRkQsNkJBQXdCO0FBRXhCLFNBQWdCLDhCQUE4QixDQUFDLE1BQWlCO0lBQzVELE1BQU0sQ0FBQyxjQUFjLENBQ2pCLG1CQUFtQixFQUNuQjtRQUNJLFdBQVcsRUFBRSwySkFBMko7UUFDeEssVUFBVSxFQUFFO1lBQ1IsSUFBSSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMseUZBQXlGLENBQUM7WUFDcEgsY0FBYyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxDQUFDLG9DQUFvQyxDQUFDO1lBQ3ZGLGVBQWUsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLDBFQUEwRSxDQUFDO1lBQ2hILE9BQU8sRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLGdFQUFnRSxDQUFDO1NBQzVHO0tBQ0osRUFDRCxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFO1FBQ3pELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ25FLE1BQU0sY0FBYyxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRXJGLE1BQU0sY0FBYyxHQUFHLE9BQU87WUFDMUIsQ0FBQyxDQUFDLDRDQUE0QyxPQUFPLElBQUk7WUFDekQsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUVULE9BQU87WUFDSCxRQUFRLEVBQUU7Z0JBQ047b0JBQ0ksSUFBSSxFQUFFLE1BQU07b0JBQ1osT0FBTyxFQUFFO3dCQUNMLElBQUksRUFBRSxNQUFNO3dCQUNaLElBQUksRUFBRTs7O0VBR2hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQzs7O0VBR3ZDLGNBQWM7OztFQUdkLGNBQWMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztFQUM1QyxjQUFjOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsrQkFzQ2U7cUJBQ047aUJBQ0o7YUFDSjtTQUNKLENBQUM7SUFDTixDQUFDLENBQ0osQ0FBQztBQUNOLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNY3BTZXJ2ZXIgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9tY3AuanMnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlclRyYW5zbGF0ZVN0cmluZ3NQcm9tcHQoc2VydmVyOiBNY3BTZXJ2ZXIpIHtcbiAgICBzZXJ2ZXIucmVnaXN0ZXJQcm9tcHQoXG4gICAgICAgICd0cmFuc2xhdGUtc3RyaW5ncycsXG4gICAgICAgIHtcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAnR2VuZXJhdGUgdHJhbnNsYXRpb25zIGZvciBpT1Mgc3RyaW5nIGNhdGFsb2cga2V5cy4gUHJvdmlkZXMgZ3VpZGFuY2Ugb24gZm9ybWF0IHBsYWNlaG9sZGVycyBhbmQgcmV0dXJucyBzdHJ1Y3R1cmVkIEpTT04gZm9yIHRoZSB1cGRhdGVfdHJhbnNsYXRpb25zIHRvb2wuJyxcbiAgICAgICAgICAgIGFyZ3NTY2hlbWE6IHtcbiAgICAgICAgICAgICAgICBrZXlzOiB6LnN0cmluZygpLmRlc2NyaWJlKCdDb21tYS1zZXBhcmF0ZWQgbGlzdCBvZiBrZXlzIHRvIHRyYW5zbGF0ZSAoZS5nLiwgXCJoZWxsb193b3JsZCxnb29kYnllLHdlbGNvbWVfbWVzc2FnZVwiKScpLFxuICAgICAgICAgICAgICAgIHNvdXJjZUxhbmd1YWdlOiB6LnN0cmluZygpLmRlZmF1bHQoJ2VuJykuZGVzY3JpYmUoJ1NvdXJjZSBsYW5ndWFnZSBjb2RlIChkZWZhdWx0OiBlbiknKSxcbiAgICAgICAgICAgICAgICB0YXJnZXRMYW5ndWFnZXM6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ0NvbW1hLXNlcGFyYXRlZCBsaXN0IG9mIHRhcmdldCBsYW5ndWFnZSBjb2RlcyAoZS5nLiwgXCJkZSxmcixqYSx6aC1IYW5zXCIpJyksXG4gICAgICAgICAgICAgICAgY29udGV4dDogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKCdPcHRpb25hbCBjb250ZXh0IGFib3V0IHdoZXJlIHRoZXNlIHN0cmluZ3MgYXJlIHVzZWQgaW4gdGhlIGFwcCcpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgYXN5bmMgKHsga2V5cywgc291cmNlTGFuZ3VhZ2UsIHRhcmdldExhbmd1YWdlcywgY29udGV4dCB9KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBrZXlMaXN0ID0ga2V5cy5zcGxpdCgnLCcpLm1hcChrID0+IGsudHJpbSgpKS5maWx0ZXIoQm9vbGVhbik7XG4gICAgICAgICAgICBjb25zdCB0YXJnZXRMYW5nTGlzdCA9IHRhcmdldExhbmd1YWdlcy5zcGxpdCgnLCcpLm1hcChsID0+IGwudHJpbSgpKS5maWx0ZXIoQm9vbGVhbik7XG5cbiAgICAgICAgICAgIGNvbnN0IGNvbnRleHRTZWN0aW9uID0gY29udGV4dFxuICAgICAgICAgICAgICAgID8gYFxcbiMjIENvbnRleHRcXG5UaGVzZSBzdHJpbmdzIGFyZSB1c2VkIGluOiAke2NvbnRleHR9XFxuYFxuICAgICAgICAgICAgICAgIDogJyc7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ3VzZXInLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBgIyBUcmFuc2xhdGlvbiBSZXF1ZXN0IGZvciBpT1MgU3RyaW5nIENhdGFsb2dcblxuIyMgS2V5cyB0byBUcmFuc2xhdGVcbiR7a2V5TGlzdC5tYXAoayA9PiBgLSBcIiR7a31cImApLmpvaW4oJ1xcbicpfVxuXG4jIyBTb3VyY2UgTGFuZ3VhZ2VcbiR7c291cmNlTGFuZ3VhZ2V9XG5cbiMjIFRhcmdldCBMYW5ndWFnZXNcbiR7dGFyZ2V0TGFuZ0xpc3QubWFwKGwgPT4gYC0gJHtsfWApLmpvaW4oJ1xcbicpfVxuJHtjb250ZXh0U2VjdGlvbn1cbiMjIGlPUyBGb3JtYXQgUGxhY2Vob2xkZXJzXG5XaGVuIHRyYW5zbGF0aW5nLCBwcmVzZXJ2ZSB0aGVzZSBpT1MgZm9ybWF0IHBsYWNlaG9sZGVycyBleGFjdGx5IGFzIHRoZXkgYXBwZWFyOlxuLSBcXGAlQFxcYCAtIFN0cmluZyBwbGFjZWhvbGRlciAob2JqZWN0cylcbi0gXFxgJWRcXGAgb3IgXFxgJWxsZFxcYCAtIEludGVnZXIgcGxhY2Vob2xkZXJcbi0gXFxgJWZcXGAgLSBGbG9hdGluZyBwb2ludCBudW1iZXIgcGxhY2Vob2xkZXJcbi0gXFxgJTEkQFxcYCwgXFxgJTIkQFxcYCAtIFBvc2l0aW9uYWwgYXJndW1lbnRzIChvcmRlciBDQU4gYmUgY2hhbmdlZCB0byBmaXQgbmF0dXJhbCBsYW5ndWFnZSBncmFtbWFyKVxuXG4jIyBFeGFtcGxlXG5JZiBzb3VyY2UgaXM6IFwiSGVsbG8gJUAsIHlvdSBoYXZlICVsbGQgaXRlbXNcIlxuR2VybWFuIGNvdWxkIGJlOiBcIkhhbGxvICVALCBTaWUgaGFiZW4gJWxsZCBBcnRpa2VsXCJcbkphcGFuZXNlIGNvdWxkIGJlOiBcIiVA44GV44KT44CBJWxsZOWAi+OBruOCouOCpOODhuODoOOBjOOBguOCiuOBvuOBmVwiXG5cbiMjIEluc3RydWN0aW9uc1xuMS4gVHJhbnNsYXRlIGVhY2gga2V5IGludG8gYWxsIHRhcmdldCBsYW5ndWFnZXNcbjIuIFByZXNlcnZlIGFsbCBmb3JtYXQgcGxhY2Vob2xkZXJzXG4zLiBFbnN1cmUgdHJhbnNsYXRpb25zIHNvdW5kIG5hdHVyYWwgaW4gZWFjaCBsYW5ndWFnZVxuNC4gQ29uc2lkZXIgY3VsdHVyYWwgY29udGV4dCBhbmQgbG9jYWxpemF0aW9uIGJlc3QgcHJhY3RpY2VzXG5cbiMjIFJlcXVpcmVkIE91dHB1dCBGb3JtYXRcblJldHVybiB0aGUgdHJhbnNsYXRpb25zIGFzIEpTT04gdGhhdCBjYW4gYmUgdXNlZCB3aXRoIHRoZSBcXGB1cGRhdGVfdHJhbnNsYXRpb25zXFxgIHRvb2w6XG5cblxcYFxcYFxcYGpzb25cbntcbiAgICBcImRhdGFcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgICBcImtleVwiOiBcImtleV9uYW1lXCIsXG4gICAgICAgICAgICBcInRyYW5zbGF0aW9uc1wiOiBbXG4gICAgICAgICAgICAgICAgeyBcImxhbmd1YWdlXCI6IFwiZW5cIiwgXCJ2YWx1ZVwiOiBcIkVuZ2xpc2ggdGV4dFwiIH0sXG4gICAgICAgICAgICAgICAgeyBcImxhbmd1YWdlXCI6IFwiZGVcIiwgXCJ2YWx1ZVwiOiBcIkdlcm1hbiB0ZXh0XCIgfSxcbiAgICAgICAgICAgICAgICB7IFwibGFuZ3VhZ2VcIjogXCJmclwiLCBcInZhbHVlXCI6IFwiRnJlbmNoIHRleHRcIiB9XG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJjb21tZW50XCI6IFwiT3B0aW9uYWw6IGRlc2NyaWJlIHdoZXJlIHRoaXMgc3RyaW5nIGlzIHVzZWRcIlxuICAgICAgICB9XG4gICAgXVxufVxuXFxgXFxgXFxgXG5cblBsZWFzZSB0cmFuc2xhdGUgdGhlIGtleXMgbm93LmAsXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgKTtcbn1cbiJdfQ==
|
|
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LWNhdGFsb2ctc3RhdGlzdGljcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tY3AvdG9vbHMvZ2V0LWNhdGFsb2ctc3RhdGlzdGljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUlBLG9FQXdCQztBQTNCRCw2QkFBd0I7QUFDeEIseURBQXFEO0FBRXJELFNBQWdCLDRCQUE0QixDQUFDLE1BQWlCO0lBQzFELE1BQU0sQ0FBQyxZQUFZLENBQ2Ysd0JBQXdCLEVBQ3hCO1FBQ0ksV0FBVyxFQUNQLHlJQUF5STtRQUM3SSxXQUFXLEVBQUU7WUFDVCxRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxzQ0FBc0MsQ0FBQztTQUN4RTtLQUNKLEVBQ0QsS0FBSyxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRTtRQUNuQixNQUFNLE9BQU8sR0FBRyxJQUFJLDhCQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDNUMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBRXRDLE9BQU87WUFDSCxPQUFPLEVBQUU7Z0JBQ0w7b0JBQ0ksSUFBSSxFQUFFLE1BQWU7b0JBQ3JCLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2lCQUN2QzthQUNKO1NBQ0osQ0FBQztJQUNOLENBQUMsQ0FDSixDQUFDO0FBQ04sQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE1jcFNlcnZlciB9IGZyb20gJ0Btb2RlbGNvbnRleHRwcm90b2NvbC9zZGsvc2VydmVyL21jcC5qcyc7XG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcbmltcG9ydCB7IFN0cmluZ0NhdGFsb2cgfSBmcm9tICcuLi8uLi9zdHJpbmctY2F0YWxvZyc7XG5cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlckdldENhdGFsb2dTdGF0aXN0aWNzKHNlcnZlcjogTWNwU2VydmVyKSB7XG4gICAgc2VydmVyLnJlZ2lzdGVyVG9vbChcbiAgICAgICAgJ2dldF9jYXRhbG9nX3N0YXRpc3RpY3MnLFxuICAgICAgICB7XG4gICAgICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAgICAgICAnR2V0IHN0YXRpc3RpY3MgYWJvdXQgYSBTdHJpbmcgQ2F0YWxvZyBpbmNsdWRpbmcgdG90YWwga2V5cywgc3VwcG9ydGVkIGxhbmd1YWdlcywgYW5kIHRyYW5zbGF0aW9uIGNvdmVyYWdlIHBlcmNlbnRhZ2UgZm9yIGVhY2ggbGFuZ3VhZ2UuJyxcbiAgICAgICAgICAgIGlucHV0U2NoZW1hOiB7XG4gICAgICAgICAgICAgICAgZmlsZVBhdGg6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ0Fic29sdXRlIHBhdGggdG8gdGhlIC54Y3N0cmluZ3MgZmlsZScpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgYXN5bmMgKHsgZmlsZVBhdGggfSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgY2F0YWxvZyA9IG5ldyBTdHJpbmdDYXRhbG9nKGZpbGVQYXRoKTtcbiAgICAgICAgICAgIGNvbnN0IHN0YXRzID0gY2F0YWxvZy5nZXRTdGF0aXN0aWNzKCk7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29udGVudDogW1xuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAndGV4dCcgYXMgY29uc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBKU09OLnN0cmluZ2lmeShzdGF0cywgbnVsbCwgMiksXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICApO1xufVxuIl19
|
|
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LXRyYW5zbGF0aW9ucy1mb3Ita2V5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21jcC90b29scy9nZXQtdHJhbnNsYXRpb25zLWZvci1rZXkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFJQSxzRUF3Q0M7QUEzQ0QsNkJBQXdCO0FBQ3hCLHlEQUFxRDtBQUVyRCxTQUFnQiw2QkFBNkIsQ0FBQyxNQUFpQjtJQUMzRCxNQUFNLENBQUMsWUFBWSxDQUNmLDBCQUEwQixFQUMxQjtRQUNJLFdBQVcsRUFDUCxxSkFBcUo7UUFDekosV0FBVyxFQUFFO1lBQ1QsUUFBUSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsc0NBQXNDLENBQUM7WUFDckUsR0FBRyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsaUNBQWlDLENBQUM7U0FDOUQ7S0FDSixFQUNELEtBQUssRUFBRSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFO1FBQ3hCLE1BQU0sT0FBTyxHQUFHLElBQUksOEJBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1QyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMscUJBQXFCLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFbEQsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1YsT0FBTztnQkFDSCxPQUFPLEVBQUU7b0JBQ0w7d0JBQ0ksSUFBSSxFQUFFLE1BQWU7d0JBQ3JCLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUNoQixFQUFFLEtBQUssRUFBRSxRQUFRLEdBQUcsd0JBQXdCLEVBQUUsRUFDOUMsSUFBSSxFQUNKLENBQUMsQ0FDSjtxQkFDSjtpQkFDSjthQUNKLENBQUM7UUFDTixDQUFDO1FBRUQsT0FBTztZQUNILE9BQU8sRUFBRTtnQkFDTDtvQkFDSSxJQUFJLEVBQUUsTUFBZTtvQkFDckIsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7aUJBQ3hDO2FBQ0o7U0FDSixDQUFDO0lBQ04sQ0FBQyxDQUNKLENBQUM7QUFDTixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTWNwU2VydmVyIH0gZnJvbSAnQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay9zZXJ2ZXIvbWNwLmpzJztcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuaW1wb3J0IHsgU3RyaW5nQ2F0YWxvZyB9IGZyb20gJy4uLy4uL3N0cmluZy1jYXRhbG9nJztcblxuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lzdGVyR2V0VHJhbnNsYXRpb25zRm9yS2V5KHNlcnZlcjogTWNwU2VydmVyKSB7XG4gICAgc2VydmVyLnJlZ2lzdGVyVG9vbChcbiAgICAgICAgJ2dldF90cmFuc2xhdGlvbnNfZm9yX2tleScsXG4gICAgICAgIHtcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICAgICAgICdHZXQgYWxsIHRyYW5zbGF0aW9ucyBmb3IgYSBzcGVjaWZpYyBrZXkgaW4gYSBTdHJpbmcgQ2F0YWxvZy4gU2hvd3MgdGhlIHRyYW5zbGF0ZWQgdGV4dCBpbiBlYWNoIHN1cHBvcnRlZCBsYW5ndWFnZSBhbG9uZyB3aXRoIHRoZSB0cmFuc2xhdGlvbiBzdGF0ZS4nLFxuICAgICAgICAgICAgaW5wdXRTY2hlbWE6IHtcbiAgICAgICAgICAgICAgICBmaWxlUGF0aDogei5zdHJpbmcoKS5kZXNjcmliZSgnQWJzb2x1dGUgcGF0aCB0byB0aGUgLnhjc3RyaW5ncyBmaWxlJyksXG4gICAgICAgICAgICAgICAga2V5OiB6LnN0cmluZygpLmRlc2NyaWJlKCdUaGUgbG9jYWxpemF0aW9uIGtleSB0byBsb29rIHVwJyksXG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBhc3luYyAoeyBmaWxlUGF0aCwga2V5IH0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNhdGFsb2cgPSBuZXcgU3RyaW5nQ2F0YWxvZyhmaWxlUGF0aCk7XG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBjYXRhbG9nLmdldFRyYW5zbGF0aW9uc0ZvcktleShrZXkpO1xuXG4gICAgICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAndGV4dCcgYXMgY29uc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dDogSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgZXJyb3I6IGBLZXkgXCIke2tleX1cIiBub3QgZm91bmQgaW4gY2F0YWxvZ2AgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY29udGVudDogW1xuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAndGV4dCcgYXMgY29uc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBKU09OLnN0cmluZ2lmeShyZXN1bHQsIG51bGwsIDIpLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgKTtcbn1cbiJdfQ==
|
|
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbWNwL3Rvb2xzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBUUEsNENBT0M7QUFkRCx5RUFBNEU7QUFDNUUseUVBQTJFO0FBQzNFLCtDQUFtRDtBQUNuRCwrREFBbUU7QUFDbkUscUVBQXdFO0FBQ3hFLG1EQUFzRDtBQUV0RCxTQUFnQixnQkFBZ0IsQ0FBQyxNQUFpQjtJQUM5QyxJQUFBLHlEQUE4QixFQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZDLElBQUEsd0RBQTZCLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFDdEMsSUFBQSxnQ0FBa0IsRUFBQyxNQUFNLENBQUMsQ0FBQztJQUMzQixJQUFBLGdEQUEwQixFQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ25DLElBQUEscURBQTRCLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFDckMsSUFBQSxtQ0FBbUIsRUFBQyxNQUFNLENBQUMsQ0FBQztBQUNoQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTWNwU2VydmVyIH0gZnJvbSAnQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay9zZXJ2ZXIvbWNwLmpzJztcbmltcG9ydCB7IHJlZ2lzdGVyTGlzdFN1cHBvcnRlZExhbmd1YWdlcyB9IGZyb20gJy4vbGlzdC1zdXBwb3J0ZWQtbGFuZ3VhZ2VzJztcbmltcG9ydCB7IHJlZ2lzdGVyR2V0VHJhbnNsYXRpb25zRm9yS2V5IH0gZnJvbSAnLi9nZXQtdHJhbnNsYXRpb25zLWZvci1rZXknO1xuaW1wb3J0IHsgcmVnaXN0ZXJTZWFyY2hLZXlzIH0gZnJvbSAnLi9zZWFyY2gta2V5cyc7XG5pbXBvcnQgeyByZWdpc3RlclVwZGF0ZVRyYW5zbGF0aW9ucyB9IGZyb20gJy4vdXBkYXRlLXRyYW5zbGF0aW9ucyc7XG5pbXBvcnQgeyByZWdpc3RlckdldENhdGFsb2dTdGF0aXN0aWNzIH0gZnJvbSAnLi9nZXQtY2F0YWxvZy1zdGF0aXN0aWNzJztcbmltcG9ydCB7IHJlZ2lzdGVyTGlzdEFsbEtleXMgfSBmcm9tICcuL2xpc3QtYWxsLWtleXMnO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJBbGxUb29scyhzZXJ2ZXI6IE1jcFNlcnZlcikge1xuICAgIHJlZ2lzdGVyTGlzdFN1cHBvcnRlZExhbmd1YWdlcyhzZXJ2ZXIpO1xuICAgIHJlZ2lzdGVyR2V0VHJhbnNsYXRpb25zRm9yS2V5KHNlcnZlcik7XG4gICAgcmVnaXN0ZXJTZWFyY2hLZXlzKHNlcnZlcik7XG4gICAgcmVnaXN0ZXJVcGRhdGVUcmFuc2xhdGlvbnMoc2VydmVyKTtcbiAgICByZWdpc3RlckdldENhdGFsb2dTdGF0aXN0aWNzKHNlcnZlcik7XG4gICAgcmVnaXN0ZXJMaXN0QWxsS2V5cyhzZXJ2ZXIpO1xufVxuIl19
|
|
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdC1hbGwta2V5cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tY3AvdG9vbHMvbGlzdC1hbGwta2V5cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUlBLGtEQStDQztBQWxERCw2QkFBd0I7QUFDeEIseURBQXFEO0FBRXJELFNBQWdCLG1CQUFtQixDQUFDLE1BQWlCO0lBQ2pELE1BQU0sQ0FBQyxZQUFZLENBQ2YsZUFBZSxFQUNmO1FBQ0ksV0FBVyxFQUNQLHFGQUFxRjtRQUN6RixXQUFXLEVBQUU7WUFDVCxRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxzQ0FBc0MsQ0FBQztZQUNyRSxLQUFLLEVBQUUsT0FBQztpQkFDSCxNQUFNLEVBQUU7aUJBQ1IsUUFBUSxFQUFFO2lCQUNWLE9BQU8sQ0FBQyxHQUFHLENBQUM7aUJBQ1osUUFBUSxDQUFDLGlEQUFpRCxDQUFDO1lBQ2hFLE1BQU0sRUFBRSxPQUFDO2lCQUNKLE1BQU0sRUFBRTtpQkFDUixRQUFRLEVBQUU7aUJBQ1YsT0FBTyxDQUFDLENBQUMsQ0FBQztpQkFDVixRQUFRLENBQUMscURBQXFELENBQUM7U0FDdkU7S0FDSixFQUNELEtBQUssRUFBRSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO1FBQ3ZELE1BQU0sS0FBSyxHQUFHLFFBQVEsSUFBSSxHQUFHLENBQUM7UUFDOUIsTUFBTSxNQUFNLEdBQUcsU0FBUyxJQUFJLENBQUMsQ0FBQztRQUM5QixNQUFNLE9BQU8sR0FBRyxJQUFJLDhCQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDNUMsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ3JDLE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQztRQUU1RCxPQUFPO1lBQ0gsT0FBTyxFQUFFO2dCQUNMO29CQUNJLElBQUksRUFBRSxNQUFlO29CQUNyQixJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FDaEI7d0JBQ0ksSUFBSSxFQUFFLGFBQWE7d0JBQ25CLEtBQUssRUFBRSxPQUFPLENBQUMsTUFBTTt3QkFDckIsTUFBTTt3QkFDTixLQUFLO3dCQUNMLE9BQU8sRUFBRSxNQUFNLEdBQUcsS0FBSyxHQUFHLE9BQU8sQ0FBQyxNQUFNO3FCQUMzQyxFQUNELElBQUksRUFDSixDQUFDLENBQ0o7aUJBQ0o7YUFDSjtTQUNKLENBQUM7SUFDTixDQUFDLENBQ0osQ0FBQztBQUNOLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNY3BTZXJ2ZXIgfSBmcm9tICdAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9tY3AuanMnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5pbXBvcnQgeyBTdHJpbmdDYXRhbG9nIH0gZnJvbSAnLi4vLi4vc3RyaW5nLWNhdGFsb2cnO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJMaXN0QWxsS2V5cyhzZXJ2ZXI6IE1jcFNlcnZlcikge1xuICAgIHNlcnZlci5yZWdpc3RlclRvb2woXG4gICAgICAgICdsaXN0X2FsbF9rZXlzJyxcbiAgICAgICAge1xuICAgICAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgICAgICAgJ0xpc3QgYWxsIGxvY2FsaXphdGlvbiBrZXlzIGluIGEgU3RyaW5nIENhdGFsb2cuIFJldHVybnMga2V5cyBzb3J0ZWQgYWxwaGFiZXRpY2FsbHkuJyxcbiAgICAgICAgICAgIGlucHV0U2NoZW1hOiB7XG4gICAgICAgICAgICAgICAgZmlsZVBhdGg6IHouc3RyaW5nKCkuZGVzY3JpYmUoJ0Fic29sdXRlIHBhdGggdG8gdGhlIC54Y3N0cmluZ3MgZmlsZScpLFxuICAgICAgICAgICAgICAgIGxpbWl0OiB6XG4gICAgICAgICAgICAgICAgICAgIC5udW1iZXIoKVxuICAgICAgICAgICAgICAgICAgICAub3B0aW9uYWwoKVxuICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCgxMDApXG4gICAgICAgICAgICAgICAgICAgIC5kZXNjcmliZSgnTWF4aW11bSBudW1iZXIgb2Yga2V5cyB0byByZXR1cm4gKGRlZmF1bHQ6IDEwMCknKSxcbiAgICAgICAgICAgICAgICBvZmZzZXQ6IHpcbiAgICAgICAgICAgICAgICAgICAgLm51bWJlcigpXG4gICAgICAgICAgICAgICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0KDApXG4gICAgICAgICAgICAgICAgICAgIC5kZXNjcmliZSgnTnVtYmVyIG9mIGtleXMgdG8gc2tpcCAoZm9yIHBhZ2luYXRpb24sIGRlZmF1bHQ6IDApJyksXG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBhc3luYyAoeyBmaWxlUGF0aCwgbGltaXQ6IGxpbWl0QXJnLCBvZmZzZXQ6IG9mZnNldEFyZyB9KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBsaW1pdCA9IGxpbWl0QXJnID8/IDEwMDtcbiAgICAgICAgICAgIGNvbnN0IG9mZnNldCA9IG9mZnNldEFyZyA/PyAwO1xuICAgICAgICAgICAgY29uc3QgY2F0YWxvZyA9IG5ldyBTdHJpbmdDYXRhbG9nKGZpbGVQYXRoKTtcbiAgICAgICAgICAgIGNvbnN0IGFsbEtleXMgPSBjYXRhbG9nLmdldEFsbEtleXMoKTtcbiAgICAgICAgICAgIGNvbnN0IHBhZ2luYXRlZEtleXMgPSBhbGxLZXlzLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgbGltaXQpO1xuXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ3RleHQnIGFzIGNvbnN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgdGV4dDogSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXlzOiBwYWdpbmF0ZWRLZXlzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbDogYWxsS2V5cy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mZnNldCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhc01vcmU6IG9mZnNldCArIGxpbWl0IDwgYWxsS2V5cy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDJcbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICApO1xufVxuIl19
|