i18ntk 1.10.2 → 2.0.2

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 (108) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +141 -1191
  3. package/main/i18ntk-analyze.js +65 -84
  4. package/main/i18ntk-backup-class.js +420 -0
  5. package/main/i18ntk-backup.js +3 -3
  6. package/main/i18ntk-complete.js +90 -65
  7. package/main/i18ntk-doctor.js +123 -103
  8. package/main/i18ntk-fixer.js +61 -725
  9. package/main/i18ntk-go.js +14 -15
  10. package/main/i18ntk-init.js +77 -26
  11. package/main/i18ntk-java.js +27 -32
  12. package/main/i18ntk-js.js +70 -68
  13. package/main/i18ntk-manage.js +129 -30
  14. package/main/i18ntk-php.js +75 -75
  15. package/main/i18ntk-py.js +55 -56
  16. package/main/i18ntk-scanner.js +59 -57
  17. package/main/i18ntk-setup.js +9 -404
  18. package/main/i18ntk-sizing.js +6 -6
  19. package/main/i18ntk-summary.js +21 -18
  20. package/main/i18ntk-ui.js +11 -10
  21. package/main/i18ntk-usage.js +54 -18
  22. package/main/i18ntk-validate.js +13 -13
  23. package/main/manage/commands/AnalyzeCommand.js +1124 -0
  24. package/main/manage/commands/BackupCommand.js +62 -0
  25. package/main/manage/commands/CommandRouter.js +295 -0
  26. package/main/manage/commands/CompleteCommand.js +61 -0
  27. package/main/manage/commands/DoctorCommand.js +60 -0
  28. package/main/manage/commands/FixerCommand.js +624 -0
  29. package/main/manage/commands/InitCommand.js +62 -0
  30. package/main/manage/commands/ScannerCommand.js +654 -0
  31. package/main/manage/commands/SizingCommand.js +60 -0
  32. package/main/manage/commands/SummaryCommand.js +61 -0
  33. package/main/manage/commands/UsageCommand.js +60 -0
  34. package/main/manage/commands/ValidateCommand.js +978 -0
  35. package/main/manage/index-fixed.js +1447 -0
  36. package/main/manage/index.js +1462 -0
  37. package/main/manage/managers/DebugMenu.js +140 -0
  38. package/main/manage/managers/InteractiveMenu.js +177 -0
  39. package/main/manage/managers/LanguageMenu.js +62 -0
  40. package/main/manage/managers/SettingsMenu.js +53 -0
  41. package/main/manage/services/AuthenticationService.js +263 -0
  42. package/main/manage/services/ConfigurationService-fixed.js +449 -0
  43. package/main/manage/services/ConfigurationService.js +449 -0
  44. package/main/manage/services/FileManagementService.js +368 -0
  45. package/main/manage/services/FrameworkDetectionService.js +458 -0
  46. package/main/manage/services/InitService.js +1051 -0
  47. package/main/manage/services/SetupService.js +462 -0
  48. package/main/manage/services/SummaryService.js +450 -0
  49. package/main/manage/services/UsageService.js +1502 -0
  50. package/package.json +32 -29
  51. package/runtime/enhanced.d.ts +221 -221
  52. package/runtime/index.d.ts +29 -29
  53. package/runtime/index.full.d.ts +331 -331
  54. package/runtime/index.js +7 -6
  55. package/scripts/build-lite.js +17 -17
  56. package/scripts/deprecate-versions.js +23 -6
  57. package/scripts/export-translations.js +5 -5
  58. package/scripts/fix-all-i18n.js +3 -3
  59. package/scripts/fix-and-purify-i18n.js +3 -2
  60. package/scripts/fix-locale-control-chars.js +110 -0
  61. package/scripts/lint-locales.js +80 -0
  62. package/scripts/locale-optimizer.js +8 -8
  63. package/scripts/prepublish.js +21 -21
  64. package/scripts/security-check.js +117 -117
  65. package/scripts/sync-translations.js +4 -4
  66. package/scripts/sync-ui-locales.js +9 -8
  67. package/scripts/validate-all-translations.js +8 -7
  68. package/scripts/verify-deprecations.js +157 -161
  69. package/scripts/verify-translations.js +6 -5
  70. package/settings/i18ntk-config.json +282 -282
  71. package/settings/language-config.json +5 -5
  72. package/settings/settings-cli.js +9 -9
  73. package/settings/settings-manager.js +18 -18
  74. package/ui-locales/de.json +2417 -2348
  75. package/ui-locales/en.json +2415 -2352
  76. package/ui-locales/es.json +2425 -2353
  77. package/ui-locales/fr.json +2418 -2348
  78. package/ui-locales/ja.json +2463 -2361
  79. package/ui-locales/ru.json +2463 -2359
  80. package/ui-locales/zh.json +2418 -2351
  81. package/utils/admin-auth.js +2 -2
  82. package/utils/admin-cli.js +297 -297
  83. package/utils/admin-pin.js +9 -9
  84. package/utils/cli-helper.js +9 -9
  85. package/utils/config-helper.js +73 -104
  86. package/utils/config-manager.js +204 -171
  87. package/utils/config.js +5 -4
  88. package/utils/env-manager.js +249 -263
  89. package/utils/framework-detector.js +27 -24
  90. package/utils/i18n-helper.js +85 -41
  91. package/utils/init-helper.js +152 -94
  92. package/utils/json-output.js +98 -98
  93. package/utils/mini-commander.js +179 -0
  94. package/utils/missing-key-validator.js +5 -5
  95. package/utils/plugin-loader.js +40 -29
  96. package/utils/prompt.js +14 -44
  97. package/utils/safe-json.js +40 -0
  98. package/utils/secure-errors.js +3 -3
  99. package/utils/security-check-improved.js +390 -0
  100. package/utils/security-config.js +5 -5
  101. package/utils/security-fixed.js +607 -0
  102. package/utils/security.js +652 -602
  103. package/utils/setup-enforcer.js +136 -44
  104. package/utils/setup-validator.js +33 -32
  105. package/utils/ultra-performance-optimizer.js +11 -9
  106. package/utils/watch-locales.js +2 -1
  107. package/utils/prompt-fixed.js +0 -55
  108. package/utils/security-check.js +0 -454
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * i18ntk-setup.js - Foundational Setup Script
5
- *
5
+ *
6
6
  * This script runs before all other initialization or operational scripts.
7
7
  * It configures the core framework, detects programming language/framework,
8
8
  * specifies translation file locations, and establishes essential prerequisites.
@@ -11,417 +11,22 @@
11
11
  const fs = require('fs');
12
12
  const path = require('path');
13
13
 
14
- const SettingsManager = require('../settings/settings-manager');
14
+ const SecurityUtils = require('../utils/security');
15
+ const configManager = require('../utils/config-manager');
16
+ const SetupService = require('./manage/services/SetupService');
15
17
 
16
18
  class I18nSetupManager {
17
19
  constructor() {
18
- this.config = {
19
- detectedLanguage: null,
20
- detectedFramework: null,
21
- sourceDir: './locales',
22
- outputDir: './i18ntk-reports',
23
- frameworkConfig: {},
24
- prerequisites: {},
25
- optimization: {
26
- mode: 'auto',
27
- cacheEnabled: true,
28
- batchSize: 1000
29
- }
30
- };
31
- this.supportedLanguages = ['javascript', 'typescript', 'python', 'java', 'go', 'php'];
32
- this.supportedFrameworks = {
33
- javascript: ['react', 'vue', 'angular', 'nextjs', 'nuxt', 'svelte'],
34
- typescript: ['react', 'vue', 'angular', 'nextjs', 'nuxt'],
35
- python: ['django', 'flask', 'fastapi'],
36
- java: ['spring', 'spring-boot', 'quarkus'],
37
- go: ['gin', 'echo', 'fiber'],
38
- php: ['laravel', 'symfony', 'wordpress']
39
- };
20
+ // Use the new SetupService for core business logic
21
+ this.setupService = new SetupService();
40
22
  }
41
23
 
42
24
  async setup() {
43
- console.log('🔧 i18n Toolkit - Foundational Setup');
44
- console.log('=====================================');
45
-
46
- try {
47
- await this.detectEnvironment();
48
- await this.configureFramework();
49
- await this.validatePrerequisites();
50
- await this.optimizeForLanguage();
51
- await this.generateSetupReport();
52
-
53
- console.log('✅ Setup completed successfully!');
54
- return this.config;
55
- } catch (error) {
56
- console.error('❌ Setup failed:', error.message);
57
- process.exit(1);
58
- }
25
+ // Delegate to SetupService for all business logic
26
+ return await this.setupService.setup();
59
27
  }
60
28
 
61
- async detectEnvironment() {
62
- console.log('📍 Detecting environment...');
63
-
64
- const packageJsonPath = path.join(process.cwd(), 'package.json');
65
- const pyprojectPath = path.join(process.cwd(), 'pyproject.toml');
66
- const requirementsPath = path.join(process.cwd(), 'requirements.txt');
67
- const goModPath = path.join(process.cwd(), 'go.mod');
68
- const pomPath = path.join(process.cwd(), 'pom.xml');
69
- const composerPath = path.join(process.cwd(), 'composer.json');
70
-
71
- if (fs.existsSync(packageJsonPath)) {
72
- this.config.detectedLanguage = 'javascript';
73
- await this.detectNodeFramework(packageJsonPath);
74
- } else if (fs.existsSync(pyprojectPath) || fs.existsSync(requirementsPath)) {
75
- this.config.detectedLanguage = 'python';
76
- await this.detectPythonFramework();
77
- } else if (fs.existsSync(goModPath)) {
78
- this.config.detectedLanguage = 'go';
79
- this.config.detectedFramework = 'generic';
80
- } else if (fs.existsSync(pomPath)) {
81
- this.config.detectedLanguage = 'java';
82
- await this.detectJavaFramework(pomPath);
83
- } else if (fs.existsSync(composerPath)) {
84
- this.config.detectedLanguage = 'php';
85
- await this.detectPhpFramework(composerPath);
86
- } else {
87
- this.config.detectedLanguage = 'generic';
88
- this.config.detectedFramework = 'generic';
89
- }
90
-
91
- console.log(` Language: ${this.config.detectedLanguage}`);
92
- console.log(` Framework: ${this.config.detectedFramework}`);
93
- }
94
-
95
- async detectNodeFramework(packageJsonPath) {
96
- try {
97
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
98
- const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
99
-
100
- if (deps.react || deps['react-dom']) this.config.detectedFramework = 'react';
101
- else if (deps.vue || deps['vue-router']) this.config.detectedFramework = 'vue';
102
- else if (deps['@angular/core']) this.config.detectedFramework = 'angular';
103
- else if (deps.next) this.config.detectedFramework = 'nextjs';
104
- else if (deps.nuxt) this.config.detectedFramework = 'nuxt';
105
- else if (deps.svelte) this.config.detectedFramework = 'svelte';
106
- else this.config.detectedFramework = 'generic';
107
- } catch (error) {
108
- this.config.detectedFramework = 'generic';
109
- }
110
- }
111
-
112
- async detectPythonFramework() {
113
- try {
114
- const requirementsPath = path.join(process.cwd(), 'requirements.txt');
115
- if (fs.existsSync(requirementsPath)) {
116
- const requirements = fs.readFileSync(requirementsPath, 'utf8');
117
- if (requirements.includes('django')) this.config.detectedFramework = 'django';
118
- else if (requirements.includes('flask')) this.config.detectedFramework = 'flask';
119
- else if (requirements.includes('fastapi')) this.config.detectedFramework = 'fastapi';
120
- else this.config.detectedFramework = 'generic';
121
- } else {
122
- this.config.detectedFramework = 'generic';
123
- }
124
- } catch (error) {
125
- this.config.detectedFramework = 'generic';
126
- }
127
- }
128
-
129
- async detectJavaFramework(pomPath) {
130
- try {
131
- const pomContent = fs.readFileSync(pomPath, 'utf8');
132
- if (pomContent.includes('spring-boot')) this.config.detectedFramework = 'spring-boot';
133
- else if (pomContent.includes('spring')) this.config.detectedFramework = 'spring';
134
- else if (pomContent.includes('quarkus')) this.config.detectedFramework = 'quarkus';
135
- else this.config.detectedFramework = 'generic';
136
- } catch (error) {
137
- this.config.detectedFramework = 'generic';
138
- }
139
- }
140
-
141
- async detectPhpFramework(composerPath) {
142
- try {
143
- const composer = JSON.parse(fs.readFileSync(composerPath, 'utf8'));
144
- const deps = composer.require || {};
145
-
146
- if (deps['laravel/framework']) this.config.detectedFramework = 'laravel';
147
- else if (deps['symfony/framework-bundle']) this.config.detectedFramework = 'symfony';
148
- else if (deps['wordpress']) this.config.detectedFramework = 'wordpress';
149
- else this.config.detectedFramework = 'generic';
150
- } catch (error) {
151
- this.config.detectedFramework = 'generic';
152
- }
153
- }
154
-
155
- async configureFramework() {
156
- console.log('⚙️ Configuring framework...');
157
-
158
- const frameworkConfigs = {
159
- javascript: {
160
- sourcePatterns: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
161
- i18nLibraries: ['i18next', 'react-i18next', 'vue-i18n', '@angular/localize'],
162
- defaultLocalePath: './src/locales',
163
- extractPatterns: [
164
- /t\(['"`]([^'"`]+)['"`]/g,
165
- /i18n\.t\(['"`]([^'"`]+)['"`]/g,
166
- /\$t\(['"`]([^'"`]+)['"`]/g
167
- ]
168
- },
169
- python: {
170
- sourcePatterns: ['**/*.py'],
171
- i18nLibraries: ['django', 'flask-babel', 'babel'],
172
- defaultLocalePath: './locale',
173
- extractPatterns: [
174
- /_\(['"`]([^'"`]+)['"`]/g,
175
- /gettext\(['"`]([^'"`]+)['"`]/g
176
- ]
177
- },
178
- go: {
179
- sourcePatterns: ['**/*.go'],
180
- i18nLibraries: ['go-i18n', 'nicksnyder/go-i18n'],
181
- defaultLocalePath: './locales',
182
- extractPatterns: [
183
- /Localize\([^)]*MessageID:\s*['"`]([^'"`]+)['"`]/g
184
- ]
185
- },
186
- java: {
187
- sourcePatterns: ['**/*.java'],
188
- i18nLibraries: ['spring-boot-starter-web', 'spring-context'],
189
- defaultLocalePath: './src/main/resources/messages',
190
- extractPatterns: [
191
- /getMessage\(['"`]([^'"`]+)['"`]/g,
192
- /@Value\(['"`]([^'"`]+)['"`]/g
193
- ]
194
- },
195
- php: {
196
- sourcePatterns: ['**/*.php'],
197
- i18nLibraries: ['gettext', 'symfony/translation'],
198
- defaultLocalePath: './resources/lang',
199
- extractPatterns: [
200
- /_\(['"`]([^'"`]+)['"`]/g,
201
- /trans\(['"`]([^'"`]+)['"`]/g
202
- ]
203
- }
204
- };
205
-
206
- this.config.frameworkConfig = frameworkConfigs[this.config.detectedLanguage] || frameworkConfigs.javascript;
207
-
208
- // Auto-detect source directory
209
- const possiblePaths = [
210
- this.config.frameworkConfig.defaultLocalePath,
211
- './locales',
212
- './i18n',
213
- './translations',
214
- './src/i18n',
215
- './app/i18n'
216
- ];
217
-
218
- for (const dirPath of possiblePaths) {
219
- if (fs.existsSync(dirPath)) {
220
- this.config.sourceDir = dirPath;
221
- break;
222
- }
223
- }
224
-
225
- console.log(` Source directory: ${this.config.sourceDir}`);
226
- }
227
-
228
- async validatePrerequisites() {
229
- console.log('🔍 Validating prerequisites...');
230
-
231
- this.config.prerequisites = {
232
- nodeVersion: process.version,
233
- nodeVersionValid: parseInt(process.version.slice(1).split('.')[0]) >= 16,
234
- hasPackageJson: fs.existsSync('package.json'),
235
- hasLocales: fs.existsSync(this.config.sourceDir),
236
- hasGit: this.checkCommand('git'),
237
- hasNpm: this.checkCommand('npm'),
238
- hasPython: this.checkCommand('python3') || this.checkCommand('python'),
239
- hasJava: this.checkCommand('java'),
240
- hasGo: this.checkCommand('go'),
241
- hasPhp: this.checkCommand('php')
242
- };
243
-
244
- // Check for i18n libraries
245
- if (this.config.detectedLanguage === 'javascript') {
246
- const packageJsonPath = path.join(process.cwd(), 'package.json');
247
- if (fs.existsSync(packageJsonPath)) {
248
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
249
- const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
250
-
251
- this.config.prerequisites.hasI18nLibrary = Object.keys(deps).some(dep =>
252
- this.config.frameworkConfig.i18nLibraries.some(lib => dep.includes(lib))
253
- );
254
- }
255
- }
256
-
257
- Object.entries(this.config.prerequisites).forEach(([key, value]) => {
258
- if (typeof value === 'boolean') {
259
- console.log(` ${key}: ${value ? '✅' : '❌'}`);
260
- } else {
261
- console.log(` ${key}: ${value}`);
262
- }
263
- });
264
- }
265
-
266
- checkCommand(command) {
267
- // Secure command checking without child_process
268
- const extensions = process.platform === 'win32' ? ['.exe', '.cmd', '.bat'] : [''];
269
- const pathEnv = process.env.PATH || process.env.Path || '';
270
- const pathDirs = pathEnv.split(process.platform === 'win32' ? ';' : ':');
271
-
272
- for (const dir of pathDirs) {
273
- for (const ext of extensions) {
274
- const fullPath = path.join(dir, command + ext);
275
- try {
276
- if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
277
- return true;
278
- }
279
- } catch {
280
- // Ignore errors accessing files
281
- }
282
- }
283
- }
284
- return false;
285
- }
286
-
287
- async optimizeForLanguage() {
288
- console.log('🚀 Optimizing for language...');
289
-
290
- const optimizationStrategies = {
291
- javascript: {
292
- mode: 'extreme',
293
- cacheEnabled: true,
294
- batchSize: 1000,
295
- parallelProcessing: true,
296
- treeShaking: true
297
- },
298
- python: {
299
- mode: 'ultra',
300
- cacheEnabled: true,
301
- batchSize: 500,
302
- asyncProcessing: true,
303
- lazyLoading: true
304
- },
305
- go: {
306
- mode: 'extreme',
307
- cacheEnabled: true,
308
- batchSize: 2000,
309
- concurrentProcessing: true,
310
- memoryOptimization: true
311
- },
312
- java: {
313
- mode: 'ultra',
314
- cacheEnabled: true,
315
- batchSize: 800,
316
- jvmOptimization: true,
317
- connectionPooling: true
318
- },
319
- php: {
320
- mode: 'optimized',
321
- cacheEnabled: true,
322
- batchSize: 300,
323
- opcacheEnabled: true,
324
- memoryLimit: '256M'
325
- }
326
- };
327
-
328
- this.config.optimization = {
329
- ...this.config.optimization,
330
- ...optimizationStrategies[this.config.detectedLanguage]
331
- };
332
-
333
- // Update configuration using SettingsManager
334
- const SettingsManager = require('../settings/settings-manager');
335
- const settingsManager = new SettingsManager();
336
-
337
- console.log('🔧 About to update settings with:', {
338
- setup: {
339
- completed: true,
340
- completedAt: new Date().toISOString(),
341
- version: require('../package.json').version,
342
- setupId: `setup_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
343
- }
344
- });
345
-
346
- settingsManager.updateSettings({
347
- 'sourceDir': this.config.sourceDir,
348
- 'outputDir': this.config.outputDir,
349
- 'detectedLanguage': this.config.detectedLanguage,
350
- 'detectedFramework': this.config.detectedFramework,
351
- 'optimization': this.config.optimization,
352
- 'prerequisites': this.config.prerequisites,
353
- 'security.adminPinEnabled': false,
354
- 'security.sessionTimeout': 1800000,
355
- 'security.maxFailedAttempts': 3,
356
- 'setup.completed': true,
357
- 'setup.completedAt': new Date().toISOString(),
358
- 'setup.version': require('../package.json').version,
359
- 'setup.setupId': `setup_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
360
- });
361
-
362
- console.log(` Configuration updated in settings/i18ntk-config.json`);
363
- }
364
-
365
- async generateSetupReport() {
366
- console.log('📊 Generating setup report...');
367
-
368
- const report = {
369
- timestamp: new Date().toISOString(),
370
- setup: {
371
- language: this.config.detectedLanguage,
372
- framework: this.config.detectedFramework,
373
- sourceDirectory: this.config.sourceDir,
374
- optimizationMode: this.config.optimization.mode,
375
- prerequisitesMet: Object.values(this.config.prerequisites).filter(v => v === true).length,
376
- totalPrerequisites: Object.values(this.config.prerequisites).filter(v => typeof v === 'boolean').length
377
- },
378
- recommendations: this.generateRecommendations(),
379
- nextSteps: [
380
- 'Run i18ntk-init to initialize your project',
381
- 'Run i18ntk-analyze to scan for translations',
382
- 'Run i18ntk-validate to validate your setup'
383
- ]
384
- };
385
-
386
- // Save report using SettingsManager
387
- const settingsManager = new SettingsManager();
388
- settingsManager.updateSetting('setupReport', report);
389
-
390
- // Also save a local copy for user reference
391
- const reportPath = path.join(process.cwd(), 'i18ntk-setup-report.json');
392
- fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
393
- console.log(` Setup report saved: ${reportPath}`);
394
- }
395
-
396
- generateRecommendations() {
397
- const recommendations = [];
398
-
399
- if (!this.config.prerequisites.hasLocales) {
400
- recommendations.push({
401
- type: 'warning',
402
- message: 'No locale directory found. Run i18ntk-init to create one.',
403
- action: 'i18ntk-init'
404
- });
405
- }
406
-
407
- if (this.config.detectedLanguage === 'javascript' && !this.config.prerequisites.hasI18nLibrary) {
408
- recommendations.push({
409
- type: 'info',
410
- message: 'Consider installing an i18n library for better integration',
411
- action: 'npm install i18next'
412
- });
413
- }
414
-
415
- if (!this.config.prerequisites.nodeVersionValid) {
416
- recommendations.push({
417
- type: 'error',
418
- message: 'Node.js version 16+ required',
419
- action: 'Upgrade Node.js'
420
- });
421
- }
422
-
423
- return recommendations;
424
- }
29
+
425
30
  }
426
31
 
427
32
  // CLI interface
@@ -50,7 +50,7 @@ const SetupEnforcer = require('../utils/setup-enforcer');
50
50
  }
51
51
  })();
52
52
 
53
- loadTranslations(process.env.I18NTK_LANG);
53
+ loadTranslations();
54
54
 
55
55
  // Get configuration from settings manager
56
56
  function getConfig() {
@@ -83,7 +83,7 @@ class I18nSizingAnalyzer {
83
83
 
84
84
  // Initialize i18n with UI language from config
85
85
  const uiLanguage = options.uiLanguage || config.uiLanguage || 'en';
86
- loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'ui-locales'));
86
+ loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'resources', 'i18n', 'ui-locales'));
87
87
  this.stats = {
88
88
  files: {},
89
89
  languages: {},
@@ -179,7 +179,7 @@ class I18nSizingAnalyzer {
179
179
  const stats = SecurityUtils.safeStatSync(langFile, process.cwd());
180
180
  if (!stats) return;
181
181
 
182
- let content = SecurityUtils.safeReadFileSync(langFile, process.cwd());
182
+ let content = SecurityUtils.safeReadFileSync(langFile, process.cwd(), 'utf8');
183
183
  if (typeof content !== "string") content = "";
184
184
  totalSize += stats.size;
185
185
  totalLines += content.split('\n').length;
@@ -203,7 +203,7 @@ class I18nSizingAnalyzer {
203
203
  const stats = SecurityUtils.safeStatSync(filePath, process.cwd());
204
204
  if (!stats) return;
205
205
 
206
- let content = SecurityUtils.safeReadFileSync(filePath, process.cwd());
206
+ let content = SecurityUtils.safeReadFileSync(filePath, process.cwd(), 'utf8');
207
207
  if (typeof content !== "string") content = "";
208
208
  this.stats.files[language] = {
209
209
  file,
@@ -229,7 +229,7 @@ class I18nSizingAnalyzer {
229
229
  if (langFiles) {
230
230
  // Handle nested directory structure - combine all JSON files
231
231
  langFiles.forEach(langFile => {
232
- const rawContent = SecurityUtils.safeReadFileSync(langFile, process.cwd());
232
+ const rawContent = SecurityUtils.safeReadFileSync(langFile, process.cwd(), 'utf8');
233
233
  const fileContent = SecurityUtils.safeParseJSON(rawContent);
234
234
  if (fileContent) {
235
235
  const fileName = path.basename(langFile, '.json');
@@ -238,7 +238,7 @@ class I18nSizingAnalyzer {
238
238
  });
239
239
  } else {
240
240
  // Handle single file structure
241
- const rawContent = SecurityUtils.safeReadFileSync(filePath, process.cwd());
241
+ const rawContent = SecurityUtils.safeReadFileSync(filePath, process.cwd(), 'utf8');
242
242
  combinedContent = SecurityUtils.safeParseJSON(rawContent) || {};
243
243
  }
244
244
 
@@ -19,7 +19,7 @@ const SetupEnforcer = require('../utils/setup-enforcer');
19
19
  }
20
20
  })();
21
21
 
22
- loadTranslations( 'en', path.resolve(__dirname, '..', 'ui-locales'));
22
+ loadTranslations( 'en', path.resolve(__dirname, '..', 'resources', 'i18n', 'ui-locales'));
23
23
 
24
24
 
25
25
  class I18nSummaryReporter {
@@ -54,7 +54,7 @@ class I18nSummaryReporter {
54
54
  this.config = baseConfig;
55
55
 
56
56
  const uiLanguage = this.config.uiLanguage || 'en';
57
- loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'ui-locales'));
57
+ loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'resources', 'i18n', 'ui-locales'));
58
58
 
59
59
  this.sourceDir = this.config.sourceDir;
60
60
 
@@ -112,12 +112,12 @@ class I18nSummaryReporter {
112
112
 
113
113
  // Get all available languages
114
114
  getAvailableLanguages() {
115
- if (!fs.existsSync(this.config.sourceDir)) {
115
+ if (!SecurityUtils.safeExistsSync(this.config.sourceDir, this.config.sourceDir)) {
116
116
  return [];
117
117
  }
118
118
 
119
119
  // Check for monolith JSON files (en.json, es.json, etc.)
120
- const files = fs.readdirSync(this.config.sourceDir);
120
+ const files = SecurityUtils.safeReaddirSync(this.config.sourceDir, this.config.sourceDir) || [];
121
121
  const languages = files
122
122
  .filter(file => file.endsWith('.json'))
123
123
  .map(file => path.basename(file, '.json'));
@@ -126,7 +126,8 @@ class I18nSummaryReporter {
126
126
  const directories = fs.readdirSync(this.config.sourceDir)
127
127
  .filter(item => {
128
128
  const itemPath = path.join(this.config.sourceDir, item);
129
- return fs.statSync(itemPath).isDirectory() &&
129
+ const stats = SecurityUtils.safeStatSync(itemPath, this.config.sourceDir);
130
+ return stats && stats.isDirectory() &&
130
131
  !item.startsWith('.') &&
131
132
  item !== 'node_modules';
132
133
  });
@@ -138,11 +139,11 @@ class I18nSummaryReporter {
138
139
  getLanguageFiles(language) {
139
140
  const languageDir = path.join(this.config.sourceDir, language);
140
141
 
141
- if (!fs.existsSync(languageDir)) {
142
+ if (!SecurityUtils.safeExistsSync(languageDir, this.config.sourceDir)) {
142
143
  return [];
143
144
  }
144
145
 
145
- return fs.readdirSync(languageDir)
146
+ return SecurityUtils.safeReaddirSync(languageDir, this.config.sourceDir) || []
146
147
  .filter(file => {
147
148
  return this.config.supportedExtensions.some(ext => file.endsWith(ext)) &&
148
149
  !this.config.excludeFiles.includes(file);
@@ -153,7 +154,7 @@ class I18nSummaryReporter {
153
154
  // Get file size information
154
155
  getFileSize(filePath) {
155
156
  try {
156
- const stats = fs.statSync(filePath);
157
+ const stats = SecurityUtils.safeStatSync(filePath, this.config.sourceDir);
157
158
  return {
158
159
  size: stats.size,
159
160
  sizeFormatted: this.formatFileSize(stats.size),
@@ -177,10 +178,10 @@ class I18nSummaryReporter {
177
178
  calculateFolderSize(folderPath) {
178
179
  let totalSize = 0;
179
180
  try {
180
- const items = fs.readdirSync(folderPath);
181
+ const items = SecurityUtils.safeReaddirSync(folderPath, this.config.sourceDir) || [];
181
182
  for (const item of items) {
182
183
  const itemPath = path.join(folderPath, item);
183
- const stats = fs.statSync(itemPath);
184
+ const stats = SecurityUtils.safeStatSync(itemPath, this.config.sourceDir);
184
185
  if (stats.isDirectory()) {
185
186
  totalSize += this.calculateFolderSize(itemPath);
186
187
  } else {
@@ -340,7 +341,7 @@ class I18nSummaryReporter {
340
341
  // Calculate folder sizes for each language
341
342
  for (const language of this.stats.languages) {
342
343
  const languageDir = path.join(this.config.sourceDir, language);
343
- if (fs.existsSync(languageDir)) {
344
+ if (SecurityUtils.safeExistsSync(languageDir, this.config.sourceDir)) {
344
345
  this.stats.folderSizes[language] = this.calculateFolderSize(languageDir);
345
346
  }
346
347
  }
@@ -830,7 +831,7 @@ class I18nSummaryReporter {
830
831
  this.config = { ...this.config, ...baseConfig };
831
832
 
832
833
  const uiLanguage = this.config.uiLanguage || 'en';
833
- loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'ui-locales'));
834
+ loadTranslations(uiLanguage, path.resolve(__dirname, '..', 'resources', 'i18n', 'ui-locales'));
834
835
  if (!this.config.sourceDir) {
835
836
  this.config.sourceDir = this.detectI18nDirectory();
836
837
  }
@@ -865,7 +866,7 @@ class I18nSummaryReporter {
865
866
  }
866
867
 
867
868
  // Validate source directory exists
868
- if (!fs.existsSync(this.config.sourceDir)) {
869
+ if (!SecurityUtils.safeExistsSync(this.config.sourceDir, this.config.sourceDir)) {
869
870
  console.error(t('summary.sourceDirectoryDoesNotExist', { sourceDir: this.config.sourceDir }));
870
871
  process.exit(1);
871
872
  }
@@ -898,7 +899,7 @@ class I18nSummaryReporter {
898
899
 
899
900
  // Create output directory if it doesn't exist
900
901
  const outputDir = path.resolve(process.cwd(), 'i18ntk-reports');
901
- if (!fs.existsSync(outputDir)) {
902
+ if (!SecurityUtils.safeExistsSync(outputDir)) {
902
903
  fs.mkdirSync(outputDir, { recursive: true });
903
904
  }
904
905
 
@@ -923,7 +924,7 @@ class I18nSummaryReporter {
923
924
  if (args.outputFile) {
924
925
  // Always save summary reports to i18ntk-reports
925
926
  const reportsDir = path.resolve(process.cwd(), 'i18ntk-reports');
926
- if (!fs.existsSync(reportsDir)) {
927
+ if (!SecurityUtils.safeExistsSync(reportsDir)) {
927
928
  fs.mkdirSync(reportsDir, { recursive: true });
928
929
  }
929
930
  const outputFileName = args.outputFile ? path.basename(args.outputFile) : `summary-report-${new Date().toISOString().slice(0,10)}.txt`;
@@ -943,8 +944,8 @@ class I18nSummaryReporter {
943
944
  console.log(t('summary.cleaningUpReportFiles'));
944
945
  try {
945
946
  const reportsDir = path.join(this.config.sourceDir, 'scripts', 'i18n', 'reports');
946
- if (fs.existsSync(reportsDir)) {
947
- const files = fs.readdirSync(reportsDir);
947
+ if (SecurityUtils.safeExistsSync(reportsDir)) {
948
+ const files = SecurityUtils.safeReaddirSync(reportsDir, this.config.sourceDir) || [];
948
949
  const reportFiles = files.filter(file =>
949
950
  (file.endsWith('.txt') || file.endsWith('.json') || file.endsWith('.log')) &&
950
951
  file !== path.basename(args.outputFile || '')
@@ -953,7 +954,9 @@ class I18nSummaryReporter {
953
954
  let deletedCount = 0;
954
955
  for (const file of reportFiles) {
955
956
  try {
956
- fs.unlinkSync(path.join(reportsDir, file));
957
+ // Note: Using direct fs.unlinkSync as SecurityUtils.safeUnlinkSync doesn't exist yet
958
+ // This should be replaced with a secure version when available
959
+ fs.unlinkSync(path.join(reportsDir, file));
957
960
  deletedCount++;
958
961
  } catch (error) {
959
962
  console.log(t('summary.couldNotDelete', { file, error: error.message }));