@umituz/react-native-localization 3.7.22 → 3.7.24

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.7.22",
3
+ "version": "3.7.24",
4
4
  "type": "module",
5
5
  "description": "Generic localization system for React Native apps with i18n support",
6
6
  "main": "./src/index.ts",
@@ -7,6 +7,8 @@
7
7
  * - i18n setup
8
8
  */
9
9
 
10
+ declare const __DEV__: boolean;
11
+
10
12
  import { storageRepository } from '@umituz/react-native-design-system';
11
13
  import i18n from '../config/i18n';
12
14
  import { languageRepository } from '../repository/LanguageRepository';
@@ -31,7 +33,9 @@ export class LanguageInitializer {
31
33
 
32
34
  return finalLanguage;
33
35
  } catch {
34
- console.warn("[LanguageInitializer] Failed to restore language, falling back to device locale");
36
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
37
+ console.warn("[LanguageInitializer] Failed to restore language, falling back to device locale");
38
+ }
35
39
  return await this.setupFallbackLanguage();
36
40
  }
37
41
  }
@@ -66,14 +70,12 @@ export class LanguageInitializer {
66
70
  languageCode: string;
67
71
  isRTL: boolean;
68
72
  }> {
69
- try {
70
- await i18n.changeLanguage(DEFAULT_LANGUAGE);
71
- return {
72
- languageCode: DEFAULT_LANGUAGE,
73
- isRTL: false,
74
- };
75
- } catch (fallbackError) {
76
- throw fallbackError;
77
- }
73
+ // No try-catch needed - let errors propagate naturally
74
+ // This preserves the full stack trace
75
+ await i18n.changeLanguage(DEFAULT_LANGUAGE);
76
+ return {
77
+ languageCode: DEFAULT_LANGUAGE,
78
+ isRTL: false,
79
+ };
78
80
  }
79
81
  }
@@ -6,6 +6,8 @@
6
6
  * - Persistence
7
7
  */
8
8
 
9
+ declare const __DEV__: boolean;
10
+
9
11
  import { storageRepository } from '@umituz/react-native-design-system';
10
12
  import i18n from '../config/i18n';
11
13
  import { languageRepository } from '../repository/LanguageRepository';
@@ -20,17 +22,27 @@ export class LanguageSwitcher {
20
22
  languageCode: string;
21
23
  isRTL: boolean;
22
24
  }> {
23
- console.log('[LanguageSwitcher] switchLanguage called:', languageCode);
25
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
26
+ console.log('[LanguageSwitcher] switchLanguage called:', languageCode);
27
+ }
28
+
24
29
  const language = languageRepository.getLanguageByCode(languageCode);
25
- console.log('[LanguageSwitcher] Language object:', language);
26
30
 
27
- console.log('[LanguageSwitcher] Calling i18n.changeLanguage...');
31
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
32
+ console.log('[LanguageSwitcher] Language object:', language);
33
+ }
34
+
28
35
  await i18n.changeLanguage(languageCode);
29
- console.log('[LanguageSwitcher] i18n language changed to:', i18n.language);
30
36
 
31
- console.log('[LanguageSwitcher] Saving to storage...');
37
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
38
+ console.log('[LanguageSwitcher] i18n language changed to:', i18n.language);
39
+ }
40
+
32
41
  await storageRepository.setString(LANGUAGE_STORAGE_KEY, languageCode);
33
- console.log('[LanguageSwitcher] Saved to storage');
42
+
43
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
44
+ console.log('[LanguageSwitcher] Saved to storage');
45
+ }
34
46
 
