i18ntk 1.10.1 → 1.10.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.
package/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
  [![Zero Dependencies](https://img.shields.io/badge/Dependencies-ZERO-red.svg)](https://github.com/vladnoskv/i18ntk#features)
13
13
  [![npm downloads](https://img.shields.io/npm/dt/i18ntk.svg)](https://www.npmjs.com/package/i18ntk)
14
14
  [![GitHub stars](https://img.shields.io/github/stars/vladnoskv/i18ntk?style=social)](https://github.com/vladnoskv/i18ntk)
15
- [![Socket Badge](https://socket.dev/api/badge/npm/package/i18ntk/1.10.1)](https://socket.dev/npm/package/i18ntk/overview/1.10.1)
15
+ [![Socket Badge](https://socket.dev/api/badge/npm/package/i18ntk/1.10.2)](https://socket.dev/npm/package/i18ntk/overview/1.10.2)
16
16
 
17
17
  [📦 Install Now](#-installation) • [⚡ Quick Start](#-quick-start) • [📚 Documentation](#-documentation) • [🎯 Features](#-why-choose-i18ntk)
18
18
 
@@ -22,7 +22,7 @@
22
22
 
23
23
  **15.38ms** for 200k translation keys • **<2MB** memory usage • **97% faster** than traditional tools
24
24
 
25
- **v1.10.1** - Stable & Secure • **v2.0.0** - Coming Soon
25
+ **v1.10.2** - Stable & Secure • **v2.0.0** - Coming Soon
26
26
 
27
27
  </div>
28
28
 
@@ -58,10 +58,16 @@ i18ntk fixer --interactive
58
58
 
59
59
  # 5. Validate everything
60
60
  i18ntk validate
61
+
62
+ # 6. Mangage Mre
61
63
  ```
62
64
 
63
65
  That's it! Your i18n infrastructure is ready. 🎉
64
66
 
67
+ > **🚨 v1.10.2 Update**: Fresh installs now work out-of-the-box! We've fixed the default `projectRoot` path from `"./"` to `"/"` when resetting settings. No more configuration issues on first run!
68
+ >
69
+ > **Migration Note**: If you're upgrading from v1.10.1 or earlier, your existing `projectRoot` settings will remain unchanged. Only new installations or manual resets will use the improved default.
70
+
65
71
  ## 🎯 Why Choose i18ntk?
66
72
 
67
73
  | Feature | i18ntk v1.10.0 | Traditional Tools | Manual Process |
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * I18NTK TRANSLATION ANALYSIS SCRIPT
4
4
  *
@@ -7,7 +7,6 @@
7
7
  *
8
8
  */
9
9
 
10
- const fs = require('fs');
11
10
  const path = require('path');
12
11
  const cliHelper = require('../utils/cli-helper');
13
12
  const { loadTranslations, t } = require('../utils/i18n-helper');
@@ -146,7 +145,12 @@ class I18nAnalyzer {
146
145
  // Get all available languages
147
146
  getAvailableLanguages() {
148
147
  try {
149
- const items = fs.readdirSync(this.sourceDir, { withFileTypes: true });
148
+ const items = SecurityUtils.safeReaddirSync(this.sourceDir, process.cwd(), { withFileTypes: true });
149
+ if (!items) {
150
+ console.error('Error reading source directory: Unable to access directory');
151
+ return [];
152
+ }
153
+
150
154
  const languages = [];
151
155
 
152
156
  // Check for directory-based structure
@@ -173,15 +177,17 @@ class I18nAnalyzer {
173
177
  for (const dir of directories) {
174
178
  const dirPath = path.join(this.sourceDir, dir);
175
179
  try {
176
- const dirItems = fs.readdirSync(dirPath, { withFileTypes: true });
177
- const jsonFiles = dirItems
178
- .filter(item => item.isFile() && item.name.endsWith('.json'))
179
- .map(item => item.name.replace('.json', ''));
180
-
181
- // If directory contains JSON files, it's likely a language directory
182
- if (jsonFiles.length > 0) {
183
- if (!languages.includes(dir)) {
184
- languages.push(dir);
180
+ const dirItems = SecurityUtils.safeReaddirSync(dirPath, process.cwd(), { withFileTypes: true });
181
+ if (dirItems) {
182
+ const jsonFiles = dirItems
183
+ .filter(item => item.isFile() && item.name.endsWith('.json'))
184
+ .map(item => item.name.replace('.json', ''));
185
+
186
+ // If directory contains JSON files, it's likely a language directory
187
+ if (jsonFiles.length > 0) {
188
+ if (!languages.includes(dir)) {
189
+ languages.push(dir);
190
+ }
185
191
  }
186
192
  }
187
193
  } catch (error) {
@@ -208,12 +214,14 @@ class I18nAnalyzer {
208
214
  const files = [];
209
215
 
210
216
  // Handle monolith file structure
211
- if (fs.existsSync(languageFile) && fs.statSync(languageFile).isFile()) {
217
+ const languageFileStat = SecurityUtils.safeStatSync(languageFile, this.sourceDir);
218
+ if (languageFileStat && languageFileStat.isFile()) {
212
219
  return [path.basename(languageFile)];
213
220
  }
214
221
 
215
222
  // Handle directory-based structure
216
- if (fs.existsSync(languageDir) && fs.statSync(languageDir).isDirectory()) {
223
+ const languageDirStat = SecurityUtils.safeStatSync(languageDir, this.sourceDir);
224
+ if (languageDirStat && languageDirStat.isDirectory()) {
217
225
  try {
218
226
  // Ensure the path is within the source directory for security
219
227
  const validatedPath = SecurityUtils.validatePath(languageDir, this.sourceDir);
@@ -224,7 +232,9 @@ class I18nAnalyzer {
224
232
 
225
233
  const findJsonFiles = (dir) => {
226
234
  const results = [];
227
- const items = fs.readdirSync(dir, { withFileTypes: true });
235
+ const items = SecurityUtils.safeReaddirSync(dir, this.sourceDir, { withFileTypes: true });
236
+
237
+ if (!items) return results;
228
238
 
229
239
  for (const item of items) {
230
240
  const fullPath = path.join(dir, item.name);
@@ -267,16 +277,20 @@ class I18nAnalyzer {
267
277
  const searchDir = this.sourceDir;
268
278
 
269
279
  try {
270
- if (fs.existsSync(searchDir)) {
271
- const items = fs.readdirSync(searchDir, { withFileTypes: true });
280
+ const searchDirExists = SecurityUtils.safeExistsSync(searchDir, this.sourceDir);
281
+ if (searchDirExists) {
282
+ const items = SecurityUtils.safeReaddirSync(searchDir, this.sourceDir, { withFileTypes: true });
272
283
 
273
- for (const item of items) {
274
- if (item.isDirectory() && !item.name.startsWith('.') && item.name !== 'node_modules') {
275
- const namespaceDir = path.join(searchDir, item.name);
276
- const namespaceFile = path.join(namespaceDir, `${language}.json`);
277
-
278
- if (fs.existsSync(namespaceFile)) {
279
- results.push(path.relative(path.join(this.sourceDir, item.name), namespaceFile));
284
+ if (items) {
285
+ for (const item of items) {
286
+ if (item.isDirectory() && !item.name.startsWith('.') && item.name !== 'node_modules') {
287
+ const namespaceDir = path.join(searchDir, item.name);
288
+ const namespaceFile = path.join(namespaceDir, `${language}.json`);
289
+
290
+ const namespaceFileExists = SecurityUtils.safeExistsSync(namespaceFile, this.sourceDir);
291
+ if (namespaceFileExists) {
292
+ results.push(path.relative(path.join(this.sourceDir, item.name), namespaceFile));
293
+ }
280
294
  }
281
295
  }
282
296
  }
@@ -468,15 +482,28 @@ class I18nAnalyzer {
468
482
  const sourceFullPath = path.join(this.sourceDir, sourceFilePath);
469
483
  const targetFullPath = path.join(this.sourceDir, targetFilePath);
470
484
 
471
- if (!fs.existsSync(sourceFullPath)) {
485
+ const sourceExists = SecurityUtils.safeExistsSync(sourceFullPath, this.sourceDir);
486
+ if (!sourceExists) {
472
487
  continue;
473
488
  }
474
489
 
475
490
  let sourceContent, targetContent;
476
491
 
477
492
  try {
478
- const sourceFileContent = fs.readFileSync(sourceFullPath, 'utf8');
479
- sourceContent = JSON.parse(sourceFileContent);
493
+ const sourceFileContent = SecurityUtils.safeReadFileSync(sourceFullPath, this.sourceDir, 'utf8');
494
+ if (!sourceFileContent) {
495
+ analysis.files[fileName] = {
496
+ error: `Failed to read source file: File not accessible or empty`
497
+ };
498
+ continue;
499
+ }
500
+ sourceContent = SecurityUtils.safeParseJSON(sourceFileContent);
501
+ if (!sourceContent) {
502
+ analysis.files[fileName] = {
503
+ error: `Failed to parse source file: Invalid JSON format`
504
+ };
505
+ continue;
506
+ }
480
507
  } catch (error) {
481
508
  analysis.files[fileName] = {
482
509
  error: `Failed to parse source file: ${error.message}`
@@ -484,7 +511,8 @@ class I18nAnalyzer {
484
511
  continue;
485
512
  }
486
513
 
487
- if (!fs.existsSync(targetFullPath)) {
514
+ const targetExists = SecurityUtils.safeExistsSync(targetFullPath, this.sourceDir);
515
+ if (!targetExists) {
488
516
  analysis.files[fileName] = {
489
517
  status: 'missing',
490
518
  sourceKeys: this.getAllKeys(sourceContent).size
@@ -493,9 +521,15 @@ class I18nAnalyzer {
493
521
  }
494
522
 
495
523
  try {
496
- const targetFileContent = fs.readFileSync(targetFullPath, 'utf8');
497
- const parsed = JSON.parse(targetFileContent);
498
-
524
+ const targetFileContent = SecurityUtils.safeReadFileSync(targetFullPath, this.sourceDir, 'utf8');
525
+ if (!targetFileContent) {
526
+ analysis.files[fileName] = {
527
+ error: `Failed to read target file: File not accessible or empty`
528
+ };
529
+ continue;
530
+ }
531
+
532
+ const parsed = SecurityUtils.safeParseJSON(targetFileContent);
499
533
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
500
534
  analysis.files[fileName] = {
501
535
  error: `Invalid structure in target file: must be a plain object (not array/null/type)`
@@ -644,13 +678,10 @@ try {
644
678
  }
645
679
 
646
680
  // Ensure the output directory exists
647
- try {
648
- fs.mkdirSync(this.outputDir, { recursive: true });
649
- } catch (error) {
650
- if (error.code !== 'EEXIST') {
651
- console.error(`Failed to create output directory ${this.outputDir}:`, error.message);
652
- return null;
653
- }
681
+ const dirCreated = SecurityUtils.safeMkdirSync(this.outputDir, process.cwd(), { recursive: true });
682
+ if (!dirCreated) {
683
+ console.error(`Failed to create output directory ${this.outputDir}`);
684
+ return null;
654
685
  }
655
686
 
656
687
  // Validate the output directory is within the project
@@ -670,14 +701,10 @@ try {
670
701
  return null;
671
702
  }
672
703
 
673
- // Use safeWriteFile if available, otherwise fall back to writeFileSync
674
- if (SecurityUtils.safeWriteFile) {
675
- const success = await SecurityUtils.safeWriteFile(reportPath, report, this.outputDir);
676
- if (!success) {
677
- throw new Error(t('analyze.failedToWriteReportFile') || 'Failed to write report file securely');
678
- }
679
- } else {
680
- fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf8');
704
+ // Use safeWriteFile for secure file writing
705
+ const success = await SecurityUtils.safeWriteFile(reportPath, JSON.stringify(report, null, 2), process.cwd(), 'utf8');
706
+ if (!success) {
707
+ throw new Error(t('analyze.failedToWriteReportFile') || 'Failed to write report file securely');
681
708
  }
682
709
 
683
710
  console.log(`Report saved to: ${reportPath}`);
@@ -709,8 +736,9 @@ try {
709
736
  }
710
737
 
711
738
  // Ensure output directory exists
712
- if (!fs.existsSync(this.outputDir)) {
713
- fs.mkdirSync(this.outputDir, { recursive: true });
739
+ const outputDirExists = SecurityUtils.safeExistsSync(this.outputDir, process.cwd());
740
+ if (!outputDirExists) {
741
+ SecurityUtils.safeMkdirSync(this.outputDir, process.cwd(), { recursive: true });
714
742
  }
715
743
 
716
744
  const languages = this.getAvailableLanguages();
@@ -1100,7 +1128,14 @@ async function analyzeTranslations(datasetPath) {
1100
1128
  analyzer.outputDir = './reports';
1101
1129
 
1102
1130
  // Load and analyze the dataset
1103
- const dataset = JSON.parse(fs.readFileSync(datasetPath, 'utf8'));
1131
+ const datasetContent = SecurityUtils.safeReadFileSync(datasetPath, process.cwd(), 'utf8');
1132
+ if (!datasetContent) {
1133
+ throw new Error('Failed to load dataset for benchmark');
1134
+ }
1135
+ const dataset = SecurityUtils.safeParseJSON(datasetContent);
1136
+ if (!dataset) {
1137
+ throw new Error('Failed to parse dataset JSON');
1138
+ }
1104
1139
 
1105
1140
  // Simulate analysis processing
1106
1141
  const languages = Object.keys(dataset).filter(lang => lang !== 'en');
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  'use strict';
4
4
 
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * I18NTK INITIALIZATION SCRIPT
4
4
  *
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * I18NTK MANAGEMENT TOOLKIT - MAIN MANAGER
4
4
  *
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  * i18ntk-setup.js - Foundational Setup Script
@@ -334,6 +334,15 @@ class I18nSetupManager {
334
334
  const SettingsManager = require('../settings/settings-manager');
335
335
  const settingsManager = new SettingsManager();
336
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
+
337
346
  settingsManager.updateSettings({
338
347
  'sourceDir': this.config.sourceDir,
339
348
  'outputDir': this.config.outputDir,
@@ -33,7 +33,6 @@
33
33
 
34
34
  const fs = require('fs');
35
35
  const path = require('path');
36
- const { performance } = require('perf_hooks');
37
36
  const { loadTranslations, t } = require('../utils/i18n-helper');
38
37
  const configManager = require('../settings/settings-manager');
39
38
  const SecurityUtils = require('../utils/security');
@@ -116,23 +115,24 @@ class I18nSizingAnalyzer {
116
115
  throw new Error(t("sizing.invalidSourceDirectoryError", { sourceDir: this.sourceDir }));
117
116
  }
118
117
 
119
- if (!fs.existsSync(validatedSourceDir)) {
118
+ if (!SecurityUtils.safeExistsSync(validatedSourceDir)) {
120
119
  throw new Error(t("sizing.sourceDirectoryNotFoundError", { sourceDir: validatedSourceDir }));
121
120
  }
122
121
 
123
122
  const files = [];
124
- const items = fs.readdirSync(validatedSourceDir);
123
+ const items = SecurityUtils.safeReaddirSync(validatedSourceDir);
125
124
 
126
125
  // Check for nested language directories
127
126
  for (const item of items) {
128
127
  const itemPath = SecurityUtils.validatePath(path.join(validatedSourceDir, item), process.cwd());
129
128
  if (!itemPath) continue;
130
129
 
131
- const stat = fs.statSync(itemPath);
130
+ const stat = SecurityUtils.safeStatSync(itemPath);
131
+ if (!stat) continue;
132
132
 
133
133
  if (stat.isDirectory()) {
134
134
  // This is a language directory, combine all JSON files
135
- const langFiles = fs.readdirSync(itemPath)
135
+ const langFiles = SecurityUtils.safeReaddirSync(itemPath)
136
136
  .filter(file => file.endsWith('.json'))
137
137
  .map(file => SecurityUtils.validatePath(path.join(itemPath, file), process.cwd()))
138
138
  .filter(file => file !== null);
@@ -165,7 +165,7 @@ class I18nSizingAnalyzer {
165
165
 
166
166
  // Analyze file sizes
167
167
  analyzeFileSizes(files) {
168
- console.log(t("sizing.analyzing_file_sizes"));
168
+ SecurityUtils.debugLog('info', t("sizing.analyzing_file_sizes"));
169
169
 
170
170
  files.forEach(({ language, file, path: filePath, files: langFiles }) => {
171
171
  if (langFiles) {
@@ -176,7 +176,9 @@ class I18nSizingAnalyzer {
176
176
  let lastModified = new Date(0);
177
177
 
178
178
  langFiles.forEach(langFile => {
179
- const stats = fs.statSync(langFile);
179
+ const stats = SecurityUtils.safeStatSync(langFile, process.cwd());
180
+ if (!stats) return;
181
+
180
182
  let content = SecurityUtils.safeReadFileSync(langFile, process.cwd());
181
183
  if (typeof content !== "string") content = "";
182
184
  totalSize += stats.size;
@@ -198,7 +200,9 @@ class I18nSizingAnalyzer {
198
200
  };
199
201
  } else {
200
202
  // Handle single file structure
201
- const stats = fs.statSync(filePath);
203
+ const stats = SecurityUtils.safeStatSync(filePath, process.cwd());
204
+ if (!stats) return;
205
+
202
206
  let content = SecurityUtils.safeReadFileSync(filePath, process.cwd());
203
207
  if (typeof content !== "string") content = "";
204
208
  this.stats.files[language] = {
@@ -216,7 +220,7 @@ class I18nSizingAnalyzer {
216
220
 
217
221
  // Analyze translation content
218
222
  analyzeTranslationContent(files) {
219
- console.log(t("sizing.analyzing_translation_content"));
223
+ SecurityUtils.debugLog('info', t("sizing.analyzing_translation_content"));
220
224
 
221
225
  files.forEach(({ language, path: filePath, files: langFiles }) => {
222
226
  try {
@@ -262,7 +266,7 @@ class I18nSizingAnalyzer {
262
266
  });
263
267
 
264
268
  } catch (error) {
265
- console.error(t("sizing.failed_to_parse_language_error", { language, errorMessage: error.message }));
269
+ SecurityUtils.debugLog('error', t("sizing.failed_to_parse_language_error", { language, errorMessage: error.message }));
266
270
  }
267
271
  });
268
272
  }
@@ -312,13 +316,13 @@ class I18nSizingAnalyzer {
312
316
 
313
317
  // Generate size comparison analysis
314
318
  generateSizeComparison() {
315
- console.log(t("sizing.generating_size_comparisons"));
319
+ SecurityUtils.debugLog('info', t("sizing.generating_size_comparisons"));
316
320
 
317
321
  const languages = Object.keys(this.stats.languages);
318
322
  const baseLanguage = languages[0]; // Use first language as baseline
319
323
 
320
324
  if (!baseLanguage) {
321
- console.warn(t("sizing.no_languages_found_for_comparison"));
325
+ SecurityUtils.debugLog('warn', t("sizing.no_languages_found_for_comparison"));
322
326
  return;
323
327
  }
324
328
 
@@ -491,7 +495,7 @@ class I18nSizingAnalyzer {
491
495
  async generateHumanReadableReport() {
492
496
  if (!this.outputReport) return;
493
497
 
494
- console.log(t("sizing.generating_detailed_report"));
498
+ SecurityUtils.debugLog('info', t("sizing.generating_detailed_report"));
495
499
 
496
500
  const validatedOutputDir = SecurityUtils.validatePath(this.outputDir, process.cwd());
497
501
  if (!validatedOutputDir) {
@@ -499,8 +503,8 @@ class I18nSizingAnalyzer {
499
503
  }
500
504
 
501
505
  // Ensure output directory exists
502
- if (!fs.existsSync(validatedOutputDir)) {
503
- fs.mkdirSync(validatedOutputDir, { recursive: true });
506
+ if (!SecurityUtils.safeExistsSync(validatedOutputDir)) {
507
+ SecurityUtils.safeMkdirSync(validatedOutputDir, { recursive: true });
504
508
  }
505
509
 
506
510
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
@@ -514,7 +518,7 @@ class I18nSizingAnalyzer {
514
518
  let textReport = this.generateTextReport(timestamp);
515
519
  const textSuccess = await SecurityUtils.safeWriteFile(textReportPath, textReport, process.cwd());
516
520
  if (textSuccess) {
517
- console.log(t("sizing.human_report_saved", { reportPath: textReportPath }));
521
+ SecurityUtils.debugLog('info', t("sizing.human_report_saved", { reportPath: textReportPath }));
518
522
  }
519
523
 
520
524
  // Generate JSON for programmatic access
@@ -660,7 +664,7 @@ Generated: ${new Date().toISOString()}
660
664
 
661
665
  const success = await SecurityUtils.safeWriteFile(csvPath, csvContent, process.cwd());
662
666
  if (success) {
663
- console.log(t("sizing.csv_report_saved_to", { csvPath }));
667
+ SecurityUtils.debugLog('info', t("sizing.csv_report_saved_to", { csvPath }));
664
668
  SecurityUtils.logSecurityEvent('CSV report saved', 'info', { csvPath });
665
669
  } else {
666
670
  throw new Error(t("sizing.failedToSaveCsvError"));
@@ -669,20 +673,21 @@ Generated: ${new Date().toISOString()}
669
673
 
670
674
  // Main analysis method
671
675
  async analyze() {
672
- const startTime = performance.now();
676
+ const perfTimer = SecurityUtils.getPerformanceTimer();
677
+ const startTime = perfTimer.now();
673
678
 
674
679
  try {
675
- console.log(t("sizing.starting_i18n_sizing_analysis"));
676
- console.log(t("sizing.source_directory", { sourceDir: this.sourceDir }));
680
+ SecurityUtils.debugLog('info', t("sizing.starting_i18n_sizing_analysis"));
681
+ SecurityUtils.debugLog('info', t("sizing.source_directory", { sourceDir: this.sourceDir }));
677
682
 
678
683
  const files = this.getLanguageFiles();
679
684
 
680
685
  if (files.length === 0) {
681
- console.log(t("sizing.no_translation_files_found"));
686
+ SecurityUtils.debugLog('warn', t("sizing.no_translation_files_found"));
682
687
  return;
683
688
  }
684
689
 
685
- console.log(t("sizing.found_languages", { languages: files.map(f => f.language).join(', ') }));
690
+ SecurityUtils.debugLog('info', t("sizing.found_languages", { languages: files.map(f => f.language).join(', ') }));
686
691
 
687
692
  this.analyzeFileSizes(files);
688
693
  this.analyzeTranslationContent(files);
@@ -691,16 +696,16 @@ Generated: ${new Date().toISOString()}
691
696
  if (this.format === 'table') {
692
697
  this.displayFolderResults();
693
698
  } else if (this.format === 'json') {
694
- console.log(t("sizing.analysisStats", { stats: JSON.stringify(this.stats, null, 2) }));
699
+ SecurityUtils.debugLog('info', t("sizing.analysisStats", { stats: JSON.stringify(this.stats, null, 2) }));
695
700
  }
696
701
 
697
702
  await this.generateHumanReadableReport();
698
703
 
699
- const endTime = performance.now();
700
- console.log(t("sizing.analysis_completed", { duration: (endTime - startTime).toFixed(2) }));
704
+ const endTime = perfTimer.now();
705
+ SecurityUtils.debugLog('info', t("sizing.analysis_completed", { duration: (endTime - startTime).toFixed(2) }));
701
706
 
702
707
  } catch (error) {
703
- console.error(t("sizing.analysis_failed", { errorMessage: error.message }));
708
+ SecurityUtils.debugLog('error', t("sizing.analysis_failed", { errorMessage: error.message }));
704
709
  process.exit(1);
705
710
  }
706
711
  }
@@ -901,19 +906,20 @@ Options:
901
906
  // Main analysis method
902
907
  async analyze() {
903
908
  try {
904
- console.log(t("sizing.starting_analysis"));
905
- console.log(t("sizing.source_directory", { sourceDir: this.sourceDir }));
909
+ SecurityUtils.debugLog('info', t("sizing.starting_analysis"));
910
+ SecurityUtils.debugLog('info', t("sizing.source_directory", { sourceDir: this.sourceDir }));
906
911
 
907
- const startTime = performance.now();
912
+ const perfTimer = SecurityUtils.getPerformanceTimer();
913
+ const startTime = perfTimer.now();
908
914
 
909
915
  // Get language files
910
916
  const files = this.getLanguageFiles();
911
917
  if (files.length === 0) {
912
- console.warn(t("sizing.no_translation_files_found"));
918
+ SecurityUtils.debugLog('warn', t("sizing.no_translation_files_found"));
913
919
  return { success: false, error: "No translation files found" };
914
920
  }
915
921
 
916
- console.log(t("sizing.found_files", { count: files.length }));
922
+ SecurityUtils.debugLog('info', t("sizing.found_files", { count: files.length }));
917
923
 
918
924
  // Analyze file sizes
919
925
  this.analyzeFileSizes(files);
@@ -930,15 +936,15 @@ Options:
930
936
  // Generate reports if requested
931
937
  await this.generateHumanReadableReport();
932
938
 
933
- const endTime = performance.now();
939
+ const endTime = perfTimer.now();
934
940
  const duration = ((endTime - startTime) / 1000).toFixed(2);
935
941
 
936
- console.log(t("sizing.analysis_completed", { duration }));
942
+ SecurityUtils.debugLog('info', t("sizing.analysis_completed", { duration }));
937
943
 
938
944
  return { success: true, stats: this.stats };
939
945
 
940
946
  } catch (error) {
941
- console.error(t("sizing.analysis_failed", { errorMessage: error.message }));
947
+ SecurityUtils.debugLog('error', t("sizing.analysis_failed", { errorMessage: error.message }));
942
948
  return { success: false, error: error.message };
943
949
  }
944
950
  }
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * I18NTK USAGE ANALYSIS TOOLKIT - Version 1.8.3
4
4
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18ntk",
3
- "version": "1.10.1",
3
+ "version": "1.10.2",
4
4
  "description": "🚀 The fastest i18n toolkit with 97% performance boost! Zero-dependency, enterprise-grade internationalization for React, Vue, Angular, Python, Java, PHP & more. Features PIN protection, auto framework detection, 7+ UI languages, and comprehensive translation management. Perfect for startups to enterprises.",
5
5
  "keywords": [
6
6
  "i18n",
@@ -213,8 +213,8 @@
213
213
  },
214
214
  "preferGlobal": true,
215
215
  "versionInfo": {
216
- "version": "1.10.1",
217
- "releaseDate": "22/08/2025",
216
+ "version": "1.10.2",
217
+ "releaseDate": "23/08/2025",
218
218
  "lastUpdated": "23/08/2025",
219
219
  "maintainer": "Vladimir Noskov",
220
220
  "changelog": "./CHANGELOG.md",
@@ -283,6 +283,5 @@
283
283
  "laravel": ">=8.0.0"
284
284
  }
285
285
  },
286
- "dependencies": {},
287
286
  "_comment": "This package is zero-dependency and uses only native Node.js modules"
288
287
  }