@umituz/react-native-localization 3.5.3 → 3.5.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-localization",
3
- "version": "3.5.3",
3
+ "version": "3.5.5",
4
4
  "description": "Generic localization system for React Native apps with i18n support",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -10,13 +10,13 @@
10
10
  "test": "jest",
11
11
  "test:watch": "jest --watch",
12
12
  "test:coverage": "jest --coverage",
13
- "prepublishOnly": "ts-node src/scripts/prepublish.ts",
13
+ "prepublishOnly": "node src/scripts/prepublish.js",
14
14
  "version:patch": "npm version patch -m 'chore: release v%s'",
15
15
  "version:minor": "npm version minor -m 'chore: release v%s'",
16
16
  "version:major": "npm version major -m 'chore: release v%s'",
17
- "i18n:setup": "ts-node src/scripts/setup-languages.ts",
18
- "i18n:sync": "ts-node src/scripts/sync-translations.ts",
19
- "i18n:translate": "ts-node src/scripts/translate-missing.ts"
17
+ "i18n:setup": "node src/scripts/setup-languages.js",
18
+ "i18n:sync": "node src/scripts/sync-translations.js",
19
+ "i18n:translate": "node src/scripts/translate-missing.js"
20
20
  },
21
21
  "keywords": [
22
22
  "react-native",
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Pre-Publish Script
5
+ * Basic checks before publishing
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
12
+ const SRC_DIR = path.join(PACKAGE_ROOT, 'src');
13
+
14
+ if (!fs.existsSync(SRC_DIR)) {
15
+ process.exit(1);
16
+ }
17
+
18
+ const mainFiles = [
19
+ 'src/index.ts',
20
+ 'src/infrastructure/config/i18n.ts',
21
+ 'src/infrastructure/storage/LocalizationStore.ts',
22
+ ];
23
+
24
+ let allFilesExist = true;
25
+ for (const file of mainFiles) {
26
+ const filePath = path.join(PACKAGE_ROOT, file);
27
+ if (!fs.existsSync(filePath)) {
28
+ allFilesExist = false;
29
+ }
30
+ }
31
+
32
+ if (!allFilesExist) {
33
+ process.exit(1);
34
+ }
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Setup Languages Script
5
+ * Generates index.ts with all available translation files
6
+ * Usage: node setup-languages.js [locales-dir]
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ function main() {
13
+ const targetDir = process.argv[2] || 'src/domains/localization/translations';
14
+ const localesDir = path.resolve(process.cwd(), targetDir);
15
+
16
+ console.log('🚀 Setting up language files...\n');
17
+ console.log(`📂 Locales directory: ${localesDir}\n`);
18
+
19
+ if (!fs.existsSync(localesDir)) {
20
+ console.error(`❌ Locales directory not found: ${localesDir}`);
21
+ process.exit(1);
22
+ }
23
+
24
+ const files = fs.readdirSync(localesDir)
25
+ .filter(f => f.match(/^[a-z]{2}-[A-Z]{2}\.ts$/))
26
+ .sort();
27
+
28
+ console.log(`📊 Found ${files.length} language files:\n`);
29
+
30
+ const imports = [];
31
+ const exports = [];
32
+
33
+ files.forEach(file => {
34
+ const code = file.replace('.ts', '');
35
+ const varName = code.replace(/-([a-z0-9])/g, (g) => g[1].toUpperCase()).replace('-', '');
36
+
37
+ console.log(` 📄 ${code}`);
38
+ imports.push(`import ${varName} from "./${code}";`);
39
+ exports.push(` "${code}": ${varName},`);
40
+ });
41
+
42
+ const content = `/**
43
+ * Localization Index
44
+ * Exports all available translation files
45
+ * Auto-generated by scripts/setup-languages.js
46
+ */
47
+
48
+ ${imports.join('\n')}
49
+
50
+ export const translations = {
51
+ ${exports.join('\n')}
52
+ };
53
+
54
+ export type TranslationKey = keyof typeof translations;
55
+
56
+ export default translations;
57
+ `;
58
+
59
+ const indexPath = path.join(localesDir, 'index.ts');
60
+ fs.writeFileSync(indexPath, content);
61
+
62
+ console.log(`\n✅ Generated index.ts with ${files.length} languages`);
63
+ console.log(` Output: ${indexPath}`);
64
+ }
65
+
66
+ main();
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Sync Translations Script
5
+ * Synchronizes translation keys from en-US.ts to all other language files
6
+ * Usage: node sync-translations.js [locales-dir]
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const { parseTypeScriptFile, generateTypeScriptContent } = require('./utils/file-parser');
12
+ const { addMissingKeys, removeExtraKeys } = require('./utils/sync-helper');
13
+ const { getLangDisplayName } = require('./utils/translation-config');
14
+
15
+ function syncLanguageFile(enUSPath, targetPath, langCode) {
16
+ const enUS = parseTypeScriptFile(enUSPath);
17
+ let target;
18
+
19
+ try {
20
+ target = parseTypeScriptFile(targetPath);
21
+ } catch {
22
+ target = {};
23
+ }
24
+
25
+ const addStats = { added: 0 };
26
+ const removeStats = { removed: 0 };
27
+
28
+ addMissingKeys(enUS, target, addStats);
29
+ removeExtraKeys(enUS, target, removeStats);
30
+
31
+ const changed = addStats.added > 0 || removeStats.removed > 0;
32
+
33
+ if (changed) {
34
+ const content = generateTypeScriptContent(target, langCode);
35
+ fs.writeFileSync(targetPath, content);
36
+ }
37
+
38
+ return {
39
+ added: addStats.added,
40
+ removed: removeStats.removed,
41
+ changed,
42
+ };
43
+ }
44
+
45
+ function main() {
46
+ const targetDir = process.argv[2] || 'src/domains/localization/translations';
47
+ const localesDir = path.resolve(process.cwd(), targetDir);
48
+
49
+ console.log('🚀 Starting translation synchronization...\n');
50
+ console.log(`📂 Locales directory: ${localesDir}\n`);
51
+
52
+ if (!fs.existsSync(localesDir)) {
53
+ console.error(`❌ Locales directory not found: ${localesDir}`);
54
+ process.exit(1);
55
+ }
56
+
57
+ const enUSPath = path.join(localesDir, 'en-US.ts');
58
+ if (!fs.existsSync(enUSPath)) {
59
+ console.error(`❌ Base file not found: ${enUSPath}`);
60
+ process.exit(1);
61
+ }
62
+
63
+ const files = fs.readdirSync(localesDir)
64
+ .filter(f => f.match(/^[a-z]{2}-[A-Z]{2}\.ts$/) && f !== 'en-US.ts')
65
+ .sort();
66
+
67
+ console.log(`📊 Languages to sync: ${files.length}\n`);
68
+
69
+ let totalAdded = 0;
70
+ let totalRemoved = 0;
71
+ let totalChanged = 0;
72
+
73
+ for (const file of files) {
74
+ const langCode = file.replace('.ts', '');
75
+ const targetPath = path.join(localesDir, file);
76
+
77
+ console.log(`🌍 Syncing ${langCode} (${getLangDisplayName(langCode)})...`);
78
+
79
+ const result = syncLanguageFile(enUSPath, targetPath, langCode);
80
+
81
+ if (result.changed) {
82
+ console.log(` ✏️ +${result.added} keys, -${result.removed} keys`);
83
+ totalAdded += result.added;
84
+ totalRemoved += result.removed;
85
+ totalChanged++;
86
+ } else {
87
+ console.log(` ✅ Already synchronized`);
88
+ }
89
+ }
90
+
91
+ console.log(`\n📊 Summary:`);
92
+ console.log(` Languages processed: ${files.length}`);
93
+ console.log(` Files changed: ${totalChanged}`);
94
+ console.log(` Keys added: ${totalAdded}`);
95
+ console.log(` Keys removed: ${totalRemoved}`);
96
+
97
+ if (totalChanged > 0) {
98
+ console.log(`\n✅ Synchronization completed!`);
99
+ console.log(` Next: Run 'npm run i18n:translate' to translate new keys`);
100
+ } else {
101
+ console.log(`\n✅ All languages were already synchronized!`);
102
+ }
103
+ }
104
+
105
+ main();
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Translate Missing Script
5
+ * Translates missing strings from en-US.ts to all other language files
6
+ * Usage: node translate-missing.js [locales-dir]
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const { getTargetLanguage, isEnglishVariant, getLangDisplayName } = require('./utils/translation-config');
12
+ const { parseTypeScriptFile, generateTypeScriptContent } = require('./utils/file-parser');
13
+ const { translateObject } = require('./utils/translator');
14
+
15
+ async function translateLanguageFile(enUSPath, targetPath, langCode) {
16
+ const targetLang = getTargetLanguage(langCode);
17
+
18
+ if (!targetLang) {
19
+ console.log(` ⚠️ No language mapping for ${langCode}, skipping`);
20
+ return 0;
21
+ }
22
+
23
+ if (isEnglishVariant(langCode)) {
24
+ console.log(` ⏭️ Skipping English variant: ${langCode}`);
25
+ return 0;
26
+ }
27
+
28
+ const enUS = parseTypeScriptFile(enUSPath);
29
+ let target;
30
+
31
+ try {
32
+ target = parseTypeScriptFile(targetPath);
33
+ } catch {
34
+ target = {};
35
+ }
36
+
37
+ const stats = { count: 0 };
38
+ await translateObject(enUS, target, targetLang, '', stats);
39
+
40
+ if (stats.count > 0) {
41
+ const content = generateTypeScriptContent(target, langCode);
42
+ fs.writeFileSync(targetPath, content);
43
+ }
44
+
45
+ return stats.count;
46
+ }
47
+
48
+ async function main() {
49
+ const targetDir = process.argv[2] || 'src/domains/localization/translations';
50
+ const localesDir = path.resolve(process.cwd(), targetDir);
51
+
52
+ console.log('🚀 Starting automatic translation...\n');
53
+ console.log(`📂 Locales directory: ${localesDir}\n`);
54
+
55
+ if (!fs.existsSync(localesDir)) {
56
+ console.error(`❌ Locales directory not found: ${localesDir}`);
57
+ process.exit(1);
58
+ }
59
+
60
+ const enUSPath = path.join(localesDir, 'en-US.ts');
61
+ if (!fs.existsSync(enUSPath)) {
62
+ console.error(`❌ Base file not found: ${enUSPath}`);
63
+ process.exit(1);
64
+ }
65
+
66
+ const files = fs.readdirSync(localesDir)
67
+ .filter(f => f.match(/^[a-z]{2}-[A-Z]{2}\.ts$/) && f !== 'en-US.ts')
68
+ .sort();
69
+
70
+ console.log(`📊 Languages to translate: ${files.length}`);
71
+ console.log('⚡ Running with 200ms delay between API calls\n');
72
+
73
+ let totalTranslated = 0;
74
+
75
+ for (const file of files) {
76
+ const langCode = file.replace('.ts', '');
77
+ const targetPath = path.join(localesDir, file);
78
+
79
+ console.log(`\n🌍 Translating ${langCode} (${getLangDisplayName(langCode)})...`);
80
+
81
+ const count = await translateLanguageFile(enUSPath, targetPath, langCode);
82
+ totalTranslated += count;
83
+
84
+ if (count > 0) {
85
+ console.log(` ✅ Translated ${count} strings`);
86
+ } else {
87
+ console.log(` ✓ Already complete`);
88
+ }
89
+ }
90
+
91
+ console.log(`\n✅ Translation completed!`);
92
+ console.log(` Total strings translated: ${totalTranslated}`);
93
+ console.log(`\n📝 Next: Run 'npm run i18n:setup' to update index.ts`);
94
+ }
95
+
96
+ main().catch((error) => {
97
+ console.error('❌ Translation failed:', error.message);
98
+ process.exit(1);
99
+ });
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * File Parser
5
+ * Parse and generate TypeScript translation files
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const { getLangDisplayName } = require('./translation-config');
10
+
11
+ function parseTypeScriptFile(filePath) {
12
+ const content = fs.readFileSync(filePath, 'utf8');
13
+ const match = content.match(/export\s+default\s+(\{[\s\S]*\});?\s*$/);
14
+
15
+ if (!match) {
16
+ throw new Error(`Could not parse TypeScript file: ${filePath}`);
17
+ }
18
+
19
+ const objectStr = match[1].replace(/;$/, '');
20
+
21
+ try {
22
+ return eval(`(${objectStr})`);
23
+ } catch (error) {
24
+ throw new Error(`Failed to parse object in ${filePath}: ${error.message}`);
25
+ }
26
+ }
27
+
28
+ function stringifyValue(value, indent = 2) {
29
+ if (typeof value === 'string') {
30
+ const escaped = value
31
+ .replace(/\\/g, '\\\\')
32
+ .replace(/"/g, '\\"')
33
+ .replace(/\n/g, '\\n');
34
+ return `"${escaped}"`;
35
+ }
36
+
37
+ if (Array.isArray(value)) {
38
+ if (value.length === 0) return '[]';
39
+ const items = value.map(v => stringifyValue(v, indent + 2));
40
+ return `[${items.join(', ')}]`;
41
+ }
42
+
43
+ if (typeof value === 'object' && value !== null) {
44
+ const entries = Object.entries(value);
45
+
46
+ if (entries.length === 0) {
47
+ return '{}';
48
+ }
49
+
50
+ const spaces = ' '.repeat(indent);
51
+ const innerSpaces = ' '.repeat(indent + 2);
52
+ const entriesStr = entries
53
+ .map(([k, v]) => {
54
+ const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? k : `"${k}"`;
55
+ return `${innerSpaces}${key}: ${stringifyValue(v, indent + 2)}`;
56
+ })
57
+ .join(',\n');
58
+ return `{\n${entriesStr},\n${spaces}}`;
59
+ }
60
+
61
+ return String(value);
62
+ }
63
+
64
+ function generateTypeScriptContent(obj, langCode) {
65
+ const langName = getLangDisplayName(langCode);
66
+ const objString = stringifyValue(obj, 0);
67
+
68
+ return `/**
69
+ * ${langName} Translations
70
+ * Auto-translated from en-US.ts
71
+ */
72
+
73
+ export default ${objString};
74
+ `;
75
+ }
76
+
77
+ module.exports = {
78
+ parseTypeScriptFile,
79
+ generateTypeScriptContent,
80
+ };
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Sync Helper
5
+ * Helper functions for synchronizing translation keys
6
+ */
7
+
8
+ function addMissingKeys(enObj, targetObj, stats = { added: 0 }) {
9
+ for (const key in enObj) {
10
+ if (!Object.prototype.hasOwnProperty.call(targetObj, key)) {
11
+ targetObj[key] = enObj[key];
12
+ stats.added++;
13
+ } else if (
14
+ typeof enObj[key] === 'object' &&
15
+ enObj[key] !== null &&
16
+ !Array.isArray(enObj[key])
17
+ ) {
18
+ if (!targetObj[key] || typeof targetObj[key] !== 'object') {
19
+ targetObj[key] = {};
20
+ }
21
+ addMissingKeys(enObj[key], targetObj[key], stats);
22
+ }
23
+ }
24
+ return stats;
25
+ }
26
+
27
+ function removeExtraKeys(enObj, targetObj, stats = { removed: 0 }) {
28
+ for (const key in targetObj) {
29
+ if (!Object.prototype.hasOwnProperty.call(enObj, key)) {
30
+ delete targetObj[key];
31
+ stats.removed++;
32
+ } else if (
33
+ typeof enObj[key] === 'object' &&
34
+ enObj[key] !== null &&
35
+ !Array.isArray(enObj[key]) &&
36
+ typeof targetObj[key] === 'object' &&
37
+ targetObj[key] !== null &&
38
+ !Array.isArray(targetObj[key])
39
+ ) {
40
+ removeExtraKeys(enObj[key], targetObj[key], stats);
41
+ }
42
+ }
43
+ return stats;
44
+ }
45
+
46
+ module.exports = {
47
+ addMissingKeys,
48
+ removeExtraKeys,
49
+ };
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Translation Configuration
5
+ * Language mappings and constants for translation system
6
+ */
7
+
8
+ const LANGUAGE_MAP = {
9
+ 'ar-SA': 'ar',
10
+ 'bg-BG': 'bg',
11
+ 'cs-CZ': 'cs',
12
+ 'da-DK': 'da',
13
+ 'de-DE': 'de',
14
+ 'el-GR': 'el',
15
+ 'en-AU': 'en',
16
+ 'en-CA': 'en',
17
+ 'en-GB': 'en',
18
+ 'es-ES': 'es',
19
+ 'es-MX': 'es',
20
+ 'fi-FI': 'fi',
21
+ 'fr-CA': 'fr',
22
+ 'fr-FR': 'fr',
23
+ 'hi-IN': 'hi',
24
+ 'hr-HR': 'hr',
25
+ 'hu-HU': 'hu',
26
+ 'id-ID': 'id',
27
+ 'it-IT': 'it',
28
+ 'ja-JP': 'ja',
29
+ 'ko-KR': 'ko',
30
+ 'ms-MY': 'ms',
31
+ 'nl-NL': 'nl',
32
+ 'no-NO': 'no',
33
+ 'pl-PL': 'pl',
34
+ 'pt-BR': 'pt',
35
+ 'pt-PT': 'pt',
36
+ 'ro-RO': 'ro',
37
+ 'ru-RU': 'ru',
38
+ 'sk-SK': 'sk',
39
+ 'sv-SE': 'sv',
40
+ 'th-TH': 'th',
41
+ 'tl-PH': 'tl',
42
+ 'tr-TR': 'tr',
43
+ 'uk-UA': 'uk',
44
+ 'vi-VN': 'vi',
45
+ 'zh-CN': 'zh-CN',
46
+ 'zh-TW': 'zh-TW',
47
+ };
48
+
49
+ const SKIP_WORDS = new Set([
50
+ 'OK',
51
+ 'Email',
52
+ 'Google',
53
+ 'Apple',
54
+ 'Facebook',
55
+ 'Premium',
56
+ 'Pro',
57
+ 'Plus',
58
+ 'BPM',
59
+ ]);
60
+
61
+ const LANGUAGE_NAMES = {
62
+ 'ar-SA': 'Arabic (Saudi Arabia)',
63
+ 'bg-BG': 'Bulgarian',
64
+ 'cs-CZ': 'Czech',
65
+ 'da-DK': 'Danish',
66
+ 'de-DE': 'German',
67
+ 'el-GR': 'Greek',
68
+ 'en-AU': 'English (Australia)',
69
+ 'en-CA': 'English (Canada)',
70
+ 'en-GB': 'English (UK)',
71
+ 'en-US': 'English (US)',
72
+ 'es-ES': 'Spanish (Spain)',
73
+ 'es-MX': 'Spanish (Mexico)',
74
+ 'fi-FI': 'Finnish',
75
+ 'fr-CA': 'French (Canada)',
76
+ 'fr-FR': 'French (France)',
77
+ 'hi-IN': 'Hindi',
78
+ 'hr-HR': 'Croatian',
79
+ 'hu-HU': 'Hungarian',
80
+ 'id-ID': 'Indonesian',
81
+ 'it-IT': 'Italian',
82
+ 'ja-JP': 'Japanese',
83
+ 'ko-KR': 'Korean',
84
+ 'ms-MY': 'Malay',
85
+ 'nl-NL': 'Dutch',
86
+ 'no-NO': 'Norwegian',
87
+ 'pl-PL': 'Polish',
88
+ 'pt-BR': 'Portuguese (Brazil)',
89
+ 'pt-PT': 'Portuguese (Portugal)',
90
+ 'ro-RO': 'Romanian',
91
+ 'ru-RU': 'Russian',
92
+ 'sk-SK': 'Slovak',
93
+ 'sv-SE': 'Swedish',
94
+ 'th-TH': 'Thai',
95
+ 'tl-PH': 'Tagalog',
96
+ 'tr-TR': 'Turkish',
97
+ 'uk-UA': 'Ukrainian',
98
+ 'vi-VN': 'Vietnamese',
99
+ 'zh-CN': 'Chinese (Simplified)',
100
+ 'zh-TW': 'Chinese (Traditional)',
101
+ };
102
+
103
+ function getLangDisplayName(code) {
104
+ return LANGUAGE_NAMES[code] || code;
105
+ }
106
+
107
+ function getTargetLanguage(langCode) {
108
+ return LANGUAGE_MAP[langCode];
109
+ }
110
+
111
+ function shouldSkipWord(word) {
112
+ return SKIP_WORDS.has(word);
113
+ }
114
+
115
+ function isEnglishVariant(langCode) {
116
+ const targetLang = LANGUAGE_MAP[langCode];
117
+ return targetLang === 'en';
118
+ }
119
+
120
+ module.exports = {
121
+ LANGUAGE_MAP,
122
+ SKIP_WORDS,
123
+ LANGUAGE_NAMES,
124
+ getLangDisplayName,
125
+ getTargetLanguage,
126
+ shouldSkipWord,
127
+ isEnglishVariant,
128
+ };
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Translator
5
+ * Google Translate API integration and translation logic
6
+ */
7
+
8
+ const https = require('https');
9
+ const { shouldSkipWord } = require('./translation-config');
10
+
11
+ function delay(ms) {
12
+ return new Promise(resolve => setTimeout(resolve, ms));
13
+ }
14
+
15
+ async function translateText(text, targetLang) {
16
+ return new Promise((resolve) => {
17
+ if (shouldSkipWord(text)) {
18
+ resolve(text);
19
+ return;
20
+ }
21
+
22
+ const encodedText = encodeURIComponent(text);
23
+ const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodedText}`;
24
+
25
+ https
26
+ .get(url, res => {
27
+ let data = '';
28
+ res.on('data', chunk => {
29
+ data += chunk;
30
+ });
31
+ res.on('end', () => {
32
+ try {
33
+ const parsed = JSON.parse(data);
34
+ const translated = parsed[0]
35
+ .map(item => item[0])
36
+ .join('')
37
+ .trim();
38
+ resolve(translated || text);
39
+ } catch (error) {
40
+ resolve(text);
41
+ }
42
+ });
43
+ })
44
+ .on('error', () => {
45
+ resolve(text);
46
+ });
47
+ });
48
+ }
49
+
50
+ function needsTranslation(value, enValue) {
51
+ if (typeof value !== 'string') return false;
52
+ if (value === enValue) return true;
53
+ if (shouldSkipWord(value)) return false;
54
+ return false;
55
+ }
56
+
57
+ async function translateObject(enObj, targetObj, targetLang, path = '', stats = { count: 0 }) {
58
+ for (const key in enObj) {
59
+ const currentPath = path ? `${path}.${key}` : key;
60
+ const enValue = enObj[key];
61
+ const targetValue = targetObj[key];
62
+
63
+ if (Array.isArray(enValue)) {
64
+ if (!Array.isArray(targetValue)) {
65
+ targetObj[key] = [];
66
+ }
67
+ for (let i = 0; i < enValue.length; i++) {
68
+ if (typeof enValue[i] === 'string') {
69
+ if (needsTranslation(targetObj[key][i], enValue[i])) {
70
+ const preview = enValue[i].length > 40 ? enValue[i].substring(0, 40) + '...' : enValue[i];
71
+ console.log(` 🔄 ${currentPath}[${i}]: "${preview}"`);
72
+ targetObj[key][i] = await translateText(enValue[i], targetLang);
73
+ stats.count++;
74
+ await delay(200);
75
+ }
76
+ }
77
+ }
78
+ } else if (typeof enValue === 'object' && enValue !== null) {
79
+ if (!targetObj[key] || typeof targetObj[key] !== 'object') {
80
+ targetObj[key] = {};
81
+ }
82
+ await translateObject(enValue, targetObj[key], targetLang, currentPath, stats);
83
+ } else if (typeof enValue === 'string') {
84
+ if (needsTranslation(targetValue, enValue)) {
85
+ const preview = enValue.length > 40 ? enValue.substring(0, 40) + '...' : enValue;
86
+ console.log(` 🔄 ${currentPath}: "${preview}"`);
87
+ targetObj[key] = await translateText(enValue, targetLang);
88
+ stats.count++;
89
+ await delay(200);
90
+ }
91
+ }
92
+ }
93
+
94
+ return stats.count;
95
+ }
96
+
97
+ module.exports = {
98
+ translateText,
99
+ translateObject,
100
+ delay,
101
+ };