@umituz/react-native-settings 5.4.21 → 5.4.22

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-settings",
3
- "version": "5.4.21",
3
+ "version": "5.4.22",
4
4
  "description": "Complete settings hub for React Native apps - consolidated package with settings, localization, about, legal, appearance, feedback, FAQs, rating, and gamification - expo-store-review and expo-device now lazy loaded",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./dist/index.d.ts",
@@ -124,6 +124,7 @@
124
124
  "@react-navigation/stack": ">=6.0.0",
125
125
  "@tanstack/react-query": ">=5.0.0",
126
126
  "@umituz/react-native-design-system": "*",
127
+ "@umituz/react-native-google-translate": "*",
127
128
  "expo": ">=54.0.0",
128
129
  "expo-constants": ">=55.0.0",
129
130
  "expo-device": ">=6.0.0",
@@ -162,6 +163,7 @@
162
163
  "@umituz/react-native-auth": "^4.3.39",
163
164
  "@umituz/react-native-design-system": "^4.27.0",
164
165
  "@umituz/react-native-firebase": "^2.4.55",
166
+ "@umituz/react-native-google-translate": "^1.0.0",
165
167
  "@umituz/react-native-sentry": "latest",
166
168
  "eslint": "^8.57.0",
167
169
  "eslint-plugin-react": "^7.37.5",
@@ -16,8 +16,10 @@
16
16
  */
17
17
 
18
18
  import React, { memo } from 'react';
19
- import { Modal, View, StyleSheet } from 'react-native';
19
+ import { Modal, View } from 'react-native';
20
20
  import { AIConsentScreen, type AIProvider } from '../screens/AIConsentScreen';
21
+ import { useThemedStyleSheet } from '@umituz/react-native-design-system/theme';
22
+ import type { Theme } from '@umituz/react-native-design-system/theme';
21
23
 