35
47
  return {
36
48
  languageCode,
@@ -9,8 +9,18 @@ import { LanguageInitializer } from './LanguageInitializer';
9
9
  import { LanguageSwitcher } from './LanguageSwitcher';
10
10
  import { languageRepository } from '../repository/LanguageRepository';
11
11
 
12
+ declare const __DEV__: boolean;
13
+
12
14
  type LocalizationStoreType = LocalizationState & LocalizationActions & LocalizationGetters;
13
15
 
16
+ // Mutex to prevent race condition in initialize
17
+ let initializeInProgress = false;
18
+ // Debounce timer for language switching
19
+ let languageSwitchTimer: ReturnType<typeof setTimeout> | null = null;
20
+ const LANGUAGE_SWITCH_DEBOUNCE_MS = 300;
21
+ // Track pending promise resolvers to ensure all get resolved
22
+ let pendingResolvers: Array<() => void> = [];
23
+
14
24
  export const useLocalizationStore = create<LocalizationStoreType>((set, get) => ({
15
25
  // State
16
26
  currentLanguage: 'en-US',
@@ -21,10 +31,15 @@ export const useLocalizationStore = create<LocalizationStoreType>((set, get) =>
21
31
  // Actions
22
32
  initialize: async () => {
23
33
  const { isInitialized: alreadyInitialized } = get();
24
- if (alreadyInitialized) {
34
+
35
+ // Atomic check: both state flag AND in-progress mutex
36
+ if (alreadyInitialized || initializeInProgress) {
25
37
  return;
26
38
  }
27
39
 
40
+ // Set mutex immediately (synchronous)
41
+ initializeInProgress = true;
42
+
28
43
  try {
29
44
  const result = await LanguageInitializer.initialize();
30
45
 
@@ -39,22 +54,71 @@ export const useLocalizationStore = create<LocalizationStoreType>((set, get) =>
39
54
  isRTL: false,
40
55
  isInitialized: true,
41
56
  });
57
+ } finally {
58
+ // Reset mutex after completion (success or failure)
59
+ initializeInProgress = false;
42
60
  }
43
61
  },
44
62
 
45
63
  setLanguage: async (languageCode: string) => {
46
- console.log('[LocalizationStore] setLanguage called:', languageCode);
47
- const result = await LanguageSwitcher.switchLanguage(languageCode);
48
- console.log('[LocalizationStore] LanguageSwitcher result:', result);
64
+ // Debounce rapid language switches
65
+ if (languageSwitchTimer) {
66
+ clearTimeout(languageSwitchTimer);
67
+ }
49
68
 
50
- set({
51
- currentLanguage: result.languageCode,
52
- isRTL: result.isRTL,
69
+ return new Promise<void>((resolve) => {
70
+ // Add this resolver to pending list
71
+ pendingResolvers.push(resolve);
72
+
73
+ languageSwitchTimer = setTimeout(async () => {
74
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
75
+ console.log('[LocalizationStore] setLanguage called:', languageCode);
76
+ }
77
+
78
+ try {
79
+ const result = await LanguageSwitcher.switchLanguage(languageCode);
80
+
81
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
82
+ console.log('[LocalizationStore] LanguageSwitcher result:', result);
83
+ }
84
+
85
+ set({
86
+ currentLanguage: result.languageCode,
87
+ isRTL: result.isRTL,
88
+ });
89
+
90
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
91
+ console.log('[LocalizationStore] Store updated with new language:', result.languageCode);
92
+ }
93
+ } catch (error) {
94
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
95
+ console.error('[LocalizationStore] Language switch failed:', error);
96
+ }
97
+ }
98
+
99
+ languageSwitchTimer = null;
100
+
101
+ // Resolve ALL pending promises (not just the latest)
102
+ const resolvers = [...pendingResolvers];
103
+ pendingResolvers = [];
104
+ resolvers.forEach(r => r());
105
+ }, LANGUAGE_SWITCH_DEBOUNCE_MS);
53
106
  });
54
- console.log('[LocalizationStore] Store updated with new language:', result.languageCode);
55
107
  },
56
108
 
57
109
  reset: () => {
110
+ // Clear any pending language switch
111
+ if (languageSwitchTimer) {
112
+ clearTimeout(languageSwitchTimer);
113
+ languageSwitchTimer = null;
114
+ }
115
+ // Resolve any pending promises to prevent hanging
116
+ const resolvers = [...pendingResolvers];
117
+ pendingResolvers = [];
118
+ resolvers.forEach(r => r());
119
+ // Reset mutex
120
+ initializeInProgress = false;
121
+
58
122
  set({
59
123
  currentLanguage: 'en-US',
60
124
  isRTL: false,