i18ntk 2.0.4 → 2.2.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 (57) hide show
  1. package/README.md +38 -60
  2. package/main/i18ntk-analyze.js +49 -44
  3. package/main/i18ntk-complete.js +75 -74
  4. package/main/i18ntk-fixer.js +3 -3
  5. package/main/i18ntk-init.js +5 -5
  6. package/main/i18ntk-scanner.js +2 -2
  7. package/main/i18ntk-sizing.js +35 -35
  8. package/main/i18ntk-summary.js +4 -4
  9. package/main/i18ntk-ui.js +54 -8
  10. package/main/i18ntk-usage.js +14 -14
  11. package/main/i18ntk-validate.js +6 -5
  12. package/main/manage/commands/AnalyzeCommand.js +40 -35
  13. package/main/manage/commands/FixerCommand.js +2 -2
  14. package/main/manage/commands/ScannerCommand.js +2 -2
  15. package/main/manage/commands/ValidateCommand.js +9 -9
  16. package/main/manage/index.js +147 -75
  17. package/main/manage/managers/LanguageMenu.js +7 -2
  18. package/main/manage/services/UsageService.js +7 -7
  19. package/package.json +269 -290
  20. package/settings/settings-cli.js +3 -3
  21. package/ui-locales/de.json +161 -166
  22. package/ui-locales/en.json +13 -18
  23. package/ui-locales/es.json +171 -184
  24. package/ui-locales/fr.json +155 -161
  25. package/ui-locales/ja.json +192 -243
  26. package/ui-locales/ru.json +145 -196
  27. package/ui-locales/zh.json +179 -185
  28. package/utils/cli-helper.js +26 -98
  29. package/utils/extractors/regex.js +39 -12
  30. package/utils/i18n-helper.js +88 -40
  31. package/{scripts → utils}/locale-optimizer.js +61 -60
  32. package/utils/security-check-improved.js +16 -13
  33. package/utils/security.js +6 -4
  34. package/main/i18ntk-go.js +0 -283
  35. package/main/i18ntk-java.js +0 -380
  36. package/main/i18ntk-js.js +0 -512
  37. package/main/i18ntk-manage.js +0 -1694
  38. package/main/i18ntk-php.js +0 -462
  39. package/main/i18ntk-py.js +0 -379
  40. package/main/i18ntk-settings.js +0 -23
  41. package/main/manage/index-fixed.js +0 -1447
  42. package/main/manage/services/ConfigurationService-fixed.js +0 -449
  43. package/scripts/build-lite.js +0 -279
  44. package/scripts/deprecate-versions.js +0 -317
  45. package/scripts/export-translations.js +0 -84
  46. package/scripts/fix-all-i18n.js +0 -215
  47. package/scripts/fix-and-purify-i18n.js +0 -213
  48. package/scripts/fix-locale-control-chars.js +0 -110
  49. package/scripts/lint-locales.js +0 -80
  50. package/scripts/prepublish.js +0 -348
  51. package/scripts/security-check.js +0 -117
  52. package/scripts/sync-translations.js +0 -151
  53. package/scripts/sync-ui-locales.js +0 -20
  54. package/scripts/validate-all-translations.js +0 -139
  55. package/scripts/verify-deprecations.js +0 -157
  56. package/scripts/verify-translations.js +0 -63
  57. package/utils/security-fixed.js +0 -607
@@ -1,449 +0,0 @@
1
- /**
2
- * Configuration Service
3
- * Handles configuration management, initialization, and settings integration
4
- * @module services/ConfigurationService
5
- */
6
-
7
- const path = require('path');
8
- const configManager = require('../../../settings/settings-manager');
9
- const { loadTranslations, t, refreshLanguageFromSettings } = require('../../../utils/i18n-helper');
10
-
11
- const { createPrompt, isInteractive } = require('../../../utils/prompt-helper');
12
- const { loadConfig, saveConfig, ensureConfigDefaults } = require('../../../utils/config');
13
- const { getUnifiedConfig, ensureInitialized, validateSourceDir } = require('../../../utils/config-helper');
14
- const cliHelper = require('../../../utils/cli-helper');
15
- const pkg = require('../../../package.json');
16
- const SetupEnforcer = require('../../../utils/setup-enforcer');
17
-
18
- module.exports = class ConfigurationService {
19
- constructor(config = {}) {
20
- this.config = config;
21
- this.settings = null;
22
- this.configManager = configManager;
23
- this.ui = null;
24
- this.rl = null;
25
- this.isReadlineClosed = false;
26
- }
27
-
28
- /**
29
- * Initialize the service with required dependencies
30
- * @param {Object} configManager - Configuration manager instance
31
- */
32
- initialize(configManager) {
33
- this.configManager = configManager || this.configManager;
34
- this.settings = this.configManager.loadSettings ? this.configManager.loadSettings() : (this.configManager.getConfig ? this.configManager.getConfig() : {});
35
- }
36
-
37
- /**
38
- * Initialize configuration using unified system
39
- * @param {Object} options - Initialization options
40
- * @returns {Promise<Object>} Initialization result
41
- */
42
- async initialize(options = {}) {
43
- try {
44
- // Parse args here for other initialization needs (but language is already loaded)
45
- const args = this.parseArgs();
46
- if (args.help) {
47
- this.showHelp();
48
- process.exit(0);
49
- }
50
-
51
- // Load translations for the UI language
52
- const settings = this.settings || (this.configManager.loadSettings ? this.configManager.loadSettings() : (this.configManager.getConfig ? this.configManager.getConfig() : {}));
53
- const uiLanguage = args.uiLanguage || settings.uiLanguage || settings.language || this.config.uiLanguage || 'en';
54
- loadTranslations(uiLanguage);
55
-
56
- // Validate source directory exists
57
- const { validateSourceDir, displayPaths } = require('../../../utils/config-helper');
58
- try {
59
- validateSourceDir(this.config.sourceDir, 'i18ntk-manage');
60
- } catch (err) {
61
- console.log(t('init.requiredTitle'));
62
- console.log(t('init.requiredBody'));
63
- const answer = await cliHelper.prompt(t('init.promptRunNow'));
64
- if (answer.trim().toLowerCase() === 'y') {
65
- // Note: Initialization should be handled by the calling code
66
- // to avoid circular dependencies
67
- console.log('Please run initialization manually or use the init command');
68
- } else {
69
- throw err;
70
- }
71
- }
72
-
73
- } catch (error) {
74
- throw error;
75
- }
76
- }
77
-
78
- /**
79
- * Run the main configuration and initialization flow
80
- * @returns {Promise<Object>} Configuration result
81
- */
82
- async run() {
83
- // Add timeout to prevent hanging
84
- const args = this.parseArgs();
85
-
86
- const timeout = setTimeout(() => {
87
- console.error('❌ CLI startup timeout - something is hanging');
88
- if (args.debug) {
89
- console.error('🔍 DEBUG: Last known execution point reached');
90
- }
91
- process.exit(1);
92
- }, 10000); // 10 second timeout
93
-
94
- if (args.debug) {
95
- console.log('🔍 DEBUG: Starting configuration service...');
96
- console.log('🔍 DEBUG: Process.argv:', process.argv);
97
- console.log('🔍 DEBUG: Parsed args:', args);
98
- }
99
-
100
- let prompt;
101
- try {
102
- // Ensure setup is complete before running any operations
103
- await SetupEnforcer.checkSetupCompleteAsync();
104
-
105
- prompt = createPrompt({ noPrompt: args.noPrompt || Boolean(args.adminPin) });
106
- const interactive = isInteractive({ noPrompt: args.noPrompt || Boolean(args.adminPin) });
107
-
108
- // Load settings and UI language
109
- const settings = this.settings || (this.configManager.loadSettings ? this.configManager.loadSettings() : (this.configManager.getConfig ? this.configManager.getConfig() : {}));
110
- const uiLanguage = args.uiLanguage || settings.uiLanguage || settings.language || this.config.uiLanguage || 'en';
111
- loadTranslations(uiLanguage);
112
-
113
- if (args.adminPin) {
114
- // Handle admin PIN mode
115
- this.prompt = async () => '';
116
- }
117
-
118
- if (args.help) {
119
- this.showHelp();
120
- return;
121
- }
122
-
123
- let cfgAfterInitCheck = {};
124
- if (interactive) {
125
- cfgAfterInitCheck = await this.ensureInitializedOrExit(prompt);
126
- const frameworksDetected = await this.checkI18nDependencies();
127
- if (!frameworksDetected) {
128
- await this.maybePromptFramework(prompt, cfgAfterInitCheck, pkg.version);
129
- }
130
- }
131
-
132
- this.config = { ...this.config, ...cfgAfterInitCheck };
133
- await this.initialize();
134
-
135
- return { config: this.config, settings, ui: null, prompt };
136
-
137
- } catch (error) {
138
- if (this.ui && this.ui.t) {
139
- console.error(t('common.genericError', { error: error.message }));
140
- } else {
141
- console.error(`Error: ${error.message}`);
142
- }
143
- process.exit(1);
144
- } finally {
145
- if (prompt && typeof prompt.close === 'function') {
146
- prompt.close();
147
- }
148
- this.safeClose();
149
- }
150
- }
151
-
152
- /**
153
- * Ensures the project is properly initialized or exits the process
154
- * @param {Object} prompt - Prompt interface for user interaction
155
- * @returns {Promise<Object>} Configuration object if initialized
156
- */
157
- async ensureInitializedOrExit(prompt) {
158
- const { checkInitialized } = require('../../../utils/init-helper');
159
- const cliHelper = require('../../../utils/cli-helper');
160
- const pkg = require('../../../package.json');
161
-
162
- const { initialized, config } = await checkInitialized();
163
-
164
- if (!initialized) {
165
- console.log('\nThis project is not yet initialized with i18ntk.');
166
- const shouldInitialize = await cliHelper.confirm('Would you like to initialize it now?');
167
-
168
- if (!shouldInitialize) {
169
- console.log('Exiting. Please initialize the project first.');
170
- process.exit(1);
171
- }
172
-
173
- // The initialization will be handled by the init command
174
- return config;
175
- }
176
-
177
- // Check if we need to prompt for framework detection
178
- const settings = this.settings || (this.configManager.loadSettings ? this.configManager.loadSettings() : (this.configManager.getConfig ? this.configManager.getConfig() : {}));
179
-
180
- // Ensure framework configuration exists with all required fields
181
- if (!settings.framework) {
182
- settings.framework = {
183
- detected: false,
184
- preference: null,
185
- prompt: 'always',
186
- lastPromptedVersion: null,
187
- installed: [],
188
- version: '1.0' // Schema version for future compatibility
189
- };
190
- }
191
-
192
- // Check if we need to prompt for framework detection
193
- if (!settings.framework.detected &&
194
- settings.framework.prompt !== 'suppress' &&
195
- settings.framework.lastPromptedVersion !== pkg.version) {
196
-
197
- console.log('\nWe noticed you haven\'t set up an i18n framework yet.');
198
- console.log('Would you like to detect your i18n framework automatically?');
199
-
200
- console.log('1. Detect automatically');
201
- console.log('2. I\'ll set it up manually');
202
- console.log('3. Don\'t show this again');
203
-
204
- const answer = await prompt.question('\nSelect an option (1-3): ');
205
- const choice = answer.trim();
206
-
207
- let action;
208
- if (choice === '1') action = 'detect';
209
- else if (choice === '2') action = 'manual';
210
- else if (choice === '3') action = 'dont-show';
211
- else action = 'manual'; // default fallback
212
-
213
- if (action === 'dont-show') {
214
- // Update settings to suppress future prompts for this version
215
- settings.framework.prompt = 'suppress';
216
- settings.framework.lastPromptedVersion = pkg.version;
217
-
218
- if (this.configManager.saveSettings) {
219
- await this.configManager.saveSettings(settings);
220
- } else if (this.configManager.saveConfig) {
221
- await this.configManager.saveConfig(settings);
222
- }
223
-
224
- console.log('Framework detection prompt will be suppressed for this version.');
225
- } else if (action === 'detect') {
226
- // Run framework detection
227
- const FrameworkDetectionService = require('./FrameworkDetectionService');
228
- const frameworkService = new FrameworkDetectionService();
229
- frameworkService.initialize(this.configManager);
230
-
231
- const { detectedLanguage, detectedFramework } = await frameworkService.detectEnvironmentAndFramework();
232
-
233
- if (detectedFramework && detectedFramework !== 'generic') {
234
- console.log(`\nDetected framework: ${detectedFramework}`);
235
-
236
- // Update settings with detected framework
237
- settings.framework.detected = true;
238
- settings.framework.preference = detectedFramework;
239
- settings.framework.lastDetected = new Date().toISOString();
240
-
241
- if (this.configManager.saveSettings) {
242
- await this.configManager.saveSettings(settings);
243
- } else if (this.configManager.saveConfig) {
244
- await this.configManager.saveConfig(settings);
245
- }
246
-
247
- console.log(`Framework set to: ${detectedFramework}`);
248
- } else {
249
- console.log('\nCould not detect a specific i18n framework.');
250
- console.log('Please set up your i18n framework manually.');
251
- }
252
- }
253
- }
254
-
255
- return { ...config, ...settings };
256
- }
257
-
258
- /**
259
- * Check if i18n framework is installed - configuration-based check without prompts
260
- * @returns {Promise<boolean>} True if frameworks detected, false otherwise
261
- */
262
- async checkI18nDependencies() {
263
- const FrameworkDetectionService = require('./FrameworkDetectionService');
264
- const frameworkService = new FrameworkDetectionService();
265
- frameworkService.initialize(this.configManager);
266
- return await frameworkService.checkI18nDependencies(null);
267
- }
268
-
269
- /**
270
- * Handle framework detection and prompting logic
271
- * @param {Object} prompt - Prompt interface for user interaction
272
- * @param {Object} cfg - Configuration object
273
- * @param {string} currentVersion - Current version of the tool
274
- * @returns {Promise<Object>} Updated configuration
275
- */
276
- async maybePromptFramework(prompt, cfg, currentVersion) {
277
- const FrameworkDetectionService = require('./FrameworkDetectionService');
278
- const frameworkService = new FrameworkDetectionService();
279
- frameworkService.initialize(this.configManager);
280
- return await frameworkService.maybePromptFramework(prompt, cfg, currentVersion);
281
- }
282
-
283
- /**
284
- * Parse command line arguments
285
- * @returns {Object} Parsed arguments
286
- */
287
- parseArgs() {
288
- const args = process.argv.slice(2);
289
- const parsed = {};
290
-
291
- args.forEach(arg => {
292
- if (arg.startsWith('--')) {
293
- const [key, value] = arg.substring(2).split('=');
294
- const sanitizedKey = key?.trim();
295
- const sanitizedValue = value !== undefined ? value.trim() : true;
296
-
297
- switch (sanitizedKey) {
298
- case 'source-dir':
299
- parsed.sourceDir = sanitizedValue;
300
- break;
301
- case 'i18n-dir':
302
- parsed.i18nDir = sanitizedValue;
303
- break;
304
- case 'output-dir':
305
- parsed.outputDir = sanitizedValue;
306
- break;
307
- case 'source-language':
308
- parsed.sourceLanguage = sanitizedValue;
309
- break;
310
- case 'ui-language':
311
- parsed.uiLanguage = sanitizedValue;
312
- break;
313
- case 'no-prompt':
314
- parsed.noPrompt = true;
315
- break;
316
- case 'admin-pin':
317
- parsed.adminPin = sanitizedValue || '';
318
- break;
319
- case 'help':
320
- case 'h':
321
- parsed.help = true;
322
- break;
323
- default:
324
- // Handle language shorthand flags like --de, --fr
325
- if (['en', 'de', 'es', 'fr', 'ru', 'ja', 'zh'].includes(sanitizedKey)) {
326
- parsed.uiLanguage = sanitizedKey;
327
- }
328
- break;
329
- }
330
- }
331
- });
332
-
333
- return parsed;
334
- }
335
-
336
- /**
337
- * Show help information
338
- */
339
- showHelp() {
340
- const localT = (key) => {
341
- // Fallback help text when UI is not initialized
342
- const helpTexts = {
343
- 'help.usage': 'Usage: npm run i18ntk [command] [options]',
344
- 'help.interactiveMode': 'Run without arguments for interactive mode',
345
- 'help.initProject': ' init - Initialize i18n project structure',
346
- 'help.analyzeTranslations': ' analyze - Analyze translation files',
347
- 'help.validateTranslations': ' validate - Validate translations for errors',
348
- 'help.checkUsage': ' usage - Check translation usage in code',
349
- 'help.showHelp': ' help - Show this help message',
350
- 'help.availableCommands': '\nAvailable commands:',
351
- 'help.initCommand': ' --command=init Initialize i18n project',
352
- 'help.analyzeCommand': ' --command=analyze Analyze translations',
353
- 'help.validateCommand': ' --command=validate Validate translations',
354
- 'help.usageCommand': ' --command=usage Check translation usage',
355
- 'help.sizingCommand': ' --command=sizing Analyze translation sizing',
356
- 'help.completeCommand': ' --command=complete Run complete analysis',
357
- 'help.summaryCommand': ' --command=summary Generate summary report',
358
- 'help.debugCommand': ' --command=debug Run debug utilities',
359
- 'help.scannerCommand': ' --command=scanner Scan for translation keys'
360
- };
361
- return helpTexts[key] || key;
362
- };
363
-
364
- console.log(t('help.usage'));
365
- console.log(t('help.interactiveMode'));
366
- console.log(t('help.initProject'));
367
- console.log(t('help.analyzeTranslations'));
368
- console.log(t('help.validateTranslations'));
369
- console.log(t('help.checkUsage'));
370
- console.log(t('help.showHelp'));
371
- console.log(t('help.availableCommands'));
372
- console.log(t('help.initCommand'));
373
- console.log(t('help.analyzeCommand'));
374
- console.log(t('help.validateCommand'));
375
- console.log(t('help.usageCommand'));
376
- console.log(t('help.sizingCommand'));
377
- console.log(t('help.completeCommand'));
378
- console.log(t('help.summaryCommand'));
379
- console.log(t('help.debugCommand'));
380
- console.log(t('help.scannerCommand'));
381
-
382
- // Ensure proper exit for direct command execution
383
- if (process.argv.includes('--help') || process.argv.includes('-h')) {
384
- this.safeClose();
385
- process.exit(0);
386
- }
387
- }
388
-
389
- /**
390
- * Prompt user for input with fallback for non-interactive mode
391
- * @param {string} question - Question to ask
392
- * @returns {Promise<string>} User input or empty string
393
- */
394
- prompt(question) {
395
- const cliHelper = require('../../../utils/cli-helper');
396
- // If interactive not available, return empty string to avoid hangs
397
- if (!process.stdin.isTTY || process.stdin.destroyed) {
398
- console.log('\n⚠️ Interactive input not available, using default response.');
399
- return Promise.resolve('');
400
- }
401
- return cliHelper.prompt(`${question} `);
402
- }
403
-
404
- /**
405
- * Check if we're in non-interactive mode
406
- * @returns {boolean} True if in non-interactive mode
407
- */
408
- isNonInteractiveMode() {
409
- return !process.stdin.isTTY || process.stdin.destroyed || this.isReadlineClosed;
410
- }
411
-
412
- /**
413
- * Safe method to close readline interface
414
- */
415
- safeClose() {
416
- if (this.rl && !this.isReadlineClosed) {
417
- try {
418
- this.rl.close();
419
- this.isReadlineClosed = true;
420
- } catch (error) {
421
- // Ignore close errors
422
- }
423
- }
424
- }
425
-
426
- /**
427
- * Get current configuration
428
- * @returns {Object} Current configuration
429
- */
430
- getConfig() {
431
- return this.config;
432
- }
433
-
434
- /**
435
- * Get current settings
436
- * @returns {Object} Current settings
437
- */
438
- getSettings() {
439
- return this.settings;
440
- }
441
-
442
- /**
443
- * Get UI instance
444
- * @returns {Object} UI instance
445
- */
446
- getUI() {
447
- return this.ui;
448
- }
449
- };