22
24
  export interface AIConsentModalProps {
23
25
  visible: boolean;
@@ -34,6 +36,8 @@ export const AIConsentModal: React.FC<AIConsentModalProps> = memo(({
34
36
  providers,
35
37
  customMessage,
36
38
  }) => {
39
+ const styles = useThemedStyleSheet(createStyles);
40
+
37
41
  return (
38
42
  <Modal
39
43
  visible={visible}
@@ -56,9 +60,9 @@ export const AIConsentModal: React.FC<AIConsentModalProps> = memo(({
56
60
 
57
61
  AIConsentModal.displayName = 'AIConsentModal';
58
62
 
59
- const styles = StyleSheet.create({
63
+ const createStyles = (theme: Theme) => ({
60
64
  container: {
61
65
  flex: 1,
62
- backgroundColor: '#FFFFFF',
66
+ backgroundColor: theme.colors.backgroundPrimary,
63
67
  },
64
68
  });
@@ -15,7 +15,6 @@
15
15
  import React, { memo } from 'react';
16
16
  import {
17
17
  View,
18
- StyleSheet,
19
18
  ScrollView,
20
19
  TouchableOpacity,
21
20
  } from 'react-native';
@@ -31,7 +30,8 @@ import {
31
30
  NavigationHeader,
32
31
  useAppNavigation,
33
32
  } from '@umituz/react-native-design-system/molecules';
34
- import { useAppDesignTokens } from '@umituz/react-native-design-system/theme';
33
+ import { useThemedStyleSheet } from '@umituz/react-native-design-system/theme';
34
+ import type { Theme } from '@umituz/react-native-design-system/theme';
35
35
 
36
36
  export interface AIProvider {
37
37
  name: string;
@@ -85,7 +85,7 @@ export const AIConsentScreen: React.FC<AIConsentScreenProps> = memo(({
85
85
  standalone = false,
86
86
  }) => {
87
87
  const navigation = useAppNavigation();
88
- const tokens = useAppDesignTokens();
88
+ const styles = useThemedStyleSheet(createStyles);
89
89
  const [loading, setLoading] = React.useState(false);
90
90
 
91
91
  // Get params from route or use props
@@ -289,7 +289,7 @@ export const AIConsentScreen: React.FC<AIConsentScreenProps> = memo(({
289
289
 
290
290
  AIConsentScreen.displayName = 'AIConsentScreen';
291
291
 
292
- const styles = StyleSheet.create({
292
+ const createStyles = (theme: Theme) => ({
293
293
  scrollView: {
294
294
  flex: 1,
295
295
  },
@@ -300,32 +300,32 @@ const styles = StyleSheet.create({
300
300
  fontSize: 15,
301
301
  lineHeight: 22,
302
302
  marginBottom: 24,
303
- color: '#374151',
303
+ color: theme.colors.textSecondary,
304
304
  },
305
305
  section: {
306
306
  marginBottom: 24,
307
307
  padding: 16,
308
- backgroundColor: '#F9FAFB',
308
+ backgroundColor: theme.colors.surfaceVariant,
309
309
  borderRadius: 12,
310
310
  },
311
311
  sectionTitle: {
312
312
  fontSize: 17,
313
313
  fontWeight: '600',
314
- color: '#111827',
314
+ color: theme.colors.textPrimary,
315
315
  marginBottom: 12,
316
316
  },
317
317
  providerList: {
318
318
  gap: 12,
319
319
  },
320
320
  providerItem: {
321
- backgroundColor: '#FFFFFF',
321
+ backgroundColor: theme.colors.surface,
322
322
  padding: 12,
323
323
  borderRadius: 8,
324
324
  borderWidth: 1,
325
- borderColor: '#E5E7EB',
325
+ borderColor: theme.colors.borderLight,
326
326
  },
327
327
  providerHeader: {
328
- flexDirection: 'row',
328
+ flexDirection: 'row' as const,
329
329
  justifyContent: 'space-between',
330
330
  alignItems: 'center',
331
331
  marginBottom: 4,
@@ -333,26 +333,26 @@ const styles = StyleSheet.create({
333
333
  providerName: {
334
334
  fontSize: 15,
335
335
  fontWeight: '600',
336
- color: '#111827',
336
+ color: theme.colors.textPrimary,
337
337
  },
338
338
  privacyLink: {
339
339
  fontSize: 13,
340
- color: '#3B82F6',
340
+ color: theme.colors.primary,
341
341
  },
342
342
  providerPurpose: {
343
343
  fontSize: 14,
344
- color: '#6B7280',
344
+ color: theme.colors.textTertiary,
345
345
  },
346
346
  bullet: {
347
347
  fontSize: 15,
348
- color: '#374151',
348
+ color: theme.colors.textSecondary,
349
349
  lineHeight: 22,
350
350
  marginLeft: 8,
351
351
  },
352
352
  note: {
353
353
  fontSize: 13,
354
- color: '#6B7280',
355
- fontStyle: 'italic',
354
+ color: theme.colors.textTertiary,
355
+ fontStyle: 'italic' as const,
356
356
  marginLeft: 8,
357
357
  marginTop: 4,
358
358
  },
@@ -362,15 +362,15 @@ const styles = StyleSheet.create({
362
362
  },
363
363
  linkText: {
364
364
  fontSize: 15,
365
- color: '#3B82F6',
365
+ color: theme.colors.primary,
366
366
  fontWeight: '500',
367
367
  },
368
368
  declarationSection: {
369
- flexDirection: 'row',
369
+ flexDirection: 'row' as const,
370
370
  alignItems: 'flex-start',
371
371
  marginTop: 8,
372
372
  padding: 12,
373
- backgroundColor: '#EFF6FF',
373
+ backgroundColor: theme.colors.primaryBackground || 'rgba(90, 175, 127, 0.15)',
374
374
  borderRadius: 8,
375
375
  },
376
376
  checkbox: {
@@ -383,26 +383,26 @@ const styles = StyleSheet.create({
383
383
  width: 24,
384
384
  height: 24,
385
385
  borderRadius: 4,
386
- backgroundColor: '#3B82F6',
387
- alignItems: 'center',
388
- justifyContent: 'center',
386
+ backgroundColor: theme.colors.primary,
387
+ alignItems: 'center' as const,
388
+ justifyContent: 'center' as const,
389
389
  },
390
390
  checkmark: {
391
- color: '#FFFFFF',
391
+ color: theme.colors.onPrimary || '#FFFFFF',
392
392
  fontSize: 16,
393
393
  fontWeight: '700',
394
394
  },
395
395
  declarationText: {
396
396
  flex: 1,
397
397
  fontSize: 14,
398
- color: '#1E3A8A',
398
+ color: theme.colors.textPrimary,
399
399
  lineHeight: 20,
400
400
  },
401
401
  footer: {
402
- flexDirection: 'row',
402
+ flexDirection: 'row' as const,
403
403
  padding: 16,
404
404
  borderTopWidth: 1,
405
- borderTopColor: '#E5E7EB',
405
+ borderTopColor: theme.colors.borderLight,
406
406
  gap: 12,
407
407
  },
408
408
  declineButton: {
@@ -3,17 +3,24 @@
3
3
  /**
4
4
  * Translate Missing Script
5
5
  * Automatically translates missing strings using Google Translate
6
+ * Refactored to use @umituz/react-native-google-translate package
6
7
  */
7
8
 
8
9
  import fs from 'fs';
9
10
  import path from 'path';
10
11
  import { parseTypeScriptFile, generateTypeScriptContent } from './utils/file-parser.js';
11
- import { getTargetLanguage, getLangDisplayName } from './utils/translation-config.js';
12
- import { translateObject } from './utils/translator.js';
12
+ import { googleTranslateService } from '@umituz/react-native-google-translate/services';
13
13
  import { setupLanguages } from './setup-languages.js';
14
14
  import { syncTranslations } from './sync-translations.js';
15
15
 
16
16
  async function translateMissing(targetDir, srcDir) {
17
+ // Initialize the translation service
18
+ googleTranslateService.initialize({
19
+ minDelay: 100,
20
+ maxRetries: 3,
21
+ timeout: 10000,
22
+ });
23
+
17
24
  const localesDir = path.resolve(process.cwd(), targetDir);
18
25
  const enUSPath = path.join(localesDir, 'en-US.ts');
19
26
 
@@ -41,27 +48,44 @@ async function translateMissing(targetDir, srcDir) {
41
48
 
42
49
  for (const file of files) {
43
50
  const langCode = file.replace('.ts', '');
44
- const targetLang = getTargetLanguage(langCode);
45
- const langName = getLangDisplayName(langCode);
46
51
 
47
- if (!targetLang || targetLang === 'en') continue;
52
+ // Skip English variants
53
+ const targetLang = getTargetLanguage(langCode);
54
+ if (!targetLang || targetLang === 'en') {
55
+ console.log(`⏭️ Skipping ${langCode} (English variant)`);
56
+ continue;
57
+ }
48
58
 
59
+ const langName = getLanguageDisplayName(langCode);
49
60
  console.log(`🌍 Translating ${langCode} (${langName})...`);
50
61
 
51
62
  const targetPath = path.join(localesDir, file);
52
63
  const target = parseTypeScriptFile(targetPath);
53
64
 
54
- const stats = { count: 0, checked: 0, translatedKeys: [] };
55
- await translateObject(enUS, target, targetLang, '', stats);
65
+ const stats = {
66
+ totalCount: 0,
67
+ successCount: 0,
68
+ failureCount: 0,
69
+ skippedCount: 0,
70
+ translatedKeys: [],
71
+ };
72
+
73
+ await googleTranslateService.translateObject(
74
+ enUS,
75
+ target,
76
+ targetLang,
77
+ '',
78
+ stats
79
+ );
56
80
 
57
81
  // Clear progress line
58
82
  process.stdout.write('\r' + ' '.repeat(80) + '\r');
59
83
 
60
- if (stats.count > 0) {
84
+ if (stats.successCount > 0) {
61
85
  const content = generateTypeScriptContent(target, langCode);
62
86
  fs.writeFileSync(targetPath, content);
63
87
 
64
- console.log(` ✅ Successfully translated ${stats.count} keys:`);
88
+ console.log(` ✅ Successfully translated ${stats.successCount} keys:`);
65
89
 
66
90
  // Detailed logging of translated keys
67
91
  const displayCount = Math.min(stats.translatedKeys.length, 15);
@@ -80,6 +104,100 @@ async function translateMissing(targetDir, srcDir) {
80
104
  console.log('\n✅ All translations completed!');
81
105
  }
82
106
 
107
+ // Helper functions (can be replaced with package imports later)
108
+ const LANGUAGE_MAP = {
109
+ 'ar-SA': 'ar',
110
+ 'bg-BG': 'bg',
111
+ 'cs-CZ': 'cs',
112
+ 'da-DK': 'da',
113
+ 'de-DE': 'de',
114
+ 'el-GR': 'el',
115
+ 'en-AU': 'en',
116
+ 'en-CA': 'en',
117
+ 'en-GB': 'en',
118
+ 'es-ES': 'es',
119
+ 'es-MX': 'es',
120
+ 'fi-FI': 'fi',
121
+ 'fr-CA': 'fr',
122
+ 'fr-FR': 'fr',
123
+ 'hi-IN': 'hi',
124
+ 'hr-HR': 'hr',
125
+ 'hu-HU': 'hu',
126
+ 'id-ID': 'id',
127
+ 'it-IT': 'it',
128
+ 'ja-JP': 'ja',
129
+ 'ko-KR': 'ko',
130
+ 'ms-MY': 'ms',
131
+ 'nl-NL': 'nl',
132
+ 'no-NO': 'no',
133
+ 'pl-PL': 'pl',
134
+ 'pt-BR': 'pt',
135
+ 'pt-PT': 'pt',
136
+ 'ro-RO': 'ro',
137
+ 'ru-RU': 'ru',
138
+ 'sk-SK': 'sk',
139
+ 'sl-SI': 'sl',
140
+ 'sv-SE': 'sv',
141
+ 'th-TH': 'th',
142
+ 'tl-PH': 'tl',
143
+ 'tr-TR': 'tr',
144
+ 'uk-UA': 'uk',
145
+ 'vi-VN': 'vi',
146
+ 'zh-CN': 'zh-CN',
147
+ 'zh-TW': 'zh-TW',
148
+ };
149
+
150
+ const LANGUAGE_NAMES = {
151
+ 'ar-SA': 'Arabic (Saudi Arabia)',
152
+ 'bg-BG': 'Bulgarian',
153
+ 'cs-CZ': 'Czech',
154
+ 'da-DK': 'Danish',
155
+ 'de-DE': 'German',
156
+ 'el-GR': 'Greek',
157
+ 'en-AU': 'English (Australia)',
158
+ 'en-CA': 'English (Canada)',
159
+ 'en-GB': 'English (UK)',
160
+ 'en-US': 'English (US)',
161
+ 'es-ES': 'Spanish (Spain)',
162
+ 'es-MX': 'Spanish (Mexico)',
163
+ 'fi-FI': 'Finnish',
164
+ 'fr-CA': 'French (Canada)',
165
+ 'fr-FR': 'French (France)',
166
+ 'hi-IN': 'Hindi',
167
+ 'hr-HR': 'Croatian',
168
+ 'hu-HU': 'Hungarian',
169
+ 'id-ID': 'Indonesian',
170
+ 'it-IT': 'Italian',
171
+ 'ja-JP': 'Japanese',
172
+ 'ko-KR': 'Korean',
173
+ 'ms-MY': 'Malay',
174
+ 'nl-NL': 'Dutch',
175
+ 'no-NO': 'Norwegian',
176
+ 'pl-PL': 'Polish',
177
+ 'pt-BR': 'Portuguese (Brazil)',
178
+ 'pt-PT': 'Portuguese (Portugal)',
179
+ 'ro-RO': 'Romanian',
180
+ 'ru-RU': 'Russian',
181
+ 'sk-SK': 'Slovak',
182
+ 'sl-SI': 'Slovenian',
183
+ 'sv-SE': 'Swedish',
184
+ 'th-TH': 'Thai',
185
+ 'tl-PH': 'Tagalog',
186
+ 'tr-TR': 'Turkish',
187
+ 'uk-UA': 'Ukrainian',
188
+ 'vi-VN': 'Vietnamese',
189
+ 'zh-CN': 'Chinese (Simplified)',
190
+ 'zh-TW': 'Chinese (Traditional)',
191
+ };
192
+
193
+ function getTargetLanguage(langCode) {
194
+ return LANGUAGE_MAP[langCode];
195
+ }
196
+
197
+ function getLanguageDisplayName(code) {
198
+ return LANGUAGE_NAMES[code] || code;
199
+ }
200
+
83
201
  const isMainModule = import.meta.url.endsWith('translate-missing.js');
84
202
  if (isMainModule) {
85
203
  const args = process.argv.slice(2).filter(arg => !arg.startsWith('--'));