@lmcc-dev/mult-fetch-mcp-server 1.1.0 → 1.2.1

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 (216) hide show
  1. package/README.md +8 -8
  2. package/README.zh.md +16 -8
  3. package/dist/i18n-test-report.json +8 -0
  4. package/dist/i18n-unused-keys-report.json +8 -0
  5. package/dist/src/client.js +70 -37
  6. package/dist/src/index.js +0 -0
  7. package/dist/src/lib/BrowserFetcher.js +12 -12
  8. package/dist/src/lib/NodeFetcher.js +22 -22
  9. package/dist/src/lib/fetch.js +40 -0
  10. package/dist/src/lib/fetchers/FetcherFactory.js +43 -0
  11. package/dist/src/lib/fetchers/browser/BrowserFetcher.js +381 -0
  12. package/dist/src/lib/fetchers/browser/BrowserInstance.js +180 -0
  13. package/dist/src/lib/fetchers/browser/PageOperations.js +168 -0
  14. package/dist/src/lib/fetchers/common/types.js +41 -0
  15. package/dist/src/lib/fetchers/common/utils.js +141 -0
  16. package/dist/src/lib/fetchers/index.js +62 -0
  17. package/dist/src/lib/fetchers/node/HttpClient.js +239 -0
  18. package/dist/src/lib/fetchers/node/NodeFetcher.js +180 -0
  19. package/dist/src/lib/i18n/index.js +105 -17
  20. package/dist/src/lib/i18n/keys/base.js +41 -0
  21. package/dist/src/lib/i18n/keys/browser.js +91 -0
  22. package/dist/src/lib/i18n/keys/client.js +68 -0
  23. package/dist/src/lib/i18n/keys/errors.js +49 -0
  24. package/dist/src/lib/i18n/keys/factory.js +46 -0
  25. package/dist/src/lib/i18n/keys/fetcher.js +87 -0
  26. package/dist/src/lib/i18n/keys/index.js +16 -0
  27. package/dist/src/lib/i18n/keys/node.js +69 -0
  28. package/dist/src/lib/i18n/keys/prompts.js +79 -0
  29. package/dist/src/lib/i18n/keys/resources.js +53 -0
  30. package/dist/src/lib/i18n/keys/server.js +67 -0
  31. package/dist/src/lib/i18n/keys/tools.js +39 -0
  32. package/dist/src/lib/i18n/keys.js +488 -119
  33. package/dist/src/lib/i18n/locales/en/browser.js +67 -57
  34. package/dist/src/lib/i18n/locales/en/client.js +57 -33
  35. package/dist/src/lib/i18n/locales/en/errors.js +36 -12
  36. package/dist/src/lib/i18n/locales/en/factory.js +38 -0
  37. package/dist/src/lib/i18n/locales/en/fetcher.js +8 -2
  38. package/dist/src/lib/i18n/locales/en/index.js +10 -8
  39. package/dist/src/lib/i18n/locales/en/node.js +57 -35
  40. package/dist/src/lib/i18n/locales/en/prompts.js +42 -65
  41. package/dist/src/lib/i18n/locales/en/resources.js +52 -55
  42. package/dist/src/lib/i18n/locales/en/server.js +49 -24
  43. package/dist/src/lib/i18n/locales/en/tools.js +27 -19
  44. package/dist/src/lib/i18n/locales/zh/browser.js +71 -62
  45. package/dist/src/lib/i18n/locales/zh/client.js +57 -32
  46. package/dist/src/lib/i18n/locales/zh/errors.js +36 -12
  47. package/dist/src/lib/i18n/locales/zh/factory.js +38 -0
  48. package/dist/src/lib/i18n/locales/zh/fetcher.js +36 -30
  49. package/dist/src/lib/i18n/locales/zh/index.js +10 -8
  50. package/dist/src/lib/i18n/locales/zh/node.js +61 -36
  51. package/dist/src/lib/i18n/locales/zh/prompts.js +35 -57
  52. package/dist/src/lib/i18n/locales/zh/resources.js +52 -55
  53. package/dist/src/lib/i18n/locales/zh/server.js +51 -25
  54. package/dist/src/lib/i18n/locales/zh/tools.js +27 -19
  55. package/dist/src/lib/i18n/logger.js +90 -19
  56. package/dist/src/lib/logger.js +135 -14
  57. package/dist/src/lib/server/browser.js +42 -10
  58. package/dist/src/lib/server/fetcher.js +87 -37
  59. package/dist/src/lib/server/index.js +2 -2
  60. package/dist/src/lib/server/prompts.js +1 -1
  61. package/dist/src/lib/server/resources.js +1 -1
  62. package/dist/src/lib/server/tools.js +46 -10
  63. package/dist/src/lib/utils/ErrorHandler.js +125 -0
  64. package/dist/src/mcp-server.js +0 -0
  65. package/dist/src/test-i18n.js +139 -0
  66. package/dist/tests/BrowserFetcher.test.js +0 -0
  67. package/dist/tests/NodeFetcher.test.js +0 -0
  68. package/dist/tests/client.test.js +42 -81
  69. package/dist/tests/fetch.test.js +70 -0
  70. package/dist/tests/fetchers/Fetcher.test.js +108 -0
  71. package/dist/tests/fetchers/browser/BrowserFetcher.test.js +195 -0
  72. package/dist/tests/fetchers/browser/BrowserInstance.test.js +163 -0
  73. package/dist/tests/fetchers/node/NodeFetcher.test.js +211 -0
  74. package/dist/tests/i18n-missing-keys.js +364 -0
  75. package/dist/tests/i18n-remove-unused-keys.js +236 -0
  76. package/dist/tests/i18n-test-report.json +2004 -0
  77. package/dist/tests/i18n-unused-keys.js +425 -0
  78. package/dist/tests/i18n.test.js +6 -7
  79. package/dist/tests/logger.test.js +14 -13
  80. package/dist/tests/mcp-server.test.js +7 -7
  81. package/dist/tests/server/browser.test.js +25 -21
  82. package/dist/tests/server/fetcher.test.js +58 -101
  83. package/dist/tests/server/index.test.js +30 -30
  84. package/dist/tests/server/prompts.test.js +36 -33
  85. package/dist/tests/server/resources.test.js +120 -84
  86. package/dist/tests/server/tools.test.js +7 -6
  87. package/dist/tests/setup.js +36 -0
  88. package/dist/tests/src/lib/i18n/index.js +108 -0
  89. package/dist/tests/src/lib/i18n/keys/base.js +47 -0
  90. package/dist/tests/src/lib/i18n/keys/browser.js +93 -0
  91. package/dist/tests/src/lib/i18n/keys/client.js +70 -0
  92. package/dist/tests/src/lib/i18n/keys/errors.js +34 -0
  93. package/dist/tests/src/lib/i18n/keys/fetcher.js +84 -0
  94. package/dist/tests/src/lib/i18n/keys/index.js +31 -0
  95. package/dist/tests/src/lib/i18n/keys/node.js +56 -0
  96. package/dist/tests/src/lib/i18n/keys/prompts.js +82 -0
  97. package/dist/tests/src/lib/i18n/keys/resources.js +50 -0
  98. package/dist/tests/src/lib/i18n/keys/server.js +64 -0
  99. package/dist/tests/src/lib/i18n/keys/tools.js +34 -0
  100. package/dist/tests/src/lib/i18n/locales/en/browser.js +88 -0
  101. package/dist/tests/src/lib/i18n/locales/en/client.js +66 -0
  102. package/dist/tests/src/lib/i18n/locales/en/errors.js +28 -0
  103. package/dist/tests/src/lib/i18n/locales/en/fetcher.js +71 -0
  104. package/dist/tests/src/lib/i18n/locales/en/index.js +29 -0
  105. package/dist/tests/src/lib/i18n/locales/en/node.js +51 -0
  106. package/dist/tests/src/lib/i18n/locales/en/prompts.js +52 -0
  107. package/dist/tests/src/lib/i18n/locales/en/resources.js +50 -0
  108. package/dist/tests/src/lib/i18n/locales/en/server.js +56 -0
  109. package/dist/tests/src/lib/i18n/locales/en/tools.js +28 -0
  110. package/dist/tests/src/lib/i18n/locales/zh/browser.js +87 -0
  111. package/dist/tests/src/lib/i18n/locales/zh/client.js +66 -0
  112. package/dist/tests/src/lib/i18n/locales/zh/errors.js +28 -0
  113. package/dist/tests/src/lib/i18n/locales/zh/fetcher.js +71 -0
  114. package/dist/tests/src/lib/i18n/locales/zh/index.js +29 -0
  115. package/dist/tests/src/lib/i18n/locales/zh/node.js +51 -0
  116. package/dist/tests/src/lib/i18n/locales/zh/prompts.js +53 -0
  117. package/dist/tests/src/lib/i18n/locales/zh/resources.js +50 -0
  118. package/dist/tests/src/lib/i18n/locales/zh/server.js +57 -0
  119. package/dist/tests/src/lib/i18n/locales/zh/tools.js +28 -0
  120. package/dist/tests/src/lib/i18n/logger.js +114 -0
  121. package/dist/tests/src/lib/logger.js +181 -0
  122. package/dist/tests/test-direct-client.js +0 -0
  123. package/dist/tests/test-i18n.js +530 -0
  124. package/dist/tests/test-mcp-methods.js +1 -1
  125. package/dist/tests/test-mcp.js +0 -0
  126. package/dist/tests/test-mini4k.js +0 -0
  127. package/dist/tests/tests/test-i18n.js +588 -0
  128. package/dist/tests/types.test.js +1 -1
  129. package/dist/tests/utils/ErrorHandler.test.js +144 -0
  130. package/dist/vitest.config.js +29 -0
  131. package/package.json +31 -27
  132. package/dist/src/cli-language.js +0 -78
  133. package/dist/src/client.d.ts +0 -6
  134. package/dist/src/client.js.map +0 -1
  135. package/dist/src/index.d.ts +0 -15
  136. package/dist/src/index.js.map +0 -1
  137. package/dist/src/lib/BrowserFetcher.d.ts +0 -175
  138. package/dist/src/lib/BrowserFetcher.js.map +0 -1
  139. package/dist/src/lib/NodeFetcher.d.ts +0 -92
  140. package/dist/src/lib/NodeFetcher.js.map +0 -1
  141. package/dist/src/lib/example.js +0 -93
  142. package/dist/src/lib/i18n/index.js.map +0 -1
  143. package/dist/src/lib/i18n/locales/en/browser.d.ts +0 -61
  144. package/dist/src/lib/i18n/locales/en/browser.js.map +0 -1
  145. package/dist/src/lib/i18n/locales/en/client.d.ts +0 -39
  146. package/dist/src/lib/i18n/locales/en/client.js.map +0 -1
  147. package/dist/src/lib/i18n/locales/en/errors.d.ts +0 -17
  148. package/dist/src/lib/i18n/locales/en/errors.js.map +0 -1
  149. package/dist/src/lib/i18n/locales/en/fetcher.d.ts +0 -66
  150. package/dist/src/lib/i18n/locales/en/fetcher.js.map +0 -1
  151. package/dist/src/lib/i18n/locales/en/index.d.ts +0 -344
  152. package/dist/src/lib/i18n/locales/en/index.js.map +0 -1
  153. package/dist/src/lib/i18n/locales/en/node.d.ts +0 -41
  154. package/dist/src/lib/i18n/locales/en/node.js.map +0 -1
  155. package/dist/src/lib/i18n/locales/en/prompts.d.ts +0 -65
  156. package/dist/src/lib/i18n/locales/en/prompts.js.map +0 -1
  157. package/dist/src/lib/i18n/locales/en/resources.d.ts +0 -41
  158. package/dist/src/lib/i18n/locales/en/resources.js.map +0 -1
  159. package/dist/src/lib/i18n/locales/en/server.d.ts +0 -30
  160. package/dist/src/lib/i18n/locales/en/server.js.map +0 -1
  161. package/dist/src/lib/i18n/locales/en/tools.d.ts +0 -24
  162. package/dist/src/lib/i18n/locales/en/tools.js.map +0 -1
  163. package/dist/src/lib/i18n/locales/zh/browser.d.ts +0 -61
  164. package/dist/src/lib/i18n/locales/zh/browser.js.map +0 -1
  165. package/dist/src/lib/i18n/locales/zh/client.d.ts +0 -38
  166. package/dist/src/lib/i18n/locales/zh/client.js.map +0 -1
  167. package/dist/src/lib/i18n/locales/zh/errors.d.ts +0 -17
  168. package/dist/src/lib/i18n/locales/zh/errors.js.map +0 -1
  169. package/dist/src/lib/i18n/locales/zh/fetcher.d.ts +0 -66
  170. package/dist/src/lib/i18n/locales/zh/fetcher.js.map +0 -1
  171. package/dist/src/lib/i18n/locales/zh/index.d.ts +0 -343
  172. package/dist/src/lib/i18n/locales/zh/index.js.map +0 -1
  173. package/dist/src/lib/i18n/locales/zh/node.d.ts +0 -41
  174. package/dist/src/lib/i18n/locales/zh/node.js.map +0 -1
  175. package/dist/src/lib/i18n/locales/zh/prompts.d.ts +0 -65
  176. package/dist/src/lib/i18n/locales/zh/prompts.js.map +0 -1
  177. package/dist/src/lib/i18n/locales/zh/resources.d.ts +0 -41
  178. package/dist/src/lib/i18n/locales/zh/resources.js.map +0 -1
  179. package/dist/src/lib/i18n/locales/zh/server.d.ts +0 -30
  180. package/dist/src/lib/i18n/locales/zh/server.js.map +0 -1
  181. package/dist/src/lib/i18n/locales/zh/tools.d.ts +0 -24
  182. package/dist/src/lib/i18n/locales/zh/tools.js.map +0 -1
  183. package/dist/src/lib/i18n/logger.d.ts +0 -38
  184. package/dist/src/lib/i18n/logger.js.map +0 -1
  185. package/dist/src/lib/logger.d.ts +0 -32
  186. package/dist/src/lib/logger.js.map +0 -1
  187. package/dist/src/lib/server/browser.d.ts +0 -34
  188. package/dist/src/lib/server/browser.js.map +0 -1
  189. package/dist/src/lib/server/fetcher.d.ts +0 -20
  190. package/dist/src/lib/server/fetcher.js.map +0 -1
  191. package/dist/src/lib/server/index.d.ts +0 -10
  192. package/dist/src/lib/server/index.js.map +0 -1
  193. package/dist/src/lib/server/logger.js +0 -23
  194. package/dist/src/lib/server/prompts.d.ts +0 -11
  195. package/dist/src/lib/server/prompts.js.map +0 -1
  196. package/dist/src/lib/server/resources.d.ts +0 -11
  197. package/dist/src/lib/server/resources.js.map +0 -1
  198. package/dist/src/lib/server/tools.d.ts +0 -12
  199. package/dist/src/lib/server/tools.js.map +0 -1
  200. package/dist/src/lib/server/types.d.ts +0 -71
  201. package/dist/src/lib/server/types.js.map +0 -1
  202. package/dist/src/lib/types.d.ts +0 -119
  203. package/dist/src/lib/types.js.map +0 -1
  204. package/dist/src/mcp-server.d.ts +0 -6
  205. package/dist/src/mcp-server.js.map +0 -1
  206. package/dist/tests/jest.setup.d.ts +0 -6
  207. package/dist/tests/jest.setup.js +0 -30
  208. package/dist/tests/jest.setup.js.map +0 -1
  209. package/dist/tests/test-direct-client.d.ts +0 -6
  210. package/dist/tests/test-direct-client.js.map +0 -1
  211. package/dist/tests/test-mcp-methods.d.ts +0 -6
  212. package/dist/tests/test-mcp-methods.js.map +0 -1
  213. package/dist/tests/test-mcp.d.ts +0 -6
  214. package/dist/tests/test-mcp.js.map +0 -1
  215. package/dist/tests/test-mini4k.d.ts +0 -6
  216. package/dist/tests/test-mini4k.js.map +0 -1
@@ -0,0 +1,530 @@
1
+ /**
2
+ * Author: Martin <lmccc.dev@gmail.com>
3
+ * Co-Author: AI Assistant (Claude)
4
+ * Description: This code was collaboratively developed by Martin and AI Assistant.
5
+ */
6
+ // 测试国际化功能 (Test internationalization functionality)
7
+ import { log, COMPONENTS, clearTranslationCache } from '../src/lib/logger.js';
8
+ import { t, changeLanguage, getCurrentLanguage } from '../src/lib/i18n/index.js';
9
+ import { enTranslation } from '../src/lib/i18n/locales/en/index.js';
10
+ import { zhTranslation } from '../src/lib/i18n/locales/zh/index.js';
11
+ import * as fs from 'fs';
12
+ import * as path from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ // 获取当前文件的目录路径 (Get the directory path of the current file)
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+ // 导入所有键模块 (Import all key modules)
18
+ import * as allKeys from '../src/lib/i18n/keys/index.js';
19
+ // 默认测试配置 (Default test configuration)
20
+ const defaultConfig = {
21
+ generateReport: true,
22
+ reportPath: path.join(__dirname, '../i18n-test-report.json'),
23
+ checkEmptyValues: true,
24
+ checkPlaceholders: true,
25
+ verbose: false,
26
+ testCache: false,
27
+ testSampleKeys: false
28
+ };
29
+ // 解析命令行参数 (Parse command line arguments)
30
+ function parseCommandLineArgs() {
31
+ const config = { ...defaultConfig };
32
+ const args = process.argv.slice(2);
33
+ for (let i = 0; i < args.length; i++) {
34
+ const arg = args[i];
35
+ switch (arg) {
36
+ case '--no-report':
37
+ config.generateReport = false;
38
+ break;
39
+ case '--report-path':
40
+ if (i + 1 < args.length) {
41
+ config.reportPath = args[++i];
42
+ }
43
+ break;
44
+ case '--no-check-empty':
45
+ config.checkEmptyValues = false;
46
+ break;
47
+ case '--no-check-placeholders':
48
+ config.checkPlaceholders = false;
49
+ break;
50
+ case '--verbose':
51
+ config.verbose = true;
52
+ break;
53
+ case '--test-cache':
54
+ config.testCache = true;
55
+ break;
56
+ case '--test-sample-keys':
57
+ config.testSampleKeys = true;
58
+ break;
59
+ case '--help':
60
+ printHelp();
61
+ process.exit(0);
62
+ break;
63
+ }
64
+ }
65
+ return config;
66
+ }
67
+ // 打印帮助信息 (Print help information)
68
+ function printHelp() {
69
+ console.log(`
70
+ 国际化测试工具 (Internationalization Test Tool)
71
+
72
+ 用法: node --loader ts-node/esm tests/test-i18n.ts [选项]
73
+
74
+ 选项:
75
+ --no-report 不生成报告文件 (Don't generate report file)
76
+ --report-path <path> 指定报告文件路径 (Specify report file path)
77
+ --no-check-empty 不检查空值 (Don't check empty values)
78
+ --no-check-placeholders 不检查占位符 (Don't check placeholders)
79
+ --verbose 显示详细信息 (Show verbose information)
80
+ --test-cache 测试翻译缓存 (Test translation cache)
81
+ --test-sample-keys 测试样例键 (Test sample keys)
82
+ --help 显示帮助信息 (Show help information)
83
+ `);
84
+ }
85
+ /**
86
+ * 递归获取对象中的所有键 (Recursively get all keys in an object)
87
+ * @param obj 要获取键的对象 (Object to get keys from)
88
+ * @param prefix 键前缀 (Key prefix)
89
+ * @returns 键数组 (Array of keys)
90
+ */
91
+ function getAllKeysFromObject(obj, prefix = '') {
92
+ let keys = [];
93
+ for (const key in obj) {
94
+ if (typeof obj[key] === 'object' && obj[key] !== null) {
95
+ // 递归获取嵌套对象的键 (Recursively get keys of nested objects)
96
+ keys = [...keys, ...getAllKeysFromObject(obj[key], prefix ? `${prefix}.${key}` : key)];
97
+ }
98
+ else if (typeof obj[key] === 'string') {
99
+ // 直接使用键值作为完整的键路径 (Use key value as the complete key path)
100
+ keys.push(obj[key]);
101
+ }
102
+ }
103
+ return keys;
104
+ }
105
+ /**
106
+ * 从键模块中获取所有键 (Get all keys from key modules)
107
+ * @returns 键数组 (Array of keys)
108
+ */
109
+ function getAllKeysFromModules() {
110
+ const allKeysSet = new Set();
111
+ // 遍历所有键模块 (Iterate through all key modules)
112
+ for (const moduleKey in allKeys) {
113
+ const keyModule = allKeys[moduleKey];
114
+ if (typeof keyModule === 'object' && keyModule !== null) {
115
+ // 获取模块中的所有键 (Get all keys in the module)
116
+ const keysInModule = getAllKeysFromObject(keyModule);
117
+ keysInModule.forEach(key => allKeysSet.add(key));
118
+ }
119
+ }
120
+ return Array.from(allKeysSet);
121
+ }
122
+ /**
123
+ * 获取翻译值 (Get translation value)
124
+ * @param key 键 (Key)
125
+ * @param translations 翻译资源 (Translation resources)
126
+ * @returns 翻译值 (Translation value)
127
+ */
128
+ function getTranslationValue(key, translations) {
129
+ // 检查是否是命名空间格式的键 (Check if the key is in namespace format)
130
+ const parts = key.split('.');
131
+ if (parts.length > 1) {
132
+ const namespace = parts[0];
133
+ const subKey = parts.slice(1).join('.');
134
+ // 检查命名空间是否存在 (Check if the namespace exists)
135
+ if (translations[namespace] && translations[namespace][subKey] !== undefined) {
136
+ return translations[namespace][subKey];
137
+ }
138
+ }
139
+ // 直接在翻译资源中查找键 (Look up the key directly in translation resources)
140
+ for (const moduleName in translations) {
141
+ const module = translations[moduleName];
142
+ if (module && module[key] !== undefined) {
143
+ return module[key];
144
+ }
145
+ }
146
+ return undefined;
147
+ }
148
+ /**
149
+ * 检查键是否存在于翻译资源中 (Check if a key exists in translation resources)
150
+ * @param key 要检查的键 (Key to check)
151
+ * @param translations 翻译资源 (Translation resources)
152
+ * @returns 键是否存在 (Whether the key exists)
153
+ */
154
+ function keyExistsInTranslations(key, translations) {
155
+ return getTranslationValue(key, translations) !== undefined;
156
+ }
157
+ /**
158
+ * 检查翻译值是否为空 (Check if a translation value is empty)
159
+ * @param key 键 (Key)
160
+ * @param translations 翻译资源 (Translation resources)
161
+ * @returns 翻译值是否为空 (Whether the translation value is empty)
162
+ */
163
+ function isTranslationEmpty(key, translations) {
164
+ const value = getTranslationValue(key, translations);
165
+ return value === '' || value === null || value === undefined;
166
+ }
167
+ /**
168
+ * 提取占位符 (Extract placeholders)
169
+ * @param text 文本 (Text)
170
+ * @returns 占位符数组 (Array of placeholders)
171
+ */
172
+ function extractPlaceholders(text) {
173
+ if (!text)
174
+ return [];
175
+ // 匹配 {{xxx}} 和 {xxx} 格式的占位符 (Match {{xxx}} and {xxx} format placeholders)
176
+ const placeholders = [];
177
+ const regex1 = /\{\{([^{}]+)\}\}/g;
178
+ const regex2 = /\{([^{}]+)\}/g;
179
+ let match;
180
+ while ((match = regex1.exec(text)) !== null) {
181
+ placeholders.push(match[1]);
182
+ }
183
+ while ((match = regex2.exec(text)) !== null) {
184
+ placeholders.push(match[1]);
185
+ }
186
+ return placeholders;
187
+ }
188
+ /**
189
+ * 检查占位符是否匹配 (Check if placeholders match)
190
+ * @param key 键 (Key)
191
+ * @param enValue 英文值 (English value)
192
+ * @param zhValue 中文值 (Chinese value)
193
+ * @returns 占位符是否匹配 (Whether placeholders match)
194
+ */
195
+ function checkPlaceholdersMatch(key, enValue, zhValue) {
196
+ const enPlaceholders = extractPlaceholders(enValue);
197
+ const zhPlaceholders = extractPlaceholders(zhValue);
198
+ // 检查占位符数量是否相同 (Check if the number of placeholders is the same)
199
+ if (enPlaceholders.length !== zhPlaceholders.length) {
200
+ return false;
201
+ }
202
+ // 检查占位符名称是否相同 (Check if placeholder names are the same)
203
+ const enSet = new Set(enPlaceholders);
204
+ for (const placeholder of zhPlaceholders) {
205
+ if (!enSet.has(placeholder)) {
206
+ return false;
207
+ }
208
+ }
209
+ return true;
210
+ }
211
+ /**
212
+ * 测试翻译键 (Test translation keys)
213
+ * @param keys 要测试的键数组 (Array of keys to test)
214
+ * @param language 语言 (Language)
215
+ */
216
+ function testKeys(keys, language) {
217
+ console.log(`\n=== 测试 ${language} 翻译 (Testing ${language} translation) ===`);
218
+ for (const key of keys) {
219
+ try {
220
+ const translated = t(key);
221
+ console.log(`Key: ${key}`);
222
+ console.log(`Translation: ${translated}`);
223
+ console.log('---');
224
+ }
225
+ catch (error) {
226
+ console.error(`Error translating key: ${key}`);
227
+ console.error(error);
228
+ console.log('---');
229
+ }
230
+ }
231
+ }
232
+ /**
233
+ * 测试日志函数 (Test log function)
234
+ * @param keys 要测试的键数组 (Array of keys to test)
235
+ * @param component 组件名称 (Component name)
236
+ */
237
+ function testLogFunction(keys, component) {
238
+ console.log(`\n=== 测试日志函数 (Testing log function) ===`);
239
+ for (const key of keys) {
240
+ try {
241
+ log(key, true, {}, component);
242
+ }
243
+ catch (error) {
244
+ console.error(`Error logging key: ${key}`);
245
+ console.error(error);
246
+ }
247
+ }
248
+ }
249
+ /**
250
+ * 测试带参数的翻译 (Test translation with parameters)
251
+ * @param keys 要测试的键数组 (Array of keys to test)
252
+ * @param params 参数对象 (Parameters object)
253
+ */
254
+ function testWithParams(keys, params) {
255
+ console.log(`\n=== 测试带参数的翻译 (Testing translation with parameters) ===`);
256
+ for (const key of keys) {
257
+ try {
258
+ const translated = t(key, params);
259
+ console.log(`Key: ${key}`);
260
+ console.log(`Params: ${JSON.stringify(params)}`);
261
+ console.log(`Translation: ${translated}`);
262
+ console.log('---');
263
+ }
264
+ catch (error) {
265
+ console.error(`Error translating key with params: ${key}`);
266
+ console.error(error);
267
+ console.log('---');
268
+ }
269
+ }
270
+ }
271
+ /**
272
+ * 测试翻译缓存 (Test translation cache)
273
+ * @param key 要测试的键 (Key to test)
274
+ * @param iterations 迭代次数 (Number of iterations)
275
+ */
276
+ function testTranslationCache(key, iterations) {
277
+ console.log(`\n=== 测试翻译缓存 (Testing translation cache) ===`);
278
+ console.log(`Key: ${key}`);
279
+ console.log(`Iterations: ${iterations}`);
280
+ try {
281
+ // 清除翻译缓存 (Clear translation cache)
282
+ clearTranslationCache();
283
+ // 测试不使用缓存的性能 (Test performance without cache)
284
+ console.log('Without cache:');
285
+ const startWithoutCache = Date.now();
286
+ for (let i = 0; i < iterations; i++) {
287
+ t(key);
288
+ }
289
+ const endWithoutCache = Date.now();
290
+ console.log(`Time: ${endWithoutCache - startWithoutCache}ms`);
291
+ // 测试使用缓存的性能 (Test performance with cache)
292
+ console.log('With cache:');
293
+ const startWithCache = Date.now();
294
+ for (let i = 0; i < iterations; i++) {
295
+ log(key, true, {}, COMPONENTS.SERVER);
296
+ }
297
+ const endWithCache = Date.now();
298
+ console.log(`Time: ${endWithCache - startWithCache}ms`);
299
+ }
300
+ catch (error) {
301
+ console.error('Error testing translation cache:');
302
+ console.error(error);
303
+ }
304
+ console.log('---');
305
+ }
306
+ /**
307
+ * 设置环境变量 (Set environment variable)
308
+ * @param name 环境变量名称 (Environment variable name)
309
+ * @param value 环境变量值 (Environment variable value)
310
+ */
311
+ function setEnv(name, value) {
312
+ process.env[name] = value;
313
+ console.log(`Set environment variable ${name}=${value}`);
314
+ }
315
+ /**
316
+ * 生成测试报告 (Generate test report)
317
+ * @param report 报告对象 (Report object)
318
+ * @param reportPath 报告文件路径 (Report file path)
319
+ */
320
+ function generateReport(report, reportPath) {
321
+ try {
322
+ const reportDir = path.dirname(reportPath);
323
+ if (!fs.existsSync(reportDir)) {
324
+ fs.mkdirSync(reportDir, { recursive: true });
325
+ }
326
+ fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf8');
327
+ console.log(`\n✅ 测试报告已生成: ${reportPath} (Test report generated: ${reportPath})`);
328
+ }
329
+ catch (error) {
330
+ console.error(`\n❌ 生成测试报告失败 (Failed to generate test report):`, error);
331
+ }
332
+ }
333
+ /**
334
+ * 检查所有键是否都有中英文对应 (Check if all keys have both English and Chinese translations)
335
+ * @param config 测试配置 (Test configuration)
336
+ */
337
+ function checkAllKeysHaveTranslations(config) {
338
+ console.log('\n=== 检查所有键是否都有中英文对应 (Check if all keys have both English and Chinese translations) ===');
339
+ try {
340
+ // 获取所有键 (Get all keys)
341
+ const allKeys = getAllKeysFromModules();
342
+ console.log(`总计找到 ${allKeys.length} 个键 (Total keys found: ${allKeys.length})`);
343
+ // 检查结果 (Check results)
344
+ const missingTranslations = [];
345
+ const emptyTranslations = [];
346
+ const placeholderMismatches = [];
347
+ // 检查每个键 (Check each key)
348
+ for (const key of allKeys) {
349
+ // 检查缺失的翻译 (Check missing translations)
350
+ const missingLanguages = [];
351
+ // 获取翻译值 (Get translation values)
352
+ const enValue = getTranslationValue(key, enTranslation);
353
+ const zhValue = getTranslationValue(key, zhTranslation);
354
+ // 检查英文翻译 (Check English translation)
355
+ if (enValue === undefined) {
356
+ missingLanguages.push('en');
357
+ }
358
+ // 检查中文翻译 (Check Chinese translation)
359
+ if (zhValue === undefined) {
360
+ missingLanguages.push('zh');
361
+ }
362
+ if (missingLanguages.length > 0) {
363
+ missingTranslations.push({ key, languages: missingLanguages });
364
+ }
365
+ // 如果两种语言的翻译都存在,进行进一步检查 (If translations for both languages exist, perform further checks)
366
+ if (enValue !== undefined && zhValue !== undefined) {
367
+ // 检查空值 (Check empty values)
368
+ if (config.checkEmptyValues) {
369
+ const emptyLanguages = [];
370
+ if (enValue === '') {
371
+ emptyLanguages.push('en');
372
+ }
373
+ if (zhValue === '') {
374
+ emptyLanguages.push('zh');
375
+ }
376
+ if (emptyLanguages.length > 0) {
377
+ emptyTranslations.push({ key, languages: emptyLanguages });
378
+ }
379
+ }
380
+ // 检查占位符 (Check placeholders)
381
+ if (config.checkPlaceholders && typeof enValue === 'string' && typeof zhValue === 'string') {
382
+ if (!checkPlaceholdersMatch(key, enValue, zhValue)) {
383
+ placeholderMismatches.push({ key, enValue, zhValue });
384
+ }
385
+ }
386
+ }
387
+ }
388
+ // 输出结果 (Output results)
389
+ let hasIssues = false;
390
+ // 输出缺失的翻译 (Output missing translations)
391
+ if (missingTranslations.length > 0) {
392
+ hasIssues = true;
393
+ console.log(`\n❌ 发现 ${missingTranslations.length} 个键缺少翻译 (Found ${missingTranslations.length} keys missing translations)`);
394
+ if (config.verbose) {
395
+ for (const { key, languages } of missingTranslations) {
396
+ console.log(`键 (Key): ${key}`);
397
+ console.log(`缺少翻译 (Missing translations for): ${languages.join(', ')}`);
398
+ console.log('---');
399
+ }
400
+ }
401
+ }
402
+ // 输出空值 (Output empty values)
403
+ if (config.checkEmptyValues && emptyTranslations.length > 0) {
404
+ hasIssues = true;
405
+ console.log(`\n❌ 发现 ${emptyTranslations.length} 个键的翻译为空 (Found ${emptyTranslations.length} keys with empty translations)`);
406
+ if (config.verbose) {
407
+ for (const { key, languages } of emptyTranslations) {
408
+ console.log(`键 (Key): ${key}`);
409
+ console.log(`空值语言 (Empty value languages): ${languages.join(', ')}`);
410
+ console.log('---');
411
+ }
412
+ }
413
+ }
414
+ // 输出占位符不匹配 (Output placeholder mismatches)
415
+ if (config.checkPlaceholders && placeholderMismatches.length > 0) {
416
+ hasIssues = true;
417
+ console.log(`\n❌ 发现 ${placeholderMismatches.length} 个键的占位符不匹配 (Found ${placeholderMismatches.length} keys with placeholder mismatches)`);
418
+ if (config.verbose) {
419
+ for (const { key, enValue, zhValue } of placeholderMismatches) {
420
+ console.log(`键 (Key): ${key}`);
421
+ console.log(`英文值 (English value): ${enValue}`);
422
+ console.log(`中文值 (Chinese value): ${zhValue}`);
423
+ console.log(`英文占位符 (English placeholders): ${extractPlaceholders(enValue).join(', ')}`);
424
+ console.log(`中文占位符 (Chinese placeholders): ${extractPlaceholders(zhValue).join(', ')}`);
425
+ console.log('---');
426
+ }
427
+ }
428
+ }
429
+ // 如果没有问题,输出成功信息 (If no issues, output success message)
430
+ if (!hasIssues) {
431
+ console.log('\n✅ 所有键都有正确的中英文对应 (All keys have correct English and Chinese translations)');
432
+ }
433
+ // 生成报告 (Generate report)
434
+ if (config.generateReport) {
435
+ const report = {
436
+ timestamp: new Date().toISOString(),
437
+ totalKeys: allKeys.length,
438
+ missingTranslations,
439
+ emptyTranslations: config.checkEmptyValues ? emptyTranslations : [],
440
+ placeholderMismatches: config.checkPlaceholders ? placeholderMismatches : [],
441
+ hasIssues
442
+ };
443
+ generateReport(report, config.reportPath);
444
+ }
445
+ return {
446
+ missingTranslations,
447
+ emptyTranslations,
448
+ placeholderMismatches,
449
+ hasIssues
450
+ };
451
+ }
452
+ catch (error) {
453
+ console.error('\n❌ 检查翻译时出错 (Error checking translations):');
454
+ console.error(error);
455
+ return {
456
+ missingTranslations: [],
457
+ emptyTranslations: [],
458
+ placeholderMismatches: [],
459
+ hasIssues: true
460
+ };
461
+ }
462
+ }
463
+ /**
464
+ * 主测试函数 (Main test function)
465
+ */
466
+ async function testI18n() {
467
+ console.log('=== 测试国际化功能 (Testing internationalization functionality) ===');
468
+ try {
469
+ // 解析命令行参数 (Parse command line arguments)
470
+ const config = parseCommandLineArgs();
471
+ // 检查所有键是否都有中英文对应 (Check if all keys have both English and Chinese translations)
472
+ const checkResult = checkAllKeysHaveTranslations(config);
473
+ // 如果不需要进行其他测试,直接返回 (If no other tests are needed, return directly)
474
+ if (!config.testSampleKeys && !config.testCache) {
475
+ return checkResult;
476
+ }
477
+ // 测试样例键 (Test sample keys)
478
+ if (config.testSampleKeys) {
479
+ // 测试简单的键 (Test simple keys)
480
+ const simpleKeys = [
481
+ 'server.starting',
482
+ 'server.started',
483
+ 'server.stopping',
484
+ 'server.stopped'
485
+ ];
486
+ // 确保 MCP_LANG 环境变量设置为英文 (Ensure MCP_LANG environment variable is set to English)
487
+ setEnv('MCP_LANG', 'en');
488
+ // 测试英文翻译 (Test English translation)
489
+ await changeLanguage('en');
490
+ console.log(`Current language: ${getCurrentLanguage()}`);
491
+ testKeys(simpleKeys, 'English');
492
+ // 测试日志函数 (Test log function)
493
+ testLogFunction(simpleKeys, COMPONENTS.SERVER);
494
+ // 测试带参数的翻译 (Test translation with parameters)
495
+ testWithParams(['server.listeningOn'], { port: 8080 });
496
+ // 确保 MCP_LANG 环境变量设置为中文 (Ensure MCP_LANG environment variable is set to Chinese)
497
+ setEnv('MCP_LANG', 'zh');
498
+ // 测试中文翻译 (Test Chinese translation)
499
+ await changeLanguage('zh');
500
+ console.log(`Current language: ${getCurrentLanguage()}`);
501
+ testKeys(simpleKeys, 'Chinese');
502
+ // 测试日志函数 (Test log function)
503
+ testLogFunction(simpleKeys, COMPONENTS.SERVER);
504
+ // 测试带参数的翻译 (Test translation with parameters)
505
+ testWithParams(['server.listeningOn'], { port: 8080 });
506
+ }
507
+ // 测试翻译缓存 (Test translation cache)
508
+ if (config.testCache) {
509
+ testTranslationCache('server.starting', 10);
510
+ }
511
+ // 返回检查结果 (Return check result)
512
+ return checkResult;
513
+ }
514
+ catch (error) {
515
+ console.error('测试过程中出错 (Error during testing):');
516
+ console.error(error);
517
+ return {
518
+ missingTranslations: [],
519
+ emptyTranslations: [],
520
+ placeholderMismatches: [],
521
+ hasIssues: true
522
+ };
523
+ }
524
+ }
525
+ // 运行测试 (Run test)
526
+ testI18n().catch(error => {
527
+ console.error('运行测试时出错 (Error running test):');
528
+ console.error(error);
529
+ process.exit(1);
530
+ });
@@ -83,7 +83,7 @@ async function testMcpMethods() {
83
83
  console.log('测试 prompts/get 方法...');
84
84
  try {
85
85
  const getPromptResult = await client.getPrompt({
86
- name: 'fetch-website',
86
+ name: 'mult-fetch-mcp:prompt:fetch-website',
87
87
  arguments: {
88
88
  url: 'https://example.com',
89
89
  format: 'html',
File without changes
File without changes