i18ntk 4.1.0 → 4.2.1
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/CHANGELOG.md +64 -5
- package/README.md +73 -17
- package/SECURITY.md +10 -4
- package/main/i18ntk-analyze.js +10 -20
- package/main/i18ntk-backup.js +106 -44
- package/main/i18ntk-init.js +153 -157
- package/main/i18ntk-setup.js +36 -13
- package/main/i18ntk-sizing.js +44 -27
- package/main/i18ntk-translate.js +311 -41
- package/main/i18ntk-usage.js +272 -103
- package/main/i18ntk-validate.js +38 -31
- package/main/manage/commands/AnalyzeCommand.js +7 -17
- package/main/manage/commands/CommandRouter.js +6 -6
- package/main/manage/commands/SizingCommand.js +5 -2
- package/main/manage/commands/TranslateCommand.js +73 -56
- package/main/manage/commands/ValidateCommand.js +58 -26
- package/main/manage/index.js +11 -42
- package/main/manage/managers/InteractiveMenu.js +11 -40
- package/main/manage/services/InitService.js +114 -118
- package/main/manage/services/UsageService.js +247 -96
- package/package.json +19 -14
- package/runtime/enhanced.d.ts +5 -5
- package/runtime/enhanced.js +49 -25
- package/runtime/i18ntk.d.ts +30 -7
- package/runtime/index.d.ts +48 -19
- package/runtime/index.js +175 -90
- package/settings/settings-cli.js +115 -38
- package/settings/settings-manager.js +24 -6
- package/ui-locales/de.json +192 -11
- package/ui-locales/en.json +182 -8
- package/ui-locales/es.json +193 -12
- package/ui-locales/fr.json +189 -8
- package/ui-locales/ja.json +190 -8
- package/ui-locales/ru.json +191 -9
- package/ui-locales/zh.json +194 -9
- package/utils/cli-helper.js +8 -12
- package/utils/config-helper.js +1 -1
- package/utils/config-manager.js +8 -6
- package/utils/localized-confirm.js +55 -0
- package/utils/menu-layout.js +41 -0
- package/utils/report-writer.js +110 -0
- package/utils/security.js +15 -22
- package/utils/translate/api.js +31 -3
- package/utils/translate/placeholder.js +42 -1
- package/utils/translate/report.js +32 -4
- package/utils/translate/safe-network.js +24 -4
- package/utils/usage-insights.js +435 -0
- package/utils/usage-source.js +50 -0
- package/utils/watch-locales.js +1 -8
|
@@ -13,30 +13,33 @@ const SecurityUtils = require('../../../utils/security');
|
|
|
13
13
|
const configManager = require('../../../utils/config-manager');
|
|
14
14
|
const { loadTranslations, t } = require('../../../utils/i18n-helper');
|
|
15
15
|
const { detectFramework } = require('../../../utils/framework-detector');
|
|
16
|
-
const { getFormatAdapter } = require('../../../utils/format-manager');
|
|
17
|
-
const AdminAuth = require('../../../utils/admin-auth');
|
|
16
|
+
const { getFormatAdapter } = require('../../../utils/format-manager');
|
|
17
|
+
const AdminAuth = require('../../../utils/admin-auth');
|
|
18
|
+
const { parseConfirmation } = require('../../../utils/localized-confirm');
|
|
19
|
+
const { normalizeReportFormat, writeReportFile } = require('../../../utils/report-writer');
|
|
18
20
|
|
|
19
21
|
// Language configurations with native names
|
|
20
|
-
const LANGUAGE_CONFIG = {
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
'
|
|
22
|
+
const LANGUAGE_CONFIG = {
|
|
23
|
+
'en': { name: 'English', nativeName: 'English' },
|
|
24
|
+
'de': { name: 'German', nativeName: 'Deutsch' },
|
|
25
|
+
'es': { name: 'Spanish', nativeName: 'Espa\u00f1ol' },
|
|
26
|
+
'fr': { name: 'French', nativeName: 'Fran\u00e7ais' },
|
|
27
|
+
'ru': { name: 'Russian', nativeName: '\u0420\u0443\u0441\u0441\u043a\u0438\u0439' },
|
|
28
|
+
'it': { name: 'Italian', nativeName: 'Italiano' },
|
|
29
|
+
'ja': { name: 'Japanese', nativeName: '\u65e5\u672c\u8a9e' },
|
|
30
|
+
'ko': { name: 'Korean', nativeName: '\ud55c\uad6d\uc5b4' },
|
|
31
|
+
'zh': { name: 'Chinese', nativeName: '\u4e2d\u6587' },
|
|
32
|
+
'ar': { name: 'Arabic', nativeName: '\u0627\u0644\u0639\u0631\u0628\u064a\u0629' },
|
|
33
|
+
'hi': { name: 'Hindi', nativeName: '\u0939\u093f\u0928\u094d\u0926\u0940' },
|
|
34
|
+
'nl': { name: 'Dutch', nativeName: 'Nederlands' },
|
|
35
|
+
'sv': { name: 'Swedish', nativeName: 'Svenska' },
|
|
36
|
+
'da': { name: 'Danish', nativeName: 'Dansk' },
|
|
37
|
+
'no': { name: 'Norwegian', nativeName: 'Norsk' },
|
|
38
|
+
'fi': { name: 'Finnish', nativeName: 'Suomi' },
|
|
39
|
+
'pl': { name: 'Polish', nativeName: 'Polski' },
|
|
40
|
+
'cs': { name: 'Czech', nativeName: '\u010ce\u0161tina' },
|
|
41
|
+
'hu': { name: 'Hungarian', nativeName: 'Magyar' },
|
|
42
|
+
'tr': { name: 'Turkish', nativeName: 'T\u00fcrk\u00e7e' }
|
|
40
43
|
};
|
|
41
44
|
|
|
42
45
|
class InitService {
|
|
@@ -65,7 +68,7 @@ class InitService {
|
|
|
65
68
|
: path.join(this.sourceDir, this.config.sourceLanguage);
|
|
66
69
|
|
|
67
70
|
// Ensure defaultLanguages is properly initialized from config
|
|
68
|
-
this.config.defaultLanguages = this.config.defaultLanguages || ['de', 'es', 'fr', 'ru'];
|
|
71
|
+
this.config.defaultLanguages = this.config.defaultLanguages || ['en', 'de', 'es', 'fr', 'ru'];
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
// Check i18n dependencies
|
|
@@ -694,7 +697,7 @@ class InitService {
|
|
|
694
697
|
await flushStdout();
|
|
695
698
|
const enableProtection = await ask('\n' + t('adminPin.setup_prompt'));
|
|
696
699
|
|
|
697
|
-
if (enableProtection
|
|
700
|
+
if (parseConfirmation(enableProtection, { language: this.config.uiLanguage || this.config.language || 'en', defaultValue: false })) {
|
|
698
701
|
try {
|
|
699
702
|
const adminAuth = new AdminAuth();
|
|
700
703
|
await adminAuth.initialize();
|
|
@@ -743,16 +746,16 @@ class InitService {
|
|
|
743
746
|
}
|
|
744
747
|
|
|
745
748
|
const { ask } = require('../../../utils/cli');
|
|
746
|
-
console.log('\
|
|
747
|
-
console.log('
|
|
748
|
-
const enableAnswer = await ask(
|
|
749
|
-
const enabled =
|
|
749
|
+
console.log('\n' + t('init.backup.title'));
|
|
750
|
+
console.log(t('init.backup.description'));
|
|
751
|
+
const enableAnswer = await ask(t('init.backup.enablePrompt'));
|
|
752
|
+
const enabled = parseConfirmation(enableAnswer, { language: this.config.uiLanguage || this.config.language || 'en', defaultValue: false });
|
|
750
753
|
|
|
751
754
|
if (!enabled) {
|
|
752
755
|
return defaultBackupConfig;
|
|
753
756
|
}
|
|
754
757
|
|
|
755
|
-
const keepAnswer = await ask(
|
|
758
|
+
const keepAnswer = await ask(t('init.backup.keepPrompt'));
|
|
756
759
|
const parsedKeep = parseInt(String(keepAnswer || '').trim(), 10);
|
|
757
760
|
const maxBackups = Number.isInteger(parsedKeep) ? Math.min(Math.max(parsedKeep, 1), 3) : 1;
|
|
758
761
|
|
|
@@ -822,7 +825,7 @@ class InitService {
|
|
|
822
825
|
let perLanguage = [];
|
|
823
826
|
if (structure !== 'existing') {
|
|
824
827
|
const duplicateChoice = await ask('\n' + t('init.setup.apply_all_prompt'));
|
|
825
|
-
duplicateStructure = duplicateChoice
|
|
828
|
+
duplicateStructure = parseConfirmation(duplicateChoice, { language: this.config.uiLanguage || this.config.language || 'en', defaultValue: true });
|
|
826
829
|
if (!duplicateStructure) {
|
|
827
830
|
// Prompt for languages to include/exclude
|
|
828
831
|
console.log(t('init.setup.per_language_intro'));
|
|
@@ -978,98 +981,91 @@ class InitService {
|
|
|
978
981
|
console.log(t('init.nextStep3'));
|
|
979
982
|
}
|
|
980
983
|
|
|
981
|
-
// Generate completion summary with proper error handling
|
|
982
|
-
async generateCompletionSummary(results, targetLanguages) {
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
console.log(
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
});
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
console.log(t('common.separator'));
|
|
1044
|
-
console.log(`🌍 Languages processed: ${Object.keys(results || {}).length}`);
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
// Generate detailed report
|
|
984
|
+
// Generate completion summary with proper error handling
|
|
985
|
+
async generateCompletionSummary(results, targetLanguages) {
|
|
986
|
+
return await this.generateLocalizedCompletionSummary(results, targetLanguages);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
async generateLocalizedCompletionSummary(results, targetLanguages) {
|
|
990
|
+
try {
|
|
991
|
+
console.log('\n' + '='.repeat(50));
|
|
992
|
+
console.log(t('init.initializationSummaryTitle'));
|
|
993
|
+
console.log(t('common.separator'));
|
|
994
|
+
|
|
995
|
+
let totalChanges = 0;
|
|
996
|
+
let languagesProcessed = 0;
|
|
997
|
+
let missingKeysAdded = 0;
|
|
998
|
+
|
|
999
|
+
Object.entries(results || {}).forEach(([lang, data]) => {
|
|
1000
|
+
if (!data || typeof data !== 'object') return;
|
|
1001
|
+
|
|
1002
|
+
const langName = LANGUAGE_CONFIG[lang]?.name || 'Unknown';
|
|
1003
|
+
const stats = data.totalStats || { total: 0, translated: 0, percentage: 0, missing: 0 };
|
|
1004
|
+
const statusIcon = stats.percentage === 100 ? '✅' : stats.percentage >= 80 ? '🟡' : '🔴';
|
|
1005
|
+
|
|
1006
|
+
console.log(t('init.languageSummary', {
|
|
1007
|
+
icon: statusIcon,
|
|
1008
|
+
name: langName,
|
|
1009
|
+
code: lang,
|
|
1010
|
+
percentage: stats.percentage || 0,
|
|
1011
|
+
}));
|
|
1012
|
+
|
|
1013
|
+
if (Array.isArray(data.files)) {
|
|
1014
|
+
console.log(t('init.languageFiles', { count: data.files.length }));
|
|
1015
|
+
}
|
|
1016
|
+
console.log(t('init.languageKeys', { translated: stats.translated || 0, total: stats.total || 0 }));
|
|
1017
|
+
console.log(t('init.languageMissing', { count: stats.missing || 0 }));
|
|
1018
|
+
|
|
1019
|
+
totalChanges += (stats.translated || 0) + (stats.missing || 0);
|
|
1020
|
+
languagesProcessed += 1;
|
|
1021
|
+
missingKeysAdded += stats.missing || 0;
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
console.log('\n' + t('init.completionSummaryTitle'));
|
|
1025
|
+
console.log(t('common.separator'));
|
|
1026
|
+
console.log(t('init.totalChanges', { count: totalChanges }));
|
|
1027
|
+
console.log(t('init.languagesProcessed', { count: languagesProcessed }));
|
|
1028
|
+
console.log(t('init.missingKeysAdded', { count: missingKeysAdded }));
|
|
1029
|
+
|
|
1030
|
+
if (process.stdin.isTTY && !this.config?.noPrompt) {
|
|
1031
|
+
const { ask } = require('../../../utils/cli');
|
|
1032
|
+
const generateReport = await ask('\n' + t('init.reportPrompt'));
|
|
1033
|
+
if (parseConfirmation(generateReport, { language: this.config.uiLanguage || this.config.language || 'en', defaultValue: true })) {
|
|
1034
|
+
await this.generateDetailedReport(results, targetLanguages);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
} catch (error) {
|
|
1038
|
+
console.error('\n' + t('init.completionError', { error: error.message }));
|
|
1039
|
+
console.log(t('init.completionSummaryBasicTitle'));
|
|
1040
|
+
console.log(t('common.separator'));
|
|
1041
|
+
console.log(t('init.languagesProcessed', { count: Object.keys(results || {}).length }));
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// Generate detailed report
|
|
1049
1046
|
async generateDetailedReport(results, targetLanguages) {
|
|
1050
1047
|
try {
|
|
1051
1048
|
const outputDir = this.config.outputDir || path.join(process.cwd(), 'i18ntk-reports');
|
|
1052
|
-
if (!SecurityUtils.safeExistsSync(outputDir)) {
|
|
1053
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
console.log(`✅ Report generated: ${reportPath}`);
|
|
1049
|
+
if (!SecurityUtils.safeExistsSync(outputDir)) {
|
|
1050
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
const reportPayload = {
|
|
1054
|
+
timestamp: new Date().toISOString(),
|
|
1055
|
+
languages: targetLanguages,
|
|
1056
|
+
results,
|
|
1057
|
+
summary: {
|
|
1058
|
+
languagesProcessed: targetLanguages.length,
|
|
1059
|
+
totalFiles: Object.values(results).reduce((sum, data) => sum + (data.files?.length || 0), 0),
|
|
1060
|
+
totalKeys: Object.values(results).reduce((sum, data) => sum + (data.totalStats?.total || 0), 0),
|
|
1061
|
+
totalMissing: Object.values(results).reduce((sum, data) => sum + (data.totalStats?.missing || 0), 0)
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
const format = normalizeReportFormat(this.config.reports?.format || this.config.reportFormat || 'markdown');
|
|
1065
|
+
const writtenPath = await writeReportFile(outputDir, 'init-report', reportPayload, { format, title: 'I18NTK Init Report' });
|
|
1066
|
+
console.log(t('init.reportGenerated', { reportPath: writtenPath }));
|
|
1071
1067
|
} catch (error) {
|
|
1072
|
-
console.error('
|
|
1068
|
+
console.error(t('init.reportFailed', { error: error.message }));
|
|
1073
1069
|
}
|
|
1074
1070
|
}
|
|
1075
1071
|
|