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,11 +2,47 @@
2
2
  const path = require('path');
3
3
  const fs = require('fs');
4
4
 
5
+ // Lazy load SecurityUtils to prevent circular dependencies
6
+ let securityUtils;
7
+ function getSecurityUtils() {
8
+ if (!securityUtils) {
9
+ try {
10
+ securityUtils = require('./security');
11
+ } catch (error) {
12
+ // Fallback: use basic fs operations if SecurityUtils is not available
13
+ return {
14
+ safeExistsSync: (path) => {
15
+ try {
16
+ return require('fs').existsSync(path);
17
+ } catch {
18
+ return false;
19
+ }
20
+ },
21
+ safeWriteFileSync: (path, data, encoding) => {
22
+ try {
23
+ return require('fs').writeFileSync(path, data, encoding);
24
+ } catch {
25
+ return null;
26
+ }
27
+ },
28
+ safeReadFileSync: (path, encoding) => {
29
+ try {
30
+ return require('fs').readFileSync(path, encoding);
31
+ } catch {
32
+ return null;
33
+ }
34
+ }
35
+ };
36
+ }
37
+ }
38
+ return securityUtils;
39
+ }
40
+
5
41
  // Helper functions for OS-agnostic path handling
6
42
  function toPosix(p) { return String(p).replace(/\\/g, '/'); }
