i18ntk 2.1.0 → 2.3.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 (73) hide show
  1. package/README.md +87 -50
  2. package/main/i18ntk-analyze.js +63 -63
  3. package/main/i18ntk-backup-class.js +37 -41
  4. package/main/i18ntk-backup.js +28 -30
  5. package/main/i18ntk-complete.js +75 -74
  6. package/main/i18ntk-doctor.js +7 -6
  7. package/main/i18ntk-fixer.js +3 -3
  8. package/main/i18ntk-init.js +49 -13
  9. package/main/i18ntk-scanner.js +2 -2
  10. package/main/i18ntk-sizing.js +36 -37
  11. package/main/i18ntk-summary.js +4 -4
  12. package/main/i18ntk-ui.js +95 -96
  13. package/main/i18ntk-usage.js +31 -19
  14. package/main/i18ntk-validate.js +78 -27
  15. package/main/manage/commands/AnalyzeCommand.js +71 -73
  16. package/main/manage/commands/CommandRouter.js +15 -12
  17. package/main/manage/commands/FixerCommand.js +94 -38
  18. package/main/manage/commands/ScannerCommand.js +2 -2
  19. package/main/manage/commands/ValidateCommand.js +87 -36
  20. package/main/manage/index.js +165 -152
  21. package/main/manage/managers/DebugMenu.js +6 -6
  22. package/main/manage/managers/InteractiveMenu.js +6 -6
  23. package/main/manage/managers/LanguageMenu.js +12 -6
  24. package/main/manage/managers/SettingsMenu.js +6 -6
  25. package/main/manage/services/AuthenticationService.js +5 -6
  26. package/main/manage/services/ConfigurationService.js +22 -34
  27. package/main/manage/services/FileManagementService.js +6 -6
  28. package/main/manage/services/InitService.js +44 -8
  29. package/main/manage/services/UsageService.js +24 -12
  30. package/package.json +21 -42
  31. package/settings/settings-cli.js +5 -5
  32. package/settings/settings-manager.js +984 -968
  33. package/ui-locales/de.json +12 -11
  34. package/ui-locales/en.json +12 -11
  35. package/ui-locales/es.json +12 -11
  36. package/ui-locales/fr.json +12 -11
  37. package/ui-locales/ja.json +12 -11
  38. package/ui-locales/ru.json +12 -11
  39. package/ui-locales/zh.json +12 -11
  40. package/utils/config-helper.js +27 -16
  41. package/utils/config-manager.js +8 -7
  42. package/utils/i18n-helper.js +161 -166
  43. package/utils/init-helper.js +3 -2
  44. package/utils/json-output.js +11 -10
  45. package/{scripts → utils}/locale-optimizer.js +61 -60
  46. package/utils/logger.js +4 -4
  47. package/utils/safe-json.js +3 -3
  48. package/utils/secure-backup.js +8 -7
  49. package/utils/setup-enforcer.js +63 -98
  50. package/main/i18ntk-go.js +0 -283
  51. package/main/i18ntk-java.js +0 -380
  52. package/main/i18ntk-js.js +0 -512
  53. package/main/i18ntk-manage.js +0 -1694
  54. package/main/i18ntk-php.js +0 -462
  55. package/main/i18ntk-py.js +0 -379
  56. package/main/i18ntk-settings.js +0 -23
  57. package/main/manage/index-fixed.js +0 -1447
  58. package/scripts/build-lite.js +0 -279
  59. package/scripts/deprecate-versions.js +0 -317
  60. package/scripts/export-translations.js +0 -84
  61. package/scripts/fix-all-i18n.js +0 -236
  62. package/scripts/fix-and-purify-i18n.js +0 -233
  63. package/scripts/fix-locale-control-chars.js +0 -110
  64. package/scripts/lint-locales.js +0 -80
  65. package/scripts/prepublish-dev.js +0 -221
  66. package/scripts/prepublish.js +0 -362
  67. package/scripts/security-check.js +0 -117
  68. package/scripts/sync-translations.js +0 -151
  69. package/scripts/sync-ui-locales.js +0 -20
  70. package/scripts/validate-all-translations.js +0 -195
  71. package/scripts/verify-deprecations.js +0 -157
  72. package/scripts/verify-translations.js +0 -63
  73. package/utils/security-fixed.js +0 -609
