@umituz/react-native-localization 2.0.1 → 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.
- package/package.json +1 -1
- package/scripts/prepublish.js +7 -52
- package/src/infrastructure/config/I18nInitializer.ts +33 -28
- package/src/infrastructure/config/TranslationLoader.ts +1 -12
- package/src/infrastructure/config/i18n.ts +5 -7
- package/scripts/analyze-keys.js +0 -230
- package/scripts/check-translations.js +0 -354
- package/scripts/createLocaleLoaders.js +0 -187
- package/scripts/remove-unused-keys.js +0 -216
- package/scripts/setup-languages.js +0 -290
- package/scripts/translate-missing.js +0 -619
- package/scripts/utils/findLocalesDir.js +0 -79
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable no-console */
|
|
3
|
-
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const { getLocalesDir } = require('./utils/findLocalesDir');
|
|
7
|
-
|
|
8
|
-
// Function to get all keys from an object recursively
|
|
9
|
-
function getAllKeys(obj, prefix = '') {
|
|
10
|
-
let keys = [];
|
|
11
|
-
for (const key in obj) {
|
|
12
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
13
|
-
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
14
|
-
if (
|
|
15
|
-
typeof obj[key] === 'object' &&
|
|
16
|
-
obj[key] !== null &&
|
|
17
|
-
!Array.isArray(obj[key])
|
|
18
|
-
) {
|
|
19
|
-
keys = keys.concat(getAllKeys(obj[key], fullKey));
|
|
20
|
-
} else {
|
|
21
|
-
keys.push(fullKey);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return keys;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Function to get value by key path
|
|
29
|
-
function getValueByPath(obj, path) {
|
|
30
|
-
return path.split('.').reduce((current, key) => current && current[key], obj);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Function to compare two translation objects
|
|
34
|
-
function compareTranslations(enUS, targetLang, filePath, langCode) {
|
|
35
|
-
const enKeys = getAllKeys(enUS);
|
|
36
|
-
const targetKeys = getAllKeys(targetLang);
|
|
37
|
-
|
|
38
|
-
const missingInTarget = enKeys.filter(key => !targetKeys.includes(key));
|
|
39
|
-
const extraInTarget = targetKeys.filter(key => !enKeys.includes(key));
|
|
40
|
-
|
|
41
|
-
const issues = [];
|
|
42
|
-
|
|
43
|
-
// Check for missing keys in target language
|
|
44
|
-
if (missingInTarget.length > 0) {
|
|
45
|
-
issues.push({
|
|
46
|
-
type: 'missing',
|
|
47
|
-
message: `Missing keys in ${langCode}: ${missingInTarget.join(', ')}`,
|
|
48
|
-
keys: missingInTarget,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Check for extra keys in target language
|
|
53
|
-
if (extraInTarget.length > 0) {
|
|
54
|
-
issues.push({
|
|
55
|
-
type: 'extra',
|
|
56
|
-
message: `Extra keys in ${langCode}: ${extraInTarget.join(', ')}`,
|
|
57
|
-
keys: extraInTarget,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Check for empty or placeholder values in target language
|
|
62
|
-
enKeys.forEach(key => {
|
|
63
|
-
if (targetKeys.includes(key)) {
|
|
64
|
-
const enValue = getValueByPath(enUS, key);
|
|
65
|
-
const targetValue = getValueByPath(targetLang, key);
|
|
66
|
-
|
|
67
|
-
// Skip checking if the value is the same and it's a common English word that doesn't need translation
|
|
68
|
-
const commonEnglishWords = [
|
|
69
|
-
'Premium',
|
|
70
|
-
'EULA',
|
|
71
|
-
'Plan',
|
|
72
|
-
'OK',
|
|
73
|
-
'API',
|
|
74
|
-
'URL',
|
|
75
|
-
'iOS',
|
|
76
|
-
'Android',
|
|
77
|
-
'minute',
|
|
78
|
-
'min',
|
|
79
|
-
'Sessions',
|
|
80
|
-
'Points',
|
|
81
|
-
'Nature',
|
|
82
|
-
'Instrumental',
|
|
83
|
-
'Piano',
|
|
84
|
-
'Silence',
|
|
85
|
-
'Pause',
|
|
86
|
-
'Gratitude',
|
|
87
|
-
'Notes',
|
|
88
|
-
'5 min',
|
|
89
|
-
'10 min',
|
|
90
|
-
'15 min',
|
|
91
|
-
'20 min',
|
|
92
|
-
'30 min',
|
|
93
|
-
'{{count}} min',
|
|
94
|
-
'{{duration}} min',
|
|
95
|
-
'{{duration}} • {{cycles}} cycles',
|
|
96
|
-
'No',
|
|
97
|
-
'Error',
|
|
98
|
-
'Try Again',
|
|
99
|
-
'Back',
|
|
100
|
-
'Oops! Something went wrong',
|
|
101
|
-
"We encountered an unexpected error. Don't worry, your meditation data is safe.",
|
|
102
|
-
"This screen doesn't exist.",
|
|
103
|
-
'Go to home screen!',
|
|
104
|
-
'No meditation cards available',
|
|
105
|
-
"Thank you for reporting this bug! We'll investigate and fix it as soon as possible.",
|
|
106
|
-
"Thank you for your feature request! We'll consider it for future updates.",
|
|
107
|
-
'Thank you for your suggestion! We appreciate your input and will review it carefully.',
|
|
108
|
-
'Your feedback has been submitted successfully. We appreciate your input!',
|
|
109
|
-
'Continue',
|
|
110
|
-
'Go Home',
|
|
111
|
-
'Start Meditating',
|
|
112
|
-
'Begin Your Journey',
|
|
113
|
-
'Detailed statistics',
|
|
114
|
-
'Achievement badges',
|
|
115
|
-
'Weekly/monthly reports',
|
|
116
|
-
'Sign Up',
|
|
117
|
-
'Sign In',
|
|
118
|
-
'Breathe In',
|
|
119
|
-
'Hold',
|
|
120
|
-
'Breathe Out',
|
|
121
|
-
'Rest',
|
|
122
|
-
'Find a comfortable seated position',
|
|
123
|
-
'Focus on slow, controlled movements',
|
|
124
|
-
"Don't force the breath, let it flow naturally",
|
|
125
|
-
'Cycle {{current}} of {{total}}',
|
|
126
|
-
'{{inhale}}s in • {{hold}}s hold • {{exhale}}s out',
|
|
127
|
-
'Total elapsed: {{time}}',
|
|
128
|
-
'Cancel',
|
|
129
|
-
'End Session',
|
|
130
|
-
'Reset',
|
|
131
|
-
"Today's Progress",
|
|
132
|
-
'See All',
|
|
133
|
-
'Total Time',
|
|
134
|
-
'Streak',
|
|
135
|
-
'Last Session',
|
|
136
|
-
'minutes completed',
|
|
137
|
-
'Find a quiet, comfortable space',
|
|
138
|
-
'Focus on your breath naturally',
|
|
139
|
-
'Let thoughts come and go without judgment',
|
|
140
|
-
'Start with shorter sessions and build up',
|
|
141
|
-
'Legal',
|
|
142
|
-
'Loading sounds...',
|
|
143
|
-
];
|
|
144
|
-
const shouldSkip =
|
|
145
|
-
commonEnglishWords.includes(enValue) && targetValue === enValue;
|
|
146
|
-
|
|
147
|
-
// Check if value needs translation
|
|
148
|
-
// Skip if already translated (different from English) - protects manual translations
|
|
149
|
-
const isAlreadyTranslated = targetValue !== enValue;
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
!shouldSkip &&
|
|
153
|
-
!isAlreadyTranslated &&
|
|
154
|
-
(!targetValue ||
|
|
155
|
-
(typeof targetValue === 'string' && targetValue.trim() === '') ||
|
|
156
|
-
targetValue === enValue ||
|
|
157
|
-
targetValue.includes('[NEEDS TRANSLATION]') ||
|
|
158
|
-
targetValue.includes('[MISSING:') ||
|
|
159
|
-
targetValue.includes('[ÇEVİRİ GEREKLİ:') ||
|
|
160
|
-
targetValue.includes('[TRANSLATE:'))
|
|
161
|
-
) {
|
|
162
|
-
issues.push({
|
|
163
|
-
type: 'translation',
|
|
164
|
-
message: `Key "${key}" has empty, missing, or untranslated value`,
|
|
165
|
-
key: key,
|
|
166
|
-
enValue: enValue,
|
|
167
|
-
targetValue: targetValue,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
return {
|
|
174
|
-
file: filePath,
|
|
175
|
-
issues: issues,
|
|
176
|
-
totalEnKeys: enKeys.length,
|
|
177
|
-
totalTargetKeys: targetKeys.length,
|
|
178
|
-
missingCount: missingInTarget.length,
|
|
179
|
-
extraCount: extraInTarget.length,
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Main function
|
|
184
|
-
function main() {
|
|
185
|
-
const args = process.argv.slice(2);
|
|
186
|
-
const targetLanguage = args.find(arg => !arg.startsWith('--'));
|
|
187
|
-
|
|
188
|
-
if (!targetLanguage) {
|
|
189
|
-
console.log('Kullanım: npm run i18n:check <dil-kodu>');
|
|
190
|
-
console.log('Örnek: npm run i18n:check de-DE');
|
|
191
|
-
console.log('Örnek: npm run i18n:check fr-FR');
|
|
192
|
-
console.log('Örnek: npm run i18n:check tr-TR');
|
|
193
|
-
console.log(
|
|
194
|
-
'Örnek: npm run i18n:check spanish (tüm İspanyolca varyantları)'
|
|
195
|
-
);
|
|
196
|
-
console.log(
|
|
197
|
-
'\nTüm dilleri kontrol etmek için: npm run i18n:check all'
|
|
198
|
-
);
|
|
199
|
-
process.exit(1);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Find project's locales directory
|
|
203
|
-
const localesDir = getLocalesDir();
|
|
204
|
-
const enUSDir = path.join(localesDir, 'en-US');
|
|
205
|
-
|
|
206
|
-
// 🔥 CRITICAL FIX: Auto-discover all JSON files (NO HARDCODED LIST!)
|
|
207
|
-
// This ensures check-translations works with ANY en-US file structure
|
|
208
|
-
const files = fs
|
|
209
|
-
.readdirSync(enUSDir)
|
|
210
|
-
.filter(file => file.endsWith('.json'))
|
|
211
|
-
.sort();
|
|
212
|
-
|
|
213
|
-
if (files.length === 0) {
|
|
214
|
-
console.error('❌ No JSON files found in en-US directory!');
|
|
215
|
-
process.exit(1);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
console.log(`🔍 Discovered ${files.length} translation files in en-US:\n ${files.join(', ')}\n`);
|
|
219
|
-
|
|
220
|
-
// Get all language directories
|
|
221
|
-
const allLanguageDirs = fs
|
|
222
|
-
.readdirSync(localesDir)
|
|
223
|
-
.filter(dir => {
|
|
224
|
-
const fullPath = path.join(localesDir, dir);
|
|
225
|
-
return fs.statSync(fullPath).isDirectory() && dir !== 'en-US';
|
|
226
|
-
})
|
|
227
|
-
.sort();
|
|
228
|
-
|
|
229
|
-
// Determine which languages to process
|
|
230
|
-
let languageDirs = allLanguageDirs;
|
|
231
|
-
if (targetLanguage !== 'all') {
|
|
232
|
-
if (targetLanguage === 'spanish' || targetLanguage === 'es') {
|
|
233
|
-
// Check all Spanish variants
|
|
234
|
-
languageDirs = allLanguageDirs.filter(dir => dir.startsWith('es-'));
|
|
235
|
-
if (languageDirs.length === 0) {
|
|
236
|
-
console.log('❌ No Spanish variants found.');
|
|
237
|
-
process.exit(1);
|
|
238
|
-
}
|
|
239
|
-
} else if (allLanguageDirs.includes(targetLanguage)) {
|
|
240
|
-
languageDirs = [targetLanguage];
|
|
241
|
-
} else {
|
|
242
|
-
console.log(
|
|
243
|
-
`❌ Language ${targetLanguage} not found. Available languages: ${allLanguageDirs.join(', ')}`
|
|
244
|
-
);
|
|
245
|
-
process.exit(1);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
let totalIssues = 0;
|
|
250
|
-
let totalMissing = 0;
|
|
251
|
-
let totalExtra = 0;
|
|
252
|
-
let totalTranslationIssues = 0;
|
|
253
|
-
let languagesWithIssues = 0;
|
|
254
|
-
|
|
255
|
-
console.log(
|
|
256
|
-
`🔍 Checking ${languageDirs.length} language(s) against English (en-US)...\n`
|
|
257
|
-
);
|
|
258
|
-
|
|
259
|
-
// Check each language
|
|
260
|
-
languageDirs.forEach(langCode => {
|
|
261
|
-
const langDir = path.join(localesDir, langCode);
|
|
262
|
-
let langIssues = 0;
|
|
263
|
-
let langMissing = 0;
|
|
264
|
-
let langExtra = 0;
|
|
265
|
-
let langTranslationIssues = 0;
|
|
266
|
-
|
|
267
|
-
console.log(`\n🌍 Checking ${langCode}...`);
|
|
268
|
-
|
|
269
|
-
files.forEach(file => {
|
|
270
|
-
const enUSPath = path.join(enUSDir, file);
|
|
271
|
-
const langPath = path.join(langDir, file);
|
|
272
|
-
|
|
273
|
-
if (!fs.existsSync(enUSPath)) {
|
|
274
|
-
console.log(` ❌ English file not found: ${file}`);
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (!fs.existsSync(langPath)) {
|
|
279
|
-
console.log(` ❌ ${langCode} file not found: ${file}`);
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
const enUS = JSON.parse(fs.readFileSync(enUSPath, 'utf8'));
|
|
285
|
-
const langData = JSON.parse(fs.readFileSync(langPath, 'utf8'));
|
|
286
|
-
|
|
287
|
-
const comparison = compareTranslations(enUS, langData, file, langCode);
|
|
288
|
-
|
|
289
|
-
if (comparison.issues.length === 0) {
|
|
290
|
-
console.log(` ✅ ${file}: Complete`);
|
|
291
|
-
} else {
|
|
292
|
-
console.log(
|
|
293
|
-
` 📄 ${file}: ${comparison.missingCount} missing, ${comparison.extraCount} extra, ${comparison.issues.filter(i => i.type === 'translation').length} untranslated`
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
// Show detailed issues for debugging
|
|
297
|
-
comparison.issues.forEach(issue => {
|
|
298
|
-
if (issue.type === 'translation') {
|
|
299
|
-
console.log(
|
|
300
|
-
` 🔍 ${issue.key}: "${issue.enValue}" → "${issue.targetValue || '[EMPTY]'}"`
|
|
301
|
-
);
|
|
302
|
-
} else if (issue.type === 'extra') {
|
|
303
|
-
console.log(` ➕ Extra keys: ${issue.keys.join(', ')}`);
|
|
304
|
-
} else if (issue.type === 'missing') {
|
|
305
|
-
console.log(` ➖ Missing keys: ${issue.keys.join(', ')}`);
|
|
306
|
-
}
|
|
307
|
-
langIssues++;
|
|
308
|
-
totalIssues++;
|
|
309
|
-
if (issue.type === 'missing') {
|
|
310
|
-
langMissing += issue.keys.length;
|
|
311
|
-
totalMissing += issue.keys.length;
|
|
312
|
-
} else if (issue.type === 'extra') {
|
|
313
|
-
langExtra += issue.keys.length;
|
|
314
|
-
totalExtra += issue.keys.length;
|
|
315
|
-
} else if (issue.type === 'translation') {
|
|
316
|
-
langTranslationIssues++;
|
|
317
|
-
totalTranslationIssues++;
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
} catch (error) {
|
|
322
|
-
console.log(` ❌ Error processing ${file}: ${error.message}`);
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
// Summary for this language
|
|
327
|
-
if (langIssues === 0) {
|
|
328
|
-
console.log(` 🎉 ${langCode}: All translations complete!`);
|
|
329
|
-
} else {
|
|
330
|
-
languagesWithIssues++;
|
|
331
|
-
console.log(
|
|
332
|
-
` ⚠️ ${langCode}: ${langIssues} issues (${langMissing} missing, ${langExtra} extra, ${langTranslationIssues} translation issues)`
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
console.log('\n📊 Summary:');
|
|
338
|
-
console.log(` Languages checked: ${languageDirs.length}`);
|
|
339
|
-
console.log(` Languages with issues: ${languagesWithIssues}`);
|
|
340
|
-
console.log(` Total issues found: ${totalIssues}`);
|
|
341
|
-
console.log(` Missing keys: ${totalMissing}`);
|
|
342
|
-
console.log(` Extra keys: ${totalExtra}`);
|
|
343
|
-
console.log(` Translation issues: ${totalTranslationIssues}`);
|
|
344
|
-
|
|
345
|
-
if (totalIssues === 0) {
|
|
346
|
-
console.log('\n🎉 All translations are complete and correct!');
|
|
347
|
-
process.exit(0);
|
|
348
|
-
} else {
|
|
349
|
-
console.log(`\n⚠️ ${languagesWithIssues} language(s) need attention.`);
|
|
350
|
-
process.exit(1);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
main();
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable */
|
|
3
|
-
/**
|
|
4
|
-
* Auto-Loader Generator for Localization
|
|
5
|
-
*
|
|
6
|
-
* NOTE: This is a Node.js build script, not React Native code.
|
|
7
|
-
* ESLint is disabled for this file as it uses Node.js APIs (require, __dirname, process, console).
|
|
8
|
-
*
|
|
9
|
-
* Automatically scans locale directories and generates index.ts files
|
|
10
|
-
* that import all .json translation files.
|
|
11
|
-
*
|
|
12
|
-
* Features:
|
|
13
|
-
* - Dynamic JSON file detection (no hardcoded mappings)
|
|
14
|
-
* - Nested namespace structure for better organization
|
|
15
|
-
* - Supports all languages automatically
|
|
16
|
-
* - Clean, maintainable output
|
|
17
|
-
*
|
|
18
|
-
* Usage:
|
|
19
|
-
* npm run localization:create-loaders # Generate all
|
|
20
|
-
* node scripts/createLocaleLoaders.js en-US # Generate single language
|
|
21
|
-
*
|
|
22
|
-
* Factory-First: This script is auto-copied to all generated apps
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
const fs = require('fs');
|
|
26
|
-
const path = require('path');
|
|
27
|
-
|
|
28
|
-
// Get the locales directory (works from scripts/ or root)
|
|
29
|
-
const getLocalesDir = () => {
|
|
30
|
-
const possiblePaths = [
|
|
31
|
-
path.join(__dirname, '../src/infrastructure/locales'), // Package structure
|
|
32
|
-
path.join(__dirname, '../locales'), // App structure from scripts/
|
|
33
|
-
path.join(process.cwd(), 'domains/localization/infrastructure/locales'), // App structure from root
|
|
34
|
-
path.join(process.cwd(), 'src/infrastructure/locales'), // Package from root
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
for (const p of possiblePaths) {
|
|
38
|
-
if (fs.existsSync(p)) {
|
|
39
|
-
return p;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
throw new Error('Could not find locales directory');
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const localesDir = getLocalesDir();
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Get all language directories dynamically
|
|
50
|
-
*/
|
|
51
|
-
function getLanguageDirectories() {
|
|
52
|
-
return fs
|
|
53
|
-
.readdirSync(localesDir)
|
|
54
|
-
.filter(item => {
|
|
55
|
-
const itemPath = path.join(localesDir, item);
|
|
56
|
-
return fs.statSync(itemPath).isDirectory() && item.match(/^[a-z]{2}-[A-Z]{2}$/);
|
|
57
|
-
})
|
|
58
|
-
.sort();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Create auto-loader for a single language
|
|
63
|
-
*/
|
|
64
|
-
function createAutoLoader(languageCode) {
|
|
65
|
-
const languageDir = path.join(localesDir, languageCode);
|
|
66
|
-
|
|
67
|
-
// Check if directory exists
|
|
68
|
-
if (!fs.existsSync(languageDir)) {
|
|
69
|
-
console.warn(`⚠️ Language directory not found: ${languageCode}`);
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Read all JSON files in the directory
|
|
74
|
-
const files = fs
|
|
75
|
-
.readdirSync(languageDir)
|
|
76
|
-
.filter(file => file.endsWith('.json'))
|
|
77
|
-
.sort();
|
|
78
|
-
|
|
79
|
-
if (files.length === 0) {
|
|
80
|
-
console.warn(`⚠️ No JSON files found in: ${languageCode}`);
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Create the auto-loader content with require.context for automatic discovery
|
|
85
|
-
const content = `/**
|
|
86
|
-
* Auto-loader for ${languageCode} translation modules
|
|
87
|
-
*
|
|
88
|
-
* AUTOMATIC TRANSLATION FILE DETECTION:
|
|
89
|
-
* - Uses Metro bundler's require.context to auto-discover .json files
|
|
90
|
-
* - Adding new translation file = just create .json file (zero manual updates)
|
|
91
|
-
* - Build-time resolution (fast, no runtime overhead)
|
|
92
|
-
* - Works for all languages automatically
|
|
93
|
-
*
|
|
94
|
-
* OFFLINE-ONLY TRANSLATIONS (All domains work without backend):
|
|
95
|
-
* - Automatically imports ALL .json files in this directory
|
|
96
|
-
* - Alphabetically sorted for consistency
|
|
97
|
-
* - Type-safe with TypeScript
|
|
98
|
-
*
|
|
99
|
-
* USAGE:
|
|
100
|
-
* 1. Create new translation file: my_domain.json
|
|
101
|
-
* 2. File is auto-discovered and loaded
|
|
102
|
-
* 3. Access via t('my_domain.key')
|
|
103
|
-
*
|
|
104
|
-
* This file is automatically generated by setup-languages.js or createLocaleLoaders.js
|
|
105
|
-
* but can be manually edited if needed.
|
|
106
|
-
*
|
|
107
|
-
* Generated: ${new Date().toISOString()}
|
|
108
|
-
*/
|
|
109
|
-
|
|
110
|
-
// Metro bundler require.context - auto-discover all .json files
|
|
111
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
112
|
-
const translationContext = (require as any).context('./', false, /\\.json$/);
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Load all JSON modules automatically
|
|
116
|
-
* Extracts module name from path (e.g., './auth.json' -> 'auth')
|
|
117
|
-
*/
|
|
118
|
-
const translations: Record<string, any> = {};
|
|
119
|
-
|
|
120
|
-
translationContext.keys().forEach((key: string) => {
|
|
121
|
-
// Extract module name from path: './auth.json' -> 'auth'
|
|
122
|
-
const match = key.match(/\\.\\/([^/]+)\\.json$/);
|
|
123
|
-
if (match) {
|
|
124
|
-
const moduleName = match[1];
|
|
125
|
-
translations[moduleName] = translationContext(key);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
export default translations;
|
|
130
|
-
`;
|
|
131
|
-
|
|
132
|
-
// Write the index.ts file
|
|
133
|
-
const indexPath = path.join(languageDir, 'index.ts');
|
|
134
|
-
fs.writeFileSync(indexPath, content, 'utf8');
|
|
135
|
-
|
|
136
|
-
console.log(`✅ Created auto-loader: ${languageCode}/index.ts (${files.length} modules)`);
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Create auto-loaders for all languages
|
|
142
|
-
*/
|
|
143
|
-
function createAllAutoLoaders() {
|
|
144
|
-
const languages = getLanguageDirectories();
|
|
145
|
-
|
|
146
|
-
if (languages.length === 0) {
|
|
147
|
-
console.error('❌ No language directories found in:', localesDir);
|
|
148
|
-
process.exit(1);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
console.log(`\n🌍 Creating auto-loaders for ${languages.length} languages...\n`);
|
|
152
|
-
|
|
153
|
-
let successCount = 0;
|
|
154
|
-
languages.forEach(languageCode => {
|
|
155
|
-
if (createAutoLoader(languageCode)) {
|
|
156
|
-
successCount++;
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
console.log(`\n✨ Successfully created ${successCount}/${languages.length} auto-loaders`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// ============================================================================
|
|
164
|
-
// CLI
|
|
165
|
-
// ============================================================================
|
|
166
|
-
|
|
167
|
-
const args = process.argv.slice(2);
|
|
168
|
-
|
|
169
|
-
if (args[0] === 'all' || args.length === 0) {
|
|
170
|
-
createAllAutoLoaders();
|
|
171
|
-
} else if (args[0]) {
|
|
172
|
-
// Single language
|
|
173
|
-
const languageCode = args[0];
|
|
174
|
-
if (createAutoLoader(languageCode)) {
|
|
175
|
-
console.log(`\n✨ Done!`);
|
|
176
|
-
} else {
|
|
177
|
-
console.error(`\n❌ Failed to create auto-loader for: ${languageCode}`);
|
|
178
|
-
process.exit(1);
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
console.log('Usage: node createLocaleLoaders.js [language-code|all]');
|
|
182
|
-
console.log('\nExamples:');
|
|
183
|
-
console.log(' node createLocaleLoaders.js # Generate all');
|
|
184
|
-
console.log(' node createLocaleLoaders.js all # Generate all');
|
|
185
|
-
console.log(' node createLocaleLoaders.js en-US # Generate single language');
|
|
186
|
-
console.log(' node createLocaleLoaders.js tr-TR # Generate single language');
|
|
187
|
-
}
|