7
- function isBundledPath(p) {
8
- const s = toPosix(p);
9
- return s.includes('/node_modules/i18ntk/') || s.includes('/i18ntk/ui-locales/');
43
+ function isBundledPath(p) {
44
+ const s = toPosix(p);
45
+ return s.includes('/node_modules/i18ntk/') || s.includes('/i18ntk/ui-locales/');
10
46
  }
11
47
 
12
48
  function safeRequireConfig() {
@@ -21,7 +57,8 @@ function stripBOMAndComments(s) {
21
57
  }
22
58
 
23
59
  function readJsonSafe(file) {
24
- const raw = fs.readFileSync(file, 'utf8');
60
+ const SecurityUtils = getSecurityUtils();
61
+ const raw = SecurityUtils.safeReadFileSync(file, path.dirname(file), 'utf8');
25
62
  return JSON.parse(stripBOMAndComments(raw));
26
63
  }
27
64
 
@@ -43,7 +80,8 @@ function resolveLocalesDirs() {
43
80
  try {
44
81
  const normalized = path.normalize(path.resolve(dir.trim()));
45
82
 
46
- if (fs.existsSync(normalized) && fs.statSync(normalized).isDirectory()) {
83
+ const SecurityUtils = getSecurityUtils();
84
+ if (SecurityUtils.safeExistsSync(normalized) && fs.statSync(normalized).isDirectory()) {
47
85
  dirs.push(normalized);
48
86
  }
49
87
  } catch {
@@ -54,7 +92,7 @@ function resolveLocalesDirs() {
54
92
 
55
93
  const pkgA = pkgUiLocalesDirViaThisFile();
56
94
  addDir(pkgA);
57
-
95
+
58
96
  const pkgB = pkgUiLocalesDirViaResolve();
59
97
  if (pkgB && pkgB !== pkgA) {
60
98
  addDir(pkgB);
@@ -78,28 +116,33 @@ function candidatesForLang(dir, lang) {
78
116
 
79
117
  function findLocaleFilesAllDirs(lang) {
80
118
  const dirs = resolveLocalesDirs();
81
-
119
+
82
120
  if (process.env.I18NTK_DEBUG_LOCALES === '1') {
83
121
  console.log('🔎 i18ntk locale search dirs:', dirs);
84
122
  }
85
-
123
+
86
124
  const files = [];
87
125
  const errors = [];
88
-
126
+
89
127
  for (const dir of dirs) {
90
128
  for (const candidate of candidatesForLang(dir, lang)) {
91
129
  try {
92
- if (fs.existsSync(candidate)) {
130
+ const SecurityUtils = getSecurityUtils();
131
+ if (SecurityUtils.safeExistsSync(candidate)) {
93
132
  const stats = fs.statSync(candidate);
94
133
  if (stats.isFile() && stats.size > 0) {
95
134
  // Validate file is readable and parseable
96
135
  fs.accessSync(candidate, fs.constants.R_OK);
97
136
  // Quick JSON validation
98
- const content = fs.readFileSync(candidate, 'utf8');
99
- if (content.trim().startsWith('{') || content.trim().startsWith('[')) {
100
- files.push(candidate);
137
+ const content = SecurityUtils.safeReadFileSync(candidate, path.dirname(candidate), 'utf8');
138
+ if (content) {
139
+ if (content.trim().startsWith('{') || content.trim().startsWith('[')) {
140
+ files.push(candidate);
141
+ } else {
142
+ errors.push({ file: candidate, error: 'Invalid JSON format' });
143
+ }
101
144
  } else {
102
- errors.push({ file: candidate, error: 'Invalid JSON format' });
145
+ errors.push({ file: candidate, error: 'Empty or unreadable file' });
103
146
  }
104
147
  }
105
148
  }
@@ -108,11 +151,11 @@ function findLocaleFilesAllDirs(lang) {
108
151
  }
109
152
  }
110
153
  }
111
-
154
+
112
155
  if (process.env.I18NTK_DEBUG_LOCALES === '1' && errors.length > 0) {
113
156
  console.warn(`⚠️ Locale resolution errors for ${lang}:`, errors);
114
157
  }
115
-
158
+
116
159
  return files;
117
160
  }
118
161
 
@@ -121,34 +164,34 @@ let currentLanguage = 'en';
121
164
  let isInitialized = false;
122
165
  const missingWarned = new Set();
123
166
 
124
- function loadTranslations(language) {
125
- const cfg = safeRequireConfig();
126
- const settings = cfg?.getConfig?.() || {};
127
- const configuredLanguage = settings.uiLanguage || settings.language || 'en';
128
-
129
- // Prioritize settings file language over environment variable
130
- const requested = (configuredLanguage || language || 'en').toString();
167
+ function loadTranslations(language) {
168
+ const cfg = safeRequireConfig();
169
+ const settings = cfg?.getConfig?.() || {};
170
+ const configuredLanguage = settings.uiLanguage || settings.language;
171
+
172
+ // Prioritize CLI argument, then UI language, then language fallback
173
+ const requested = (language || configuredLanguage || 'en').toString();
131
174
  const short = requested.split('-')[0].toLowerCase();
132
175
  const tryOrder = [requested, short, 'en'];
133
176
 
134
177
  const loadErrors = [];
135
-
178
+
136
179
  for (const lang of tryOrder) {
137
180
  const files = findLocaleFilesAllDirs(lang);
138
-
181
+
139
182
  // Prioritize bundled locales over project ones
140
183
  const prioritizedFiles = files.sort((a, b) => Number(isBundledPath(b)) - Number(isBundledPath(a)));
141
-
184
+
142
185
  for (const file of prioritizedFiles) {
143
186
  try {
144
187
  translations = readJsonSafe(file);
145
188
  currentLanguage = lang;
146
189
  isInitialized = true;
147
-
190
+
148
191
  if (process.env.I18NTK_DEBUG_LOCALES === '1') {
149
192
  console.log(`🗂 Loaded UI locale → ${file} (${lang})`);
150
193
  }
151
-
194
+
152
195
  // Validate translations object
153
196
  if (typeof translations === 'object' && translations !== null) {
154
197
  return translations;
@@ -199,11 +242,11 @@ function loadTranslations(language) {
199
242
  };
200
243
  currentLanguage = 'en';
201
244
  isInitialized = true;
202
-
245
+
203
246
  if (loadErrors.length > 0) {
204
247
  console.warn(`⚠️ No valid UI locale files found. Using built-in English strings.`);
205
248
  }
206
-
249
+
207
250
  return translations;
208
251
  }
209
252
 
@@ -219,7 +262,7 @@ function t(key, params = {}) {
219
262
  loadTranslations();
220
263
  isInitialized = true;
221
264
  }
222
-
265
+
223
266
  // Split the key into parts (e.g., 'module.subkey' -> ['module', 'subkey'])
224
267
  const keyParts = key.split('.');
225
268
  let value = translations;
@@ -258,12 +301,12 @@ function t(key, params = {}) {
258
301
  }
259
302
  return key;
260
303
  }
261
-
304
+
262
305
  // If we found a string, interpolate parameters
263
306
  if (typeof value === 'string') {
264
307
  return interpolateParams(value, params);
265
308
  }
266
-
309
+
267
310
  // Return the key if the final value is not a string
268
311
  console.warn(`Translation key does not resolve to a string: ${key}`);
269
312
  return key;
@@ -309,12 +352,13 @@ function getAvailableLanguages() {
309
352
  const langs = new Set();
310
353
  for (const d of dirs) {
311
354
  try {
312
- if (!fs.existsSync(d)) continue;
355
+ const SecurityUtils = getSecurityUtils();
356
+ if (!SecurityUtils.safeExistsSync(d)) continue;
313
357
  for (const f of fs.readdirSync(d)) {
314
358
  if (f.endsWith('.json')) langs.add(path.basename(f, '.json'));
315
359
  }
316
360
  for (const f of fs.readdirSync(d, { withFileTypes: true })) {
317
- if (f.isDirectory() && fs.existsSync(path.join(d, f.name, `${f.name}.json`))) {
361
+ if (f.isDirectory() && SecurityUtils.safeExistsSync(path.join(d, f.name, `${f.name}.json`))) {
318
362
  langs.add(f.name);
319
363
  }
320
364
  }
@@ -347,11 +391,11 @@ function deepMerge(target, source) {
347
391
  * Refresh language from settings manager
348
392
  * This ensures translations stay in sync with settings changes
349
393
  */
350
- function refreshLanguageFromSettings() {
351
- const cfg = safeRequireConfig();
352
- const settings = cfg?.getConfig?.() || {};
353
- const configuredLanguage = settings.language || settings.uiLanguage || 'en';
354
-
394
+ function refreshLanguageFromSettings() {
395
+ const cfg = safeRequireConfig();
396
+ const settings = cfg?.getConfig?.() || {};
397
+ const configuredLanguage = settings.uiLanguage || settings.language || 'en';
398
+
355
399
  if (configuredLanguage !== currentLanguage) {
356
400
  isInitialized = false;
357
401
  loadTranslations(configuredLanguage);
@@ -373,4 +417,4 @@ module.exports = {
373
417
  deepMerge,
374
418
  refreshTranslations,
375
419
  refreshLanguageFromSettings
376
- };
420
+ };
@@ -1,81 +1,121 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const configManager = require('./config-helper');
4
- const { ensureDirectory } = require('./config-helper');
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const configManager = require('./config-manager');
4
+ const SecurityUtils = require('./security');
5
+
6
+ function ensureDirectory(dirPath) {
7
+ if (!dirPath || typeof dirPath !== 'string') return;
8
+ if (!SecurityUtils.safeExistsSync(dirPath)) {
9
+ fs.mkdirSync(dirPath, { recursive: true });
10
+ }
11
+ }
12
+
13
+ function readJsonSafe(filePath) {
14
+ try {
15
+ if (!SecurityUtils.safeExistsSync(filePath)) return null;
16
+ const raw = SecurityUtils.safeReadFileSync(filePath, path.dirname(filePath), 'utf8');
17
+ if (!raw) return null;
18
+ return JSON.parse(raw);
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+
24
+ function hasSourceLanguageFiles(sourceDir, sourceLanguage) {
25
+ const baseSourceDir = path.resolve(sourceDir);
26
+ const modularLanguageDir = path.join(baseSourceDir, sourceLanguage);
27
+ const singleLanguageFile = path.join(baseSourceDir, `${sourceLanguage}.json`);
28
+
29
+ if (SecurityUtils.safeExistsSync(modularLanguageDir)) {
30
+ try {
31
+ if (fs.statSync(modularLanguageDir).isDirectory()) {
32
+ return fs.readdirSync(modularLanguageDir).some(file => file.endsWith('.json'));
33
+ }
34
+ } catch {
35
+ // Continue with single-file fallback.
36
+ }
37
+ }
38
+
39
+ return SecurityUtils.safeExistsSync(singleLanguageFile);
40
+ }
5
41
 
6
42
  /**
7
43
  * Check if the project is properly initialized
8
44
  * @param {Object} options - Options for initialization check
9
45
  * @returns {Promise<Object>} Object containing initialization status and config
10
46
  */
11
- async function checkInitialized(options = {}) {
12
- const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
13
- const currentVersion = require('../package.json').version;
14
- const configDir = settings.configDir || './settings';
15
-
16
- // Ensure config directory exists
17
- ensureDirectory(configDir);
18
-
47
+ async function checkInitialized(options = {}) {
48
+ const settings = configManager.getConfig ? configManager.getConfig() : {};
49
+ const currentVersion = require('../package.json').version;
50
+ const projectConfigPath = configManager.CONFIG_PATH || path.join(process.cwd(), '.i18ntk-config');
51
+ const configDir = path.dirname(projectConfigPath);
52
+
53
+ // Ensure config directory exists
54
+ ensureDirectory(configDir);
55
+
19
56
  const defaultConfig = {
20
57
  sourceDir: settings.sourceDir || './locales',
21
58
  sourceLanguage: settings.sourceLanguage || 'en',
22
59
  projectRoot: path.resolve('.'),
23
60
  framework: settings.framework || { detected: false, prompt: 'always' },
24
- configDir: configDir
25
- };
26
-
27
- // Check initialization status file with consistent path resolution
28
- const initFilePath = path.resolve(configDir, 'initialization.json');
29
-
30
- // If initialization file exists and is valid, return early
31
- if (fs.existsSync(initFilePath)) {
32
- try {
33
- const initStatus = JSON.parse(fs.readFileSync(initFilePath, 'utf8'));
34
- const isInitialized = initStatus.initialized &&
35
- initStatus.version &&
36
- initStatus.version.split('.')[0] === currentVersion.split('.')[0];
37
-
38
- if (isInitialized) {
39
- // Merge with default config but don't override existing settings
40
- return {
41
- initialized: true,
42
- config: {
43
- ...defaultConfig,
44
- ...initStatus,
45
- // Don't override framework settings if they exist
46
- framework: initStatus.framework || defaultConfig.framework
47
- }
48
- };
49
- }
50
- } catch (e) {
51
- console.warn('Warning: Invalid initialization file, will reinitialize...', e.message);
52
- }
53
- }
54
-
55
- // Check if source language files exist
56
- const langDir = path.resolve(defaultConfig.sourceDir, defaultConfig.sourceLanguage);
57
- const hasLanguageFiles = fs.existsSync(langDir) &&
58
- fs.readdirSync(langDir).some(f => f.endsWith('.json'));
59
-
60
- // If language files exist but no init file, create one
61
- if (hasLanguageFiles) {
62
- const initData = {
63
- initialized: true,
64
- version: currentVersion,
65
- timestamp: new Date().toISOString(),
66
- sourceDir: defaultConfig.sourceDir,
67
- sourceLanguage: defaultConfig.sourceLanguage,
68
- detectedLanguage: defaultConfig.detectedLanguage,
69
- detectedFramework: defaultConfig.detectedFramework,
70
- lastUpdated: new Date().toISOString()
71
- };
72
-
73
- ensureDirectory(path.dirname(initFilePath));
74
- fs.writeFileSync(initFilePath, JSON.stringify(initData, null, 2));
75
-
76
- return {
77
- initialized: true,
78
- config: { ...defaultConfig, ...initData }
61
+ configDir: configDir
62
+ };
63
+
64
+ // Primary source of truth in v2: project-level .i18ntk-config
65
+ const projectConfig = readJsonSafe(projectConfigPath);
66
+ if (projectConfig?.setup?.completed === true) {
67
+ return {
68
+ initialized: true,
69
+ config: {
70
+ ...defaultConfig,
71
+ ...projectConfig,
72
+ framework: projectConfig.framework || defaultConfig.framework
73
+ }
74
+ };
75
+ }
76
+
77
+ // Backward compatibility: legacy initialization marker file.
78
+ const initFilePath = path.join(configDir, 'initialization.json');
79
+ const initStatus = readJsonSafe(initFilePath);
80
+ const isLegacyInitialized = Boolean(initStatus?.initialized) && (
81
+ !initStatus.version ||
82
+ initStatus.version.split('.')[0] === currentVersion.split('.')[0]
83
+ );
84
+ if (isLegacyInitialized) {
85
+ return {
86
+ initialized: true,
87
+ config: {
88
+ ...defaultConfig,
89
+ ...initStatus,
90
+ framework: initStatus.framework || defaultConfig.framework
91
+ }
92
+ };
93
+ }
94
+
95
+ // Final fallback: detect existing source language files and mark initialized.
96
+ const sourceDir = options.sourceDir || defaultConfig.sourceDir;
97
+ const sourceLanguage = options.sourceLanguage || defaultConfig.sourceLanguage;
98
+ const hasLanguageFiles = hasSourceLanguageFiles(sourceDir, sourceLanguage);
99
+
100
+ // If language files exist but no init file, create one
101
+ if (hasLanguageFiles) {
102
+ const initData = {
103
+ initialized: true,
104
+ version: currentVersion,
105
+ timestamp: new Date().toISOString(),
106
+ sourceDir,
107
+ sourceLanguage,
108
+ detectedLanguage: defaultConfig.detectedLanguage,
109
+ detectedFramework: defaultConfig.detectedFramework,
110
+ lastUpdated: new Date().toISOString()
111
+ };
112
+
113
+ ensureDirectory(path.dirname(initFilePath));
114
+ SecurityUtils.safeWriteFileSync(initFilePath, JSON.stringify(initData, null, 2), path.dirname(initFilePath), 'utf8');
115
+
116
+ return {
117
+ initialized: true,
118
+ config: { ...defaultConfig, ...initData }
79
119
  };
80
120
  }
81
121
 
@@ -90,33 +130,51 @@ async function checkInitialized(options = {}) {
90
130
  * @param {Object} config - Configuration to save
91
131
  * @returns {Promise<void>}
92
132
  */
93
- async function markAsInitialized(config) {
94
- const settings = configManager.loadSettings ? configManager.loadSettings() : (configManager.getConfig ? configManager.getConfig() : {});
95
- const configDir = settings.configDir || './settings';
96
- const initFilePath = path.resolve(configDir, 'initialization.json');
97
- const currentVersion = require('../package.json').version;
98
-
99
- const initData = {
100
- initialized: true,
101
- version: currentVersion,
102
- timestamp: new Date().toISOString(),
103
- sourceDir: config.sourceDir,
104
- sourceLanguage: config.sourceLanguage,
105
- detectedLanguage: config.detectedLanguage,
106
- detectedFramework: config.detectedFramework,
107
- lastUpdated: new Date().toISOString()
108
- };
109
-
110
- ensureDirectory(path.dirname(initFilePath));
111
- fs.writeFileSync(initFilePath, JSON.stringify(initData, null, 2));
112
-
113
- // Update the settings object if it has a save method
114
- if (configManager.saveSettings) {
115
- await configManager.saveSettings({ ...settings, ...initData });
116
- } else if (configManager.saveConfig) {
117
- await configManager.saveConfig({ ...settings, ...initData });
118
- }
119
- }
133
+ async function markAsInitialized(config) {
134
+ const settings = configManager.getConfig ? configManager.getConfig() : {};
135
+ const projectConfigPath = configManager.CONFIG_PATH || path.join(process.cwd(), '.i18ntk-config');
136
+ const configDir = path.dirname(projectConfigPath);
137
+ const initFilePath = path.join(configDir, 'initialization.json');
138
+ const currentVersion = require('../package.json').version;
139
+ const now = new Date().toISOString();
140
+ const sourceDir = config?.sourceDir || settings.sourceDir || './locales';
141
+ const sourceLanguage = config?.sourceLanguage || settings.sourceLanguage || 'en';
142
+
143
+ const initData = {
144
+ initialized: true,
145
+ version: currentVersion,
146
+ timestamp: now,
147
+ sourceDir,
148
+ sourceLanguage,
149
+ detectedLanguage: config?.detectedLanguage || settings.detectedLanguage,
150
+ detectedFramework: config?.detectedFramework || settings.detectedFramework,
151
+ lastUpdated: now
152
+ };
153
+
154
+ ensureDirectory(path.dirname(initFilePath));
155
+ SecurityUtils.safeWriteFileSync(initFilePath, JSON.stringify(initData, null, 2), path.dirname(initFilePath), 'utf8');
156
+
157
+ const mergedConfig = {
158
+ ...settings,
159
+ ...(config || {}),
160
+ sourceDir,
161
+ sourceLanguage,
162
+ version: currentVersion,
163
+ setup: {
164
+ ...(settings.setup || {}),
165
+ completed: true,
166
+ completedAt: now,
167
+ version: currentVersion,
168
+ setupId: settings.setup?.setupId || `setup_${Date.now()}`
169
+ }
170
+ };
171
+
172
+ if (configManager.saveConfig) {
173
+ await configManager.saveConfig(mergedConfig);
174
+ } else {
175
+ SecurityUtils.safeWriteFileSync(projectConfigPath, JSON.stringify(mergedConfig, null, 2), path.dirname(projectConfigPath), 'utf8');
176
+ }
177
+ }
120
178
 
121
179
  module.exports = {
122
180
  checkInitialized,