package/main/i18ntk-js.js DELETED
@@ -1,512 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * i18ntk JavaScript/TypeScript Command
5
- * Specialized command for JavaScript and TypeScript i18n management
6
- *
7
- * Usage: i18ntk-js [options]
8
- */
9
-
10
- const fs = require('fs');
11
- const path = require('path');
12
- const SecurityUtils = require(path.join(__dirname, '../utils/security.js'));
13
- const { getConfig, saveConfig } = require(path.join(__dirname, '../utils/config-helper.js'));
14
- const I18nHelper = require(path.join(__dirname, '../utils/i18n-helper.js'));
15
- const SetupEnforcer = require(path.join(__dirname, '../utils/setup-enforcer'));
16
- const { program } = require('../utils/mini-commander');
17
-
18
- (async () => {
19
- try {
20
- await SetupEnforcer.checkSetupCompleteAsync();
21
- } catch (error) {
22
- console.error('Setup check failed:', error.message);
23
- process.exit(1);
24
- }
25
- })();
26
-
27
- class I18ntkJavaScriptCommand {
28
- constructor() {
29
- this.config = null;
30
- this.sourceDir = './src';
31
- this.jsPatterns = [
32
- // JavaScript/TypeScript patterns
33
- /i18n\.t\s*\(\s*["'`]([^"'`]+)["'`]/g,
34
- /t\s*\(\s*["'`]([^"'`]+)["'`]/g,
35
- /translate\s*\(\s*["'`]([^"'`]+)["'`]/g,
36
- /formatMessage\s*\(\s*{[^}]*id:\s*["'`]([^"'`]+)["'`]/g,
37
- /intl\.formatMessage\s*\(\s*{[^}]*id:\s*["'`]([^"'`]+)["'`]/g,
38
- /useTranslations?\s*\(\s*["'`]([^"'`]+)["'`]/g,
39
- /getTranslations?\s*\(\s*["'`]([^"'`]+)["'`]/g,
40
-
41
- // React patterns
42
- /FormattedMessage\s+id=["'`]([^"'`]+)["'`]/g,
43
- /<FormattedMessage[^>]*id={["'`]([^"'`]+)["'`]}/g,
44
- /useTranslation\(\)\s*\.t\s*\(\s*["'`]([^"'`]+)["'`]/g,
45
-
46
- // Angular patterns
47
- /translate\s*\|\s*translate/g,
48
- /\{\{\s*["'`]([^"'`]+)["'`]\s*\|\s*translate\s*}}/g,
49
-
50
- // Vue patterns
51
- /\$t\s*\(\s*["'`]([^"'`]+)["'`]/g,
52
- /this\.\$t\s*\(\s*["'`]([^"'`]+)["'`]/g,
53
-
54
- // Node.js patterns
55
- /__\s*\(\s*["'`]([^"'`]+)["'`]/g,
56
- /gettext\s*\(\s*["'`]([^"'`]+)["'`]/g,
57
-
58
- // Template literal patterns
59
- /i18n\.t\s*\(\s*`([^`]+)`/g,
60
- /t\s*\(\s*`([^`]+)`/g
61
- ];
62
-
63
- this.frameworks = {
64
- react: {
65
- indicators: ['package.json', 'react', 'react-dom'],
66
- patterns: ['useTranslation', 'FormattedMessage', 'react-intl']
67
- },
68
- vue: {
69
- indicators: ['package.json', 'vue', 'vue-i18n'],
70
- patterns: ['$t', 'vue-i18n', 'i18n']
71
- },
72
- angular: {
73
- indicators: ['package.json', '@angular/core', '@ngx-translate'],
74
- patterns: ['translate', '@ngx-translate/core']
75
- },
76
- node: {
77
- indicators: ['package.json', 'express', 'i18n'],
78
- patterns: ['__', 'gettext', 'i18n']
79
- }
80
- };
81
- }
82
-
83
- async init() {
84
- console.log('šŸ”§ Initializing i18ntk JavaScript/TypeScript command...');
85
-
86
- program
87
- .name('i18ntk-js')
88
- .description('i18ntk specialized for JavaScript and TypeScript applications')
89
- .version('1.10.1')
90
- .option('-s, --source-dir <dir>', 'Source directory to scan', './src')
91
- .option('-l, --locales-dir <dir>', 'Locales directory', './locales')
92
- .option('--framework <type>', 'JavaScript framework type', 'auto')
93
- .option('--typescript', 'Include TypeScript files')
94
- .option('--react', 'Force React mode')
95
- .option('--vue', 'Force Vue mode')
96
- .option('--angular', 'Force Angular mode')
97
- .option('--node', 'Force Node.js mode')
98
- .option('--dry-run', 'Show what would be done without making changes')
99
- .option('--debug', 'Enable debug output')
100
- .option('--extract-only', 'Only extract translations, don\'t analyze')
101
- .option('--include-tests', 'Include test files in analysis')
102
- .parse();
103
-
104
- this.options = program.opts();
105
- this.sourceDir = path.resolve(this.options.sourceDir);
106
- this.localesDir = path.resolve(this.options.localesDir);
107
-
108
- await this.validateSourceDir();
109
- await this.loadConfig();
110
- }
111
-
112
- async validateSourceDir() {
113
- if (!SecurityUtils.safeExistsSync(this.sourceDir, path.dirname(this.sourceDir))) {
114
- console.error(`āŒ Source directory not found: ${this.sourceDir}`);
115
- process.exit(1);
116
- }
117
-
118
- const stats = fs.statSync(this.sourceDir);
119
- if (!stats.isDirectory()) {
120
- console.error(`āŒ Source path is not a directory: ${this.sourceDir}`);
121
- process.exit(1);
122
- }
123
- }
124
-
125
- async loadConfig() {
126
- try {
127
- this.config = await getConfig();
128
- this.config.javascript = this.config.javascript || {};
129
- } catch (error) {
130
- console.warn('āš ļø Could not load config, using defaults');
131
- this.config = { javascript: {} };
132
- }
133
- }
134
-
135
- async detectFramework() {
136
- if (this.options.react) return 'react';
137
- if (this.options.vue) return 'vue';
138
- if (this.options.angular) return 'angular';
139
- if (this.options.node) return 'node';
140
-
141
- console.log('šŸ” Detecting JavaScript framework...');
142
-
143
- let framework = 'generic';
144
-
145
- try {
146
- const packageJsonPath = path.join(this.sourceDir, 'package.json');
147
- if (SecurityUtils.safeExistsSync(packageJsonPath, this.sourceDir)) {
148
- const packageJsonContent = SecurityUtils.safeReadFileSync(packageJsonPath, this.sourceDir, 'utf8');
149
- const packageJson = SecurityUtils.safeParseJSON(packageJsonContent);
150
-
151
- const dependencies = {
152
- ...packageJson.dependencies || {},
153
- ...packageJson.devDependencies || {}
154
- };
155
-
156
- // Check for React
157
- if (dependencies.react && dependencies['react-dom']) {
158
- framework = 'react';
159
- }
160
- // Check for Vue
161
- else if (dependencies.vue && dependencies['vue-i18n']) {
162
- framework = 'vue';
163
- }
164
- // Check for Angular
165
- else if (dependencies['@angular/core'] || dependencies['@ngx-translate/core']) {
166
- framework = 'angular';
167
- }
168
- // Check for Node.js
169
- else if (dependencies.express || dependencies.i18n || dependencies['i18next']) {
170
- framework = 'node';
171
- }
172
- }
173
-
174
- } catch (error) {
175
- if (this.options.debug) {
176
- console.error('Debug: Framework detection error:', error.message);
177
- }
178
- }
179
-
180
- console.log(`āœ… Detected framework: ${framework}`);
181
- return framework;
182
- }
183
-
184
- findFiles(pattern, extensions = []) {
185
- const results = [];
186
- const validExtensions = extensions.length > 0 ? extensions : ['.js', '.jsx', '.ts', '.tsx'];
187
-
188
- function scanDir(dir) {
189
- if (!SecurityUtils.safeExistsSync(dir, path.dirname(dir))) return;
190
-
191
- const items = fs.readdirSync(dir);
192
- for (const item of items) {
193
- const fullPath = path.join(dir, item);
194
- const stat = fs.statSync(fullPath);
195
-
196
- if (stat.isDirectory()) {
197
- // Skip node_modules and hidden directories
198
- if (item === 'node_modules' || item.startsWith('.')) continue;
199
-
200
- // Skip test directories unless explicitly included
201
- if (!this.options.includeTests &&
202
- (item === '__tests__' || item === 'test' || item === 'tests' || item.includes('.test.'))) {
203
- continue;
204
- }
205
-
206
- scanDir.call(this, fullPath);
207
- } else {
208
- // Check file extension
209
- const ext = path.extname(item);
210
- if (validExtensions.includes(ext)) {
211
- // Skip test files unless explicitly included
212
- if (!this.options.includeTests &&
213
- (item.includes('.test.') || item.includes('.spec.') || item.includes('__test__'))) {
214
- continue;
215
- }
216
-
217
- results.push(fullPath);
218
- }
219
- }
220
- }
221
- }
222
-
223
- scanDir.call(this, this.sourceDir);
224
- return results;
225
- }
226
-
227
- async extractTranslations() {
228
- console.log('šŸ“¦ Extracting JavaScript/TypeScript translations...');
229
-
230
- const extensions = this.options.typescript
231
- ? ['.js', '.jsx', '.ts', '.tsx']
232
- : ['.js', '.jsx'];
233
-
234
- const jsFiles = this.findFiles('', extensions);
235
- const translations = new Set();
236
-
237
- for (const file of jsFiles) {
238
- try {
239
- const content = SecurityUtils.safeReadFileSync(file, path.dirname(file), 'utf8');
240
-
241
- for (const pattern of this.jsPatterns) {
242
- let match;
243
- while ((match = pattern.exec(content)) !== null) {
244
- translations.add(match[1]);
245
- }
246
- }
247
-
248
- // Reset regex state for next file
249
- for (const pattern of this.jsPatterns) {
250
- pattern.lastIndex = 0;
251
- }
252
-
253
- } catch (error) {
254
- if (this.options.debug) {
255
- console.error(`Error reading ${file}:`, error.message);
256
- }
257
- }
258
- }
259
-
260
- console.log(`šŸ“Š Found ${translations.size} unique translation keys`);
261
- return Array.from(translations);
262
- }
263
-
264
- async createLocaleStructure() {
265
- if (!SecurityUtils.safeExistsSync(this.localesDir, path.dirname(this.localesDir))) {
266
- if (this.options.dryRun) {
267
- console.log(`šŸ“ Would create directory: ${this.localesDir}`);
268
- return;
269
- }
270
-
271
- fs.mkdirSync(this.localesDir, { recursive: true });
272
- console.log(`šŸ“ Created locales directory: ${this.localesDir}`);
273
- }
274
-
275
- const languages = ['en', 'es', 'fr', 'de', 'ja', 'ru', 'zh'];
276
-
277
- for (const lang of languages) {
278
- const langDir = path.join(this.localesDir, lang);
279
- if (!SecurityUtils.safeExistsSync(langDir, this.localesDir)) {
280
- if (this.options.dryRun) {
281
- console.log(`šŸ“ Would create directory: ${langDir}`);
282
- continue;
283
- }
284
-
285
- fs.mkdirSync(langDir, { recursive: true });
286
-
287
- // Create framework-specific translation files
288
- const commonFile = path.join(langDir, 'common.json');
289
- const initialContent = {
290
- "javascript": {
291
- "welcome": `Welcome to JavaScript (${lang})`,
292
- "framework_detected": "Framework detected: {framework}",
293
- "files_processed": "Processed {count} files",
294
- "keys_found": "Found {count} translation keys"
295
- },
296
- "components": {
297
- "button": {
298
- "submit": "Submit",
299
- "cancel": "Cancel",
300
- "save": "Save"
301
- },
302
- "form": {
303
- "validation": {
304
- "required": "This field is required",
305
- "invalid": "Invalid format"
306
- }
307
- }
308
- }
309
- };
310
-
311
- SecurityUtils.safeWriteFileSync(commonFile, JSON.stringify(initialContent, null, 2), this.localesDir);
312
- }
313
- }
314
- }
315
-
316
- async analyzeFramework(framework) {
317
- console.log(`šŸ” Analyzing ${framework} project...`);
318
-
319
- const extensions = this.options.typescript
320
- ? ['.js', '.jsx', '.ts', '.tsx']
321
- : ['.js', '.jsx'];
322
-
323
- const jsFiles = this.findFiles('', extensions);
324
-
325
- const analysis = {
326
- framework,
327
- typescript: this.options.typescript || false,
328
- files: {
329
- total: jsFiles.length,
330
- javascript: 0,
331
- typescript: 0,
332
- jsx: 0,
333
- tsx: 0,
334
- test: 0
335
- },
336
- patterns: {
337
- i18n_t: 0,
338
- t_function: 0,
339
- useTranslation: 0,
340
- FormattedMessage: 0,
341
- translate: 0,
342
- $t: 0,
343
- gettext: 0
344
- },
345
- frameworks: {
346
- react: false,
347
- vue: false,
348
- angular: false,
349
- node: false
350
- },
351
- recommendations: [],
352
- dependencies: []
353
- };
354
-
355
- // Analyze files
356
- for (const file of jsFiles) {
357
- const ext = path.extname(file);
358
- if (ext === '.js') analysis.files.javascript++;
359
- else if (ext === '.ts') analysis.files.typescript++;
360
- else if (ext === '.jsx') analysis.files.jsx++;
361
- else if (ext === '.tsx') analysis.files.tsx++;
362
-
363
- if (file.includes('.test.') || file.includes('.spec.')) {
364
- analysis.files.test++;
365
- }
366
-
367
- try {
368
- const content = SecurityUtils.safeReadFileSync(file, path.dirname(file), 'utf8');
369
-
370
- // Check patterns
371
- if (content.includes('i18n.t(')) analysis.patterns.i18n_t++;
372
- if (content.includes('t(')) analysis.patterns.t_function++;
373
- if (content.includes('useTranslation')) analysis.patterns.useTranslation++;
374
- if (content.includes('FormattedMessage')) analysis.patterns.FormattedMessage++;
375
- if (content.includes('translate')) analysis.patterns.translate++;
376
- if (content.includes('$t(')) analysis.patterns.$t++;
377
- if (content.includes('gettext(')) analysis.patterns.gettext++;
378
-
379
- // Detect frameworks
380
- if (content.includes('import React') || content.includes('require("react")')) {
381
- analysis.frameworks.react = true;
382
- }
383
- if (content.includes('Vue') || content.includes('vue-i18n')) {
384
- analysis.frameworks.vue = true;
385
- }
386
- if (content.includes('@angular') || content.includes('@ngx-translate')) {
387
- analysis.frameworks.angular = true;
388
- }
389
- if (content.includes('express') || content.includes('node')) {
390
- analysis.frameworks.node = true;
391
- }
392
-
393
- } catch (error) {
394
- // Skip unreadable files
395
- }
396
- }
397
-
398
- // Generate recommendations
399
- if (analysis.files.total > 0 && analysis.patterns.i18n_t === 0) {
400
- analysis.recommendations.push('Consider adding i18n support to your JavaScript/TypeScript files');
401
- }
402
-
403
- if (analysis.frameworks.react && analysis.patterns.FormattedMessage === 0) {
404
- analysis.recommendations.push('Consider using react-intl or react-i18next for React i18n');
405
- }
406
-
407
- if (analysis.frameworks.vue && analysis.patterns.$t === 0) {
408
- analysis.recommendations.push('Consider using vue-i18n for Vue.js i18n');
409
- }
410
-
411
- // Check package.json for dependencies
412
- try {
413
- const packageJsonPath = path.join(this.sourceDir, 'package.json');
414
- if (SecurityUtils.safeExistsSync(packageJsonPath, this.sourceDir)) {
415
- const packageJsonContent = SecurityUtils.safeReadFileSync(packageJsonPath, this.sourceDir, 'utf8');
416
- const packageJson = SecurityUtils.safeParseJSON(packageJsonContent);
417
- const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
418
-
419
- for (const [pkg, version] of Object.entries(deps)) {
420
- if (pkg.includes('i18n') || pkg.includes('intl') || pkg.includes('translate')) {
421
- analysis.dependencies.push(`${pkg}@${version}`);
422
- }
423
- }
424
- }
425
- } catch (error) {
426
- // Skip package.json analysis errors
427
- }
428
-
429
- return analysis;
430
- }
431
-
432
- async generateReport(analysis, translations) {
433
- const report = {
434
- timestamp: new Date().toISOString(),
435
- framework: analysis.framework,
436
- typescript: analysis.typescript,
437
- summary: {
438
- totalFiles: analysis.files.total,
439
- javascriptFiles: analysis.files.javascript,
440
- typescriptFiles: analysis.files.typescript,
441
- jsxFiles: analysis.files.jsx,
442
- tsxFiles: analysis.files.tsx,
443
- testFiles: analysis.files.test,
444
- translationKeys: translations.length
445
- },
446
- patterns: analysis.patterns,
447
- frameworks: analysis.frameworks,
448
- dependencies: analysis.dependencies,
449
- recommendations: analysis.recommendations,
450
- files: {
451
- javascript: this.findFiles('', ['.js']),
452
- typescript: this.findFiles('', ['.ts']),
453
- jsx: this.findFiles('', ['.jsx']),
454
- tsx: this.findFiles('', ['.tsx'])
455
- },
456
- translations: translations.sort()
457
- };
458
-
459
- const reportPath = path.join(this.sourceDir, 'i18ntk-js-report.json');
460
-
461
- if (this.options.dryRun) {
462
- console.log(`šŸ“Š Would create report: ${reportPath}`);
463
- console.log('šŸ“‹ Report contents:', JSON.stringify(report, null, 2));
464
- } else {
465
- SecurityUtils.safeWriteFileSync(reportPath, JSON.stringify(report, null, 2), this.sourceDir);
466
- console.log(`šŸ“Š Report saved: ${reportPath}`);
467
- }
468
-
469
- return report;
470
- }
471
-
472
- async run() {
473
- try {
474
- console.log('šŸš€ i18ntk JavaScript/TypeScript Command v1.10.1');
475
- console.log('='.repeat(60));
476
-
477
- await this.init();
478
-
479
- const framework = await this.detectFramework();
480
- const translations = await this.extractTranslations();
481
-
482
- if (!this.options.extractOnly) {
483
- await this.createLocaleStructure();
484
- const analysis = await this.analyzeFramework(framework);
485
- const report = await this.generateReport(analysis, translations);
486
-
487
- console.log('\nāœ… Analysis complete!');
488
- console.log(`šŸ“Š Framework: ${framework}`);
489
- console.log(`šŸ“„ Total files: ${analysis.files.total}`);
490
- console.log(`šŸŽÆ Translation keys: ${translations.length}`);
491
- console.log(`šŸ“‹ Report: ${this.options.dryRun ? 'Not saved (dry-run)' : 'Saved to i18ntk-js-report.json'}`);
492
- } else {
493
- console.log(`šŸ“¦ Extracted ${translations.length} translation keys`);
494
- }
495
-
496
- } catch (error) {
497
- console.error('āŒ Error:', error.message);
498
- if (this.options.debug) {
499
- console.error(error.stack);
500
- }
501
- process.exit(1);
502
- }
503
- }
504
- }
505
-
506
- // Run if called directly
507
- if (require.main === module) {
508
- const cmd = new I18ntkJavaScriptCommand();
509
- cmd.run();
510
- }
511
-
512
- module.exports = I18ntkJavaScriptCommand;