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-py.js DELETED
@@ -1,379 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * i18ntk Python Command
5
- * Specialized command for Python i18n management
6
- *
7
- * Usage: i18ntk-py [options]
8
- */
9
-
10
- const fs = require('fs');
11
- const path = require('path');
12
-
13
- const SecurityUtils = require(path.join(__dirname, '../utils/security'));
14
- const { getConfig, saveConfig } = require(path.join(__dirname, '../utils/config-helper'));
15
- const I18nHelper = require(path.join(__dirname, '../utils/i18n-helper'));
16
- const SetupEnforcer = require(path.join(__dirname, '../utils/setup-enforcer'));
17
- const { program } = require('../utils/mini-commander');
18
-
19
- (async () => {
20
- try {
21
- await SetupEnforcer.checkSetupCompleteAsync();
22
- } catch (error) {
23
- console.error('Setup check failed:', error.message);
24
- process.exit(1);
25
- }
26
- })();
27
-
28
- class I18ntkPythonCommand {
29
- constructor() {
30
- this.config = null;
31
- this.sourceDir = './locales';
32
- this.pythonPatterns = [
33
- /_(?:gettext)?\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,
34
- /gettext\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,
35
- /gettext_lazy\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,
36
- /ngettext\s*\(\s*["'`]([^"'`]+)["'`]\s*,/g,
37
- /lazy_gettext\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,
38
- /ugettext\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g
39
- ];
40
- }
41
-
42
- async init() {
43
- console.log('šŸ”§ Initializing i18ntk Python command...');
44
-
45
- program
46
- .name('i18ntk-py')
47
- .description('i18ntk specialized for Python applications')
48
- .version('1.10.1')
49
- .option('-s, --source-dir <dir>', 'Source directory to scan', './')
50
- .option('-l, --locales-dir <dir>', 'Locales directory', './locales')
51
- .option('--framework <type>', 'Python framework type', 'auto')
52
- .option('--dry-run', 'Show what would be done without making changes')
53
- .option('--debug', 'Enable debug output')
54
- .option('--extract-only', 'Only extract translations, don\'t analyze')
55
- .option('--django', 'Force Django mode')
56
- .option('--flask', 'Force Flask mode')
57
- .option('--generic', 'Force generic Python mode')
58
- .parse();
59
-
60
- this.options = program.opts();
61
- this.sourceDir = path.resolve(this.options.sourceDir);
62
- this.localesDir = path.resolve(this.options.localesDir);
63
-
64
- await this.validateSourceDir();
65
- await this.loadConfig();
66
- }
67
-
68
- async validateSourceDir() {
69
- if (!SecurityUtils.safeExistsSync(this.sourceDir, path.dirname(this.sourceDir))) {
70
- console.error(`āŒ Source directory not found: ${this.sourceDir}`);
71
- process.exit(1);
72
- }
73
-
74
- const stats = fs.statSync(this.sourceDir);
75
- if (!stats.isDirectory()) {
76
- console.error(`āŒ Source path is not a directory: ${this.sourceDir}`);
77
- process.exit(1);
78
- }
79
- }
80
-
81
- async loadConfig() {
82
- try {
83
- this.config = await getConfig();
84
- this.config.python = this.config.python || {};
85
- } catch (error) {
86
- console.warn('āš ļø Could not load config, using defaults');
87
- this.config = { python: {} };
88
- }
89
- }
90
-
91
- async detectFramework() {
92
- if (this.options.django) return 'django';
93
- if (this.options.flask) return 'flask';
94
- if (this.options.generic) return 'generic';
95
-
96
- console.log('šŸ” Detecting Python framework...');
97
-
98
- // Check for Django
99
- const djangoIndicators = [
100
- 'manage.py',
101
- 'settings.py',
102
- 'requirements.txt',
103
- 'django'
104
- ];
105
-
106
- // Check for Flask
107
- const flaskIndicators = [
108
- 'app.py',
109
- 'requirements.txt',
110
- 'flask'
111
- ];
112
-
113
- let framework = 'generic';
114
-
115
- try {
116
- // Check requirements.txt
117
- const requirementsPath = path.join(this.sourceDir, 'requirements.txt');
118
- if (SecurityUtils.safeExistsSync(requirementsPath, this.sourceDir)) {
119
- const requirements = SecurityUtils.safeReadFileSync(requirementsPath, this.sourceDir, 'utf8');
120
- if (requirements.includes('Django')) framework = 'django';
121
- else if (requirements.includes('Flask')) framework = 'flask';
122
- }
123
-
124
- // Check for Django files
125
- for (const indicator of djangoIndicators) {
126
- if (this.findFiles(indicator).length > 0) {
127
- framework = 'django';
128
- break;
129
- }
130
- }
131
-
132
- // Check for Flask files
133
- for (const indicator of flaskIndicators) {
134
- if (this.findFiles(indicator).length > 0) {
135
- framework = 'flask';
136
- break;
137
- }
138
- }
139
-
140
- } catch (error) {
141
- if (this.options.debug) {
142
- console.error('Debug: Framework detection error:', error.message);
143
- }
144
- }
145
-
146
- console.log(`āœ… Detected framework: ${framework}`);
147
- return framework;
148
- }
149
-
150
- findFiles(pattern) {
151
- const results = [];
152
-
153
- function scanDir(dir) {
154
- if (!SecurityUtils.safeExistsSync(dir, path.dirname(dir))) return;
155
-
156
- const items = fs.readdirSync(dir);
157
- for (const item of items) {
158
- const fullPath = path.join(dir, item);
159
- const stat = fs.statSync(fullPath);
160
-
161
- if (stat.isDirectory() && !item.startsWith('.') && item !== 'node_modules') {
162
- scanDir(fullPath);
163
- } else if (item.includes(pattern) || fullPath.includes(pattern)) {
164
- results.push(fullPath);
165
- }
166
- }
167
- }
168
-
169
- scanDir(this.sourceDir);
170
- return results;
171
- }
172
-
173
- async extractTranslations() {
174
- console.log('šŸ“¦ Extracting Python translations...');
175
-
176
- const pythonFiles = this.findFiles('.py');
177
- const translations = new Set();
178
-
179
- for (const file of pythonFiles) {
180
- try {
181
- const content = SecurityUtils.safeReadFileSync(file, path.dirname(file), 'utf8');
182
-
183
- for (const pattern of this.pythonPatterns) {
184
- let match;
185
- while ((match = pattern.exec(content)) !== null) {
186
- translations.add(match[1]);
187
- }
188
- }
189
-
190
- // Reset regex state for next file
191
- for (const pattern of this.pythonPatterns) {
192
- pattern.lastIndex = 0;
193
- }
194
-
195
- } catch (error) {
196
- if (this.options.debug) {
197
- console.error(`Error reading ${file}:`, error.message);
198
- }
199
- }
200
- }
201
-
202
- console.log(`šŸ“Š Found ${translations.size} unique translation keys`);
203
- return Array.from(translations);
204
- }
205
-
206
- async createLocaleStructure() {
207
- if (!SecurityUtils.safeExistsSync(this.localesDir, path.dirname(this.localesDir))) {
208
- if (this.options.dryRun) {
209
- console.log(`šŸ“ Would create directory: ${this.localesDir}`);
210
- return;
211
- }
212
-
213
- fs.mkdirSync(this.localesDir, { recursive: true });
214
- console.log(`šŸ“ Created locales directory: ${this.localesDir}`);
215
- }
216
-
217
- const languages = ['en', 'es', 'fr', 'de', 'ja', 'ru', 'zh'];
218
-
219
- for (const lang of languages) {
220
- const langDir = path.join(this.localesDir, lang);
221
- if (!SecurityUtils.safeExistsSync(langDir, this.localesDir)) {
222
- if (this.options.dryRun) {
223
- console.log(`šŸ“ Would create directory: ${langDir}`);
224
- continue;
225
- }
226
-
227
- fs.mkdirSync(langDir, { recursive: true });
228
-
229
- // Create basic translation files
230
- const commonFile = path.join(langDir, 'common.json');
231
- const initialContent = {
232
- "python": {
233
- "welcome": `Welcome to Python (${lang})`,
234
- "framework_detected": "Framework detected: {framework}",
235
- "files_processed": "Processed {count} files"
236
- }
237
- };
238
-
239
- SecurityUtils.safeWriteFileSync(commonFile, JSON.stringify(initialContent, null, 2), this.localesDir);
240
- }
241
- }
242
- }
243
-
244
- async analyzeFramework(framework) {
245
- console.log(`šŸ” Analyzing ${framework} project...`);
246
-
247
- const analysis = {
248
- framework,
249
- files: {
250
- total: 0,
251
- python: 0,
252
- templates: 0,
253
- config: 0
254
- },
255
- patterns: {
256
- gettext: 0,
257
- gettext_lazy: 0,
258
- ngettext: 0,
259
- django: 0,
260
- flask: 0
261
- },
262
- recommendations: []
263
- };
264
-
265
- // Count Python files
266
- const pythonFiles = this.findFiles('.py');
267
- analysis.files.python = pythonFiles.length;
268
- analysis.files.total += pythonFiles.length;
269
-
270
- // Count template files
271
- const templateExtensions = ['.html', '.jinja', '.j2'];
272
- let templateFiles = [];
273
- for (const ext of templateExtensions) {
274
- templateFiles = templateFiles.concat(this.findFiles(ext));
275
- }
276
- analysis.files.templates = templateFiles.length;
277
- analysis.files.total += templateFiles.length;
278
-
279
- // Analyze patterns
280
- for (const file of pythonFiles) {
281
- try {
282
- const content = SecurityUtils.safeReadFileSync(file, path.dirname(file), 'utf8');
283
-
284
- if (content.includes('gettext(')) analysis.patterns.gettext++;
285
- if (content.includes('gettext_lazy(')) analysis.patterns.gettext_lazy++;
286
- if (content.includes('ngettext(')) analysis.patterns.ngettext++;
287
- if (content.includes('django')) analysis.patterns.django++;
288
- if (content.includes('flask')) analysis.patterns.flask++;
289
-
290
- } catch (error) {
291
- // Skip unreadable files
292
- }
293
- }
294
-
295
- // Generate recommendations
296
- if (framework === 'django' && analysis.patterns.gettext === 0) {
297
- analysis.recommendations.push('Consider adding Django gettext for i18n support');
298
- }
299
-
300
- if (framework === 'flask' && analysis.patterns.gettext === 0) {
301
- analysis.recommendations.push('Consider adding Flask-Babel for i18n support');
302
- }
303
-
304
- return analysis;
305
- }
306
-
307
- async generateReport(analysis, translations) {
308
- const report = {
309
- timestamp: new Date().toISOString(),
310
- framework: analysis.framework,
311
- summary: {
312
- totalFiles: analysis.files.total,
313
- pythonFiles: analysis.files.python,
314
- templateFiles: analysis.files.templates,
315
- translationKeys: translations.length
316
- },
317
- patterns: analysis.patterns,
318
- recommendations: analysis.recommendations,
319
- files: {
320
- python: this.findFiles('.py'),
321
- templates: this.findFiles('.html').concat(this.findFiles('.jinja')).concat(this.findFiles('.j2'))
322
- },
323
- translations: translations.sort()
324
- };
325
-
326
- const reportPath = path.join(this.sourceDir, 'i18ntk-py-report.json');
327
-
328
- if (this.options.dryRun) {
329
- console.log(`šŸ“Š Would create report: ${reportPath}`);
330
- console.log('šŸ“‹ Report contents:', JSON.stringify(report, null, 2));
331
- } else {
332
- SecurityUtils.safeWriteFileSync(reportPath, JSON.stringify(report, null, 2), this.sourceDir);
333
- console.log(`šŸ“Š Report saved: ${reportPath}`);
334
- }
335
-
336
- return report;
337
- }
338
-
339
- async run() {
340
- try {
341
- console.log('šŸš€ i18ntk Python Command v1.10.1');
342
- console.log('='.repeat(50));
343
-
344
- await this.init();
345
-
346
- const framework = await this.detectFramework();
347
- const translations = await this.extractTranslations();
348
-
349
- if (!this.options.extractOnly) {
350
- await this.createLocaleStructure();
351
- const analysis = await this.analyzeFramework(framework);
352
- const report = await this.generateReport(analysis, translations);
353
-
354
- console.log('\nāœ… Analysis complete!');
355
- console.log(`šŸ“Š Framework: ${framework}`);
356
- console.log(`šŸ“„ Python files: ${analysis.files.python}`);
357
- console.log(`šŸŽÆ Translation keys: ${translations.length}`);
358
- console.log(`šŸ“‹ Report: ${this.options.dryRun ? 'Not saved (dry-run)' : 'Saved to i18ntk-py-report.json'}`);
359
- } else {
360
- console.log(`šŸ“¦ Extracted ${translations.length} translation keys`);
361
- }
362
-
363
- } catch (error) {
364
- console.error('āŒ Error:', error.message);
365
- if (this.options.debug) {
366
- console.error(error.stack);
367
- }
368
- process.exit(1);
369
- }
370
- }
371
- }
372
-
373
- // Run if called directly
374
- if (require.main === module) {
375
- const cmd = new I18ntkPythonCommand();
376
- cmd.run();
377
- }
378
-
379
- module.exports = I18ntkPythonCommand;
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env node
2
- const SetupEnforcer = require('../utils/setup-enforcer');
3
- const SettingsCLI = require('../settings/settings-cli');
4
-
5
- (async () => {
6
- try {
7
- await SetupEnforcer.checkSetupCompleteAsync();
8
- } catch (error) {
9
- console.error('Setup check failed:', error.message);
10
- process.exit(1);
11
- }
12
- })();
13
-
14
- async function run() {
15
- const cli = new SettingsCLI();
16
- await cli.run();
17
- }
18
-
19
- if (require.main === module) {
20
- run();
21
- }
22
-
23
- module.exports = { run };