i18ntk 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 (86) hide show
  1. package/CHANGELOG.md +401 -0
  2. package/LICENSE +21 -0
  3. package/README.md +507 -0
  4. package/dev/README.md +37 -0
  5. package/dev/debug/README.md +30 -0
  6. package/dev/debug/complete-console-translations.js +295 -0
  7. package/dev/debug/console-key-checker.js +408 -0
  8. package/dev/debug/console-translations.js +335 -0
  9. package/dev/debug/debugger.js +408 -0
  10. package/dev/debug/export-missing-keys.js +432 -0
  11. package/dev/debug/final-normalize.js +236 -0
  12. package/dev/debug/find-extra-keys.js +68 -0
  13. package/dev/debug/normalize-locales.js +153 -0
  14. package/dev/debug/refactor-locales.js +240 -0
  15. package/dev/debug/reorder-locales.js +85 -0
  16. package/dev/debug/replace-hardcoded-console.js +378 -0
  17. package/docs/INSTALLATION.md +449 -0
  18. package/docs/README.md +222 -0
  19. package/docs/TODO_ROADMAP.md +279 -0
  20. package/docs/api/API_REFERENCE.md +377 -0
  21. package/docs/api/COMPONENTS.md +492 -0
  22. package/docs/api/CONFIGURATION.md +651 -0
  23. package/docs/api/NPM_PUBLISHING_GUIDE.md +434 -0
  24. package/docs/debug/DEBUG_README.md +30 -0
  25. package/docs/debug/DEBUG_TOOLS.md +494 -0
  26. package/docs/development/AGENTS.md +351 -0
  27. package/docs/development/DEVELOPMENT_RULES.md +165 -0
  28. package/docs/development/DEV_README.md +37 -0
  29. package/docs/release-notes/RELEASE_NOTES_v1.0.0.md +173 -0
  30. package/docs/release-notes/RELEASE_NOTES_v1.6.0.md +141 -0
  31. package/docs/release-notes/RELEASE_NOTES_v1.6.1.md +185 -0
  32. package/docs/release-notes/RELEASE_NOTES_v1.6.3.md +199 -0
  33. package/docs/reports/ANALYSIS_README.md +17 -0
  34. package/docs/reports/CONSOLE_MISMATCH_BUG_REPORT_v1.5.0.md +181 -0
  35. package/docs/reports/SIZING_README.md +18 -0
  36. package/docs/reports/SUMMARY_README.md +18 -0
  37. package/docs/reports/TRANSLATION_BUG_REPORT_v1.5.0.md +129 -0
  38. package/docs/reports/USAGE_README.md +18 -0
  39. package/docs/reports/VALIDATION_README.md +18 -0
  40. package/locales/de/auth.json +3 -0
  41. package/locales/de/common.json +16 -0
  42. package/locales/de/pagination.json +6 -0
  43. package/locales/en/auth.json +3 -0
  44. package/locales/en/common.json +16 -0
  45. package/locales/en/pagination.json +6 -0
  46. package/locales/es/auth.json +3 -0
  47. package/locales/es/common.json +16 -0
  48. package/locales/es/pagination.json +6 -0
  49. package/locales/fr/auth.json +3 -0
  50. package/locales/fr/common.json +16 -0
  51. package/locales/fr/pagination.json +6 -0
  52. package/locales/ru/auth.json +3 -0
  53. package/locales/ru/common.json +16 -0
  54. package/locales/ru/pagination.json +6 -0
  55. package/main/i18ntk-analyze.js +625 -0
  56. package/main/i18ntk-autorun.js +461 -0
  57. package/main/i18ntk-complete.js +494 -0
  58. package/main/i18ntk-init.js +686 -0
  59. package/main/i18ntk-manage.js +848 -0
  60. package/main/i18ntk-sizing.js +557 -0
  61. package/main/i18ntk-summary.js +671 -0
  62. package/main/i18ntk-usage.js +1282 -0
  63. package/main/i18ntk-validate.js +762 -0
  64. package/main/ui-i18n.js +332 -0
  65. package/package.json +152 -0
  66. package/scripts/fix-missing-translation-keys.js +214 -0
  67. package/scripts/verify-package.js +168 -0
  68. package/ui-locales/de.json +637 -0
  69. package/ui-locales/en.json +688 -0
  70. package/ui-locales/es.json +637 -0
  71. package/ui-locales/fr.json +637 -0
  72. package/ui-locales/ja.json +637 -0
  73. package/ui-locales/ru.json +637 -0
  74. package/ui-locales/zh.json +637 -0
  75. package/utils/admin-auth.js +317 -0
  76. package/utils/admin-cli.js +353 -0
  77. package/utils/admin-pin.js +409 -0
  78. package/utils/detect-language-mismatches.js +454 -0
  79. package/utils/i18n-helper.js +128 -0
  80. package/utils/maintain-language-purity.js +433 -0
  81. package/utils/native-translations.js +478 -0
  82. package/utils/security.js +384 -0
  83. package/utils/test-complete-system.js +356 -0
  84. package/utils/test-console-i18n.js +402 -0
  85. package/utils/translate-mismatches.js +571 -0
  86. package/utils/validate-language-purity.js +531 -0
@@ -0,0 +1,408 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * i18nTK Debugger
5
+ * Main debugging script for identifying and fixing issues in the i18n toolkit
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const { execSync } = require('child_process');
11
+ const SecurityUtils = require('../../utils/security');
12
+
13
+ class I18nDebugger {
14
+ constructor(projectRoot = null) {
15
+ // Validate and sanitize project root path
16
+ const defaultRoot = path.resolve(__dirname, '../..');
17
+ const validatedRoot = SecurityUtils.validatePath(projectRoot || defaultRoot, process.cwd());
18
+ if (!validatedRoot) {
19
+ throw new Error('Invalid project root path provided');
20
+ }
21
+
22
+ this.projectRoot = validatedRoot;
23
+ this.issues = [];
24
+ this.warnings = [];
25
+ this.logFile = path.join(__dirname, 'logs', `debug-${new Date().toISOString().replace(/[:.]/g, '-')}.log`);
26
+
27
+ // Ensure logs directory exists
28
+ const logsDir = path.dirname(this.logFile);
29
+ if (!fs.existsSync(logsDir)) {
30
+ fs.mkdirSync(logsDir, { recursive: true });
31
+ }
32
+ }
33
+
34
+ log(message, level = 'INFO') {
35
+ const timestamp = new Date().toISOString();
36
+ const logMessage = `[${timestamp}] [${level}] ${message}`;
37
+ console.log(logMessage);
38
+ fs.appendFileSync(this.logFile, logMessage + '\n');
39
+ }
40
+
41
+ addIssue(issue) {
42
+ this.issues.push(issue);
43
+ this.log(`ISSUE: ${issue}`, 'ERROR');
44
+ }
45
+
46
+ addWarning(warning) {
47
+ this.warnings.push(warning);
48
+ this.log(`WARNING: ${warning}`, 'WARN');
49
+ }
50
+
51
+ checkFileExists(filePath, description) {
52
+ try {
53
+ // Validate path before checking existence
54
+ const validatedPath = SecurityUtils.validatePath(filePath, this.projectRoot);
55
+ if (!validatedPath) {
56
+ this.addIssue(`Invalid file path: ${filePath}`);
57
+ return false;
58
+ }
59
+
60
+ const fullPath = path.resolve(this.projectRoot, filePath);
61
+ if (!fs.existsSync(fullPath)) {
62
+ this.addIssue(`Missing file: ${filePath} (${description})`);
63
+ return false;
64
+ }
65
+ this.log(`✓ Found: ${filePath}`);
66
+ return true;
67
+ } catch (error) {
68
+ this.addIssue(`Error checking file existence: ${filePath} - ${error.message}`);
69
+ SecurityUtils.logSecurityEvent('File existence check failed', 'warn', { filePath, error: error.message });
70
+ return false;
71
+ }
72
+ }
73
+
74
+ checkOldNamingConventions() {
75
+ this.log('Checking for old naming conventions...');
76
+ const oldFiles = [
77
+ '00-manage-i18n.js',
78
+ '01-init-i18n.js',
79
+ '02-analyze-translations.js',
80
+ '03-validate-translations.js',
81
+ '04-check-usage.js',
82
+ '05-complete-translations.js',
83
+ '06-analyze-sizing.js',
84
+ '07-generate-summary.js'
85
+ ];
86
+
87
+ oldFiles.forEach(file => {
88
+ const fullPath = path.resolve(this.projectRoot, file);
89
+ if (fs.existsSync(fullPath)) {
90
+ this.addIssue(`Old naming convention file still exists: ${file}`);
91
+ }
92
+ });
93
+
94
+ // Check for references to old files in code
95
+ this.checkForOldReferences();
96
+ }
97
+
98
+ async checkForOldReferences() {
99
+ this.log('Checking for old file references in code...');
100
+ const filesToCheck = [
101
+ 'i18ntk-complete.js',
102
+ 'i18ntk-usage.js',
103
+ 'i18ntk-validate.js',
104
+ 'package.json'
105
+ ];
106
+
107
+ const oldReferences = [
108
+ '04-check-usage.js',
109
+ '00-manage-i18n.js',
110
+ '01-init-i18n.js',
111
+ '02-analyze-translations.js',
112
+ '03-validate-translations.js',
113
+ '05-complete-translations.js',
114
+ '06-analyze-sizing.js',
115
+ '07-generate-summary.js'
116
+ ];
117
+
118
+ for (const file of filesToCheck) {
119
+ const fullPath = path.resolve(this.projectRoot, file);
120
+ if (fs.existsSync(fullPath)) {
121
+ try {
122
+ const content = await SecurityUtils.safeReadFile(fullPath, this.projectRoot);
123
+ if (content) {
124
+ oldReferences.forEach(oldRef => {
125
+ if (content.includes(oldRef)) {
126
+ this.addIssue(`Old reference '${oldRef}' found in ${file}`);
127
+ }
128
+ });
129
+ }
130
+ } catch (error) {
131
+ this.addIssue(`Error reading file ${fullPath}: ${error.message}`);
132
+ SecurityUtils.logSecurityEvent('File read failed during reference check', 'error', { filePath: fullPath, error: error.message });
133
+ }
134
+ }
135
+ }
136
+ }
137
+
138
+ async checkTranslationKeys() {
139
+ this.log('Checking for missing translation keys...');
140
+ const uiLocalesDir = path.resolve(this.projectRoot, 'ui-locales');
141
+
142
+ if (!fs.existsSync(uiLocalesDir)) {
143
+ this.addIssue('ui-locales directory not found');
144
+ return;
145
+ }
146
+
147
+ const localeFiles = fs.readdirSync(uiLocalesDir).filter(f => f.endsWith('.json'));
148
+ if (localeFiles.length === 0) {
149
+ this.addIssue('No locale files found in ui-locales directory');
150
+ return;
151
+ }
152
+
153
+ // Load English as reference
154
+ const enPath = path.join(uiLocalesDir, 'en.json');
155
+ if (!fs.existsSync(enPath)) {
156
+ this.addIssue('English locale file (en.json) not found');
157
+ return;
158
+ }
159
+
160
+ try {
161
+ const enContent = await SecurityUtils.safeReadFile(enPath, this.projectRoot);
162
+ if (!enContent) {
163
+ this.addIssue('Failed to read en.json file');
164
+ return;
165
+ }
166
+
167
+ const enLocale = SecurityUtils.safeParseJSON(enContent);
168
+ if (!enLocale) {
169
+ this.addIssue('Failed to parse en.json file');
170
+ return;
171
+ }
172
+
173
+ const requiredKeys = this.extractAllKeys(enLocale);
174
+
175
+ for (const file of localeFiles) {
176
+ const filePath = path.join(uiLocalesDir, file);
177
+ try {
178
+ const content = await SecurityUtils.safeReadFile(filePath, this.projectRoot);
179
+ if (!content) {
180
+ this.addIssue(`Failed to read ${file}`);
181
+ continue;
182
+ }
183
+
184
+ const locale = SecurityUtils.safeParseJSON(content);
185
+ if (!locale) {
186
+ this.addIssue(`Failed to parse ${file}`);
187
+ continue;
188
+ }
189
+
190
+ const existingKeys = this.extractAllKeys(locale);
191
+
192
+ const missingKeys = requiredKeys.filter(key => !existingKeys.includes(key));
193
+ if (missingKeys.length > 0) {
194
+ this.addIssue(`Missing translation keys in ${file}: ${missingKeys.join(', ')}`);
195
+ }
196
+ } catch (error) {
197
+ this.addIssue(`Error processing ${file}: ${error.message}`);
198
+ SecurityUtils.logSecurityEvent('Translation file processing failed', 'error', { file, error: error.message });
199
+ }
200
+ }
201
+ } catch (error) {
202
+ this.addIssue(`Error processing en.json: ${error.message}`);
203
+ SecurityUtils.logSecurityEvent('English translation file processing failed', 'error', { error: error.message });
204
+ }
205
+ }
206
+
207
+ extractAllKeys(obj, prefix = '') {
208
+ let keys = [];
209
+ for (const key in obj) {
210
+ const fullKey = prefix ? `${prefix}.${key}` : key;
211
+ if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
212
+ keys = keys.concat(this.extractAllKeys(obj[key], fullKey));
213
+ } else {
214
+ keys.push(fullKey);
215
+ }
216
+ }
217
+ return keys;
218
+ }
219
+
220
+ async checkUserConfig() {
221
+ this.log('Checking user configuration...');
222
+
223
+ // Check user-config.json
224
+ const configPath = path.resolve(this.projectRoot, 'user-config.json');
225
+ if (this.checkFileExists('user-config.json', 'Main configuration file')) {
226
+ try {
227
+ const content = await SecurityUtils.safeReadFile(configPath, this.projectRoot);
228
+ if (!content) {
229
+ this.addIssue('Failed to read user-config.json');
230
+ return;
231
+ }
232
+
233
+ const config = SecurityUtils.safeParseJSON(content);
234
+ if (!config) {
235
+ this.addIssue('Failed to parse user-config.json');
236
+ return;
237
+ }
238
+
239
+ // Validate configuration structure
240
+ const validatedConfig = SecurityUtils.validateConfig(config);
241
+ if (!validatedConfig) {
242
+ this.addIssue('Invalid configuration structure in user-config.json');
243
+ return;
244
+ }
245
+
246
+ // Check required sections
247
+ const requiredSections = ['directories', 'processing', 'advanced', 'ui'];
248
+ requiredSections.forEach(section => {
249
+ if (!validatedConfig[section]) {
250
+ this.addWarning(`Missing configuration section: ${section}`);
251
+ }
252
+ });
253
+
254
+ // Check directory paths with security validation
255
+ if (validatedConfig.directories) {
256
+ const dirs = ['sourceDir', 'outputDir', 'uiLocalesDir'];
257
+ dirs.forEach(dir => {
258
+ if (validatedConfig.directories[dir]) {
259
+ const dirPath = SecurityUtils.validatePath(validatedConfig.directories[dir], this.projectRoot);
260
+ if (!dirPath || !fs.existsSync(dirPath)) {
261
+ this.addWarning(`Configured directory does not exist or is invalid: ${validatedConfig.directories[dir]}`);
262
+ }
263
+ }
264
+ });
265
+ }
266
+ } catch (error) {
267
+ this.addIssue(`Error processing user-config.json: ${error.message}`);
268
+ SecurityUtils.logSecurityEvent('User config processing failed', 'error', { error: error.message });
269
+ }
270
+ }
271
+ }
272
+
273
+ checkPackageJson() {
274
+ this.log('Checking package configuration...');
275
+ this.checkFileExists('package.json', 'Package configuration');
276
+ }
277
+
278
+ checkCoreFiles() {
279
+ this.log('Checking core i18nTK files...');
280
+ const coreFiles = [
281
+ 'i18ntk-manage.js',
282
+ 'i18ntk-init.js',
283
+ 'i18ntk-analyze.js',
284
+ 'i18ntk-validate.js',
285
+ 'i18ntk-usage.js',
286
+ 'i18ntk-complete.js',
287
+ 'i18ntk-sizing.js',
288
+ 'i18ntk-summary.js'
289
+ ];
290
+
291
+ coreFiles.forEach(file => {
292
+ this.checkFileExists(file, 'Core i18nTK script');
293
+ });
294
+ }
295
+
296
+ checkDependencies() {
297
+ this.log('Checking dependencies...');
298
+ try {
299
+ const packageJson = JSON.parse(fs.readFileSync(path.resolve(this.projectRoot, 'package.json'), 'utf8'));
300
+ const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
301
+
302
+ // Check if node_modules exists
303
+ const nodeModulesPath = path.resolve(this.projectRoot, 'node_modules');
304
+ if (!fs.existsSync(nodeModulesPath)) {
305
+ this.addWarning('node_modules directory not found. Run npm install.');
306
+ }
307
+
308
+ this.log(`Found ${Object.keys(dependencies).length} dependencies`);
309
+ } catch (error) {
310
+ this.addIssue(`Could not check dependencies: ${error.message}`);
311
+ }
312
+ }
313
+
314
+ async generateReport() {
315
+ const timestamp = new Date().toLocaleString();
316
+ let summary = '';
317
+
318
+ summary += '\n' + '='.repeat(60) + '\n';
319
+ summary += ' i18nTK DEBUG REPORT\n';
320
+ summary += '='.repeat(60) + '\n';
321
+ summary += `Generated: ${timestamp}\n`;
322
+ summary += `Project Root: ${this.projectRoot}\n`;
323
+ summary += '-'.repeat(60) + '\n';
324
+ summary += `📊 Summary: ${this.issues.length} issue(s), ${this.warnings.length} warning(s)\n`;
325
+ summary += '-'.repeat(60) + '\n';
326
+
327
+ if (this.issues.length > 0) {
328
+ summary += '\n🚨 CRITICAL ISSUES:\n';
329
+ this.issues.forEach((issue, index) => {
330
+ summary += ` ${index + 1}. ❌ ${issue}\n`;
331
+ });
332
+ }
333
+
334
+ if (this.warnings.length > 0) {
335
+ summary += '\n⚠️ WARNINGS:\n';
336
+ this.warnings.forEach((warning, index) => {
337
+ summary += ` ${index + 1}. ⚠️ ${warning}\n`;
338
+ });
339
+ }
340
+
341
+ if (this.issues.length === 0 && this.warnings.length === 0) {
342
+ summary += '\n✅ EXCELLENT! No issues found.\n';
343
+ summary += ' The i18nTK project appears to be healthy.\n';
344
+ }
345
+
346
+ summary += '\n' + '='.repeat(60) + '\n';
347
+ summary += `📄 Full debug log: ${this.logFile}\n`;
348
+ summary += '='.repeat(60) + '\n';
349
+
350
+ console.log(summary);
351
+
352
+ // Save report to file securely
353
+ const reportPath = path.join(path.dirname(this.logFile), 'debug-report.txt');
354
+ const success = await SecurityUtils.safeWriteFile(reportPath, summary, this.projectRoot);
355
+ if (!success) {
356
+ console.warn('Warning: Could not save debug report due to security restrictions');
357
+ SecurityUtils.logSecurityEvent('Debug report save failed', 'warn', { reportPath });
358
+ }
359
+
360
+ return {
361
+ issues: this.issues,
362
+ warnings: this.warnings,
363
+ summary: summary,
364
+ reportPath: reportPath,
365
+ logFile: this.logFile
366
+ };
367
+ }
368
+
369
+ async run() {
370
+ this.log('Starting i18nTK Debug Analysis...');
371
+ this.log(`Project Root: ${this.projectRoot}`);
372
+
373
+ SecurityUtils.logSecurityEvent('Debug analysis started', 'info', { projectRoot: this.projectRoot });
374
+
375
+ try {
376
+ this.checkCoreFiles();
377
+ await this.checkUserConfig();
378
+ this.checkPackageJson();
379
+ this.checkOldNamingConventions();
380
+ await this.checkTranslationKeys();
381
+ this.checkDependencies();
382
+
383
+ SecurityUtils.logSecurityEvent('Debug analysis completed', 'info', {
384
+ issuesFound: this.issues.length,
385
+ warningsFound: this.warnings.length
386
+ });
387
+
388
+ return await this.generateReport();
389
+ } catch (error) {
390
+ this.addIssue(`Debug analysis failed: ${error.message}`);
391
+ SecurityUtils.logSecurityEvent('Debug analysis failed', 'error', { error: error.message });
392
+ return await this.generateReport();
393
+ }
394
+ }
395
+ }
396
+
397
+ // Run debugger if called directly
398
+ if (require.main === module) {
399
+ const debugTool = new I18nDebugger();
400
+ debugTool.run().then(result => {
401
+ process.exit(result.issues.length > 0 ? 1 : 0);
402
+ }).catch(error => {
403
+ console.error('Debugger failed:', error);
404
+ process.exit(1);
405
+ });
406
+ }
407
+
408
+ module.exports = I18nDebugger;