@umituz/react-native-localization 1.2.0 → 1.2.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.
- package/lib/infrastructure/config/i18n.d.ts +1 -4
- package/lib/infrastructure/config/i18n.d.ts.map +1 -1
- package/lib/infrastructure/config/i18n.js +25 -159
- package/lib/infrastructure/config/i18n.js.map +1 -1
- package/lib/infrastructure/config/languages.d.ts +1 -1
- package/lib/infrastructure/config/languages.d.ts.map +1 -1
- package/lib/infrastructure/config/languages.js +2 -2
- package/lib/infrastructure/config/languages.js.map +1 -1
- package/lib/infrastructure/config/languagesData.d.ts +22 -3
- package/lib/infrastructure/config/languagesData.d.ts.map +1 -1
- package/lib/infrastructure/config/languagesData.js +53 -31
- package/lib/infrastructure/config/languagesData.js.map +1 -1
- package/lib/infrastructure/storage/AsyncStorageWrapper.d.ts.map +1 -1
- package/lib/infrastructure/storage/AsyncStorageWrapper.js +2 -6
- package/lib/infrastructure/storage/AsyncStorageWrapper.js.map +1 -1
- package/lib/infrastructure/storage/LocalizationStore.d.ts +2 -7
- package/lib/infrastructure/storage/LocalizationStore.d.ts.map +1 -1
- package/lib/infrastructure/storage/LocalizationStore.js +35 -116
- package/lib/infrastructure/storage/LocalizationStore.js.map +1 -1
- package/package.json +7 -5
- package/src/infrastructure/config/i18n.ts +29 -155
- package/src/infrastructure/config/languages.ts +3 -3
- package/src/infrastructure/config/languagesData.ts +64 -32
- package/src/infrastructure/storage/AsyncStorageWrapper.ts +2 -4
- package/src/infrastructure/storage/LocalizationStore.ts +39 -140
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Localization Store
|
|
3
3
|
* Zustand state management for language preferences with AsyncStorage persistence
|
|
4
|
-
*
|
|
5
|
-
* REFACTORED: Now uses centralized AsyncStorageWrapper for DRY compliance
|
|
6
|
-
* - Eliminates duplicate AsyncStorage calls
|
|
7
|
-
* - Consistent error handling and logging
|
|
8
|
-
* - Type-safe storage operations
|
|
9
4
|
*/
|
|
10
5
|
|
|
11
|
-
import { create } from
|
|
12
|
-
import { StorageWrapper, STORAGE_KEYS } from
|
|
13
|
-
import i18n from
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
DEFAULT_LANGUAGE,
|
|
17
|
-
getLanguageByCode,
|
|
18
|
-
getDeviceLocale,
|
|
19
|
-
} from "../config/languages";
|
|
20
|
-
import type { Language } from "../../domain/repositories/ILocalizationRepository";
|
|
6
|
+
import { create } from 'zustand';
|
|
7
|
+
import { StorageWrapper, STORAGE_KEYS } from './AsyncStorageWrapper';
|
|
8
|
+
import i18n from '../config/i18n';
|
|
9
|
+
import { SUPPORTED_LANGUAGES, DEFAULT_LANGUAGE, getLanguageByCode, getDeviceLocale } from '../config/languages';
|
|
10
|
+
import type { Language } from '../../domain/repositories/ILocalizationRepository';
|
|
21
11
|
|
|
22
12
|
interface LocalizationState {
|
|
23
13
|
currentLanguage: string;
|
|
@@ -42,115 +32,37 @@ export const useLocalizationStore = create<LocalizationState>((set, get) => ({
|
|
|
42
32
|
* - Fallback: English (en-US) if device locale not supported
|
|
43
33
|
*/
|
|
44
34
|
initialize: async () => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// ✅ Get saved language preference (returns null if not exists)
|
|
64
|
-
const savedLanguage = await StorageWrapper.getString(
|
|
65
|
-
STORAGE_KEYS.LANGUAGE,
|
|
66
|
-
DEFAULT_LANGUAGE,
|
|
67
|
-
);
|
|
68
|
-
/* eslint-disable-next-line no-console */
|
|
69
|
-
if (__DEV__)
|
|
70
|
-
console.log("[LocalizationStore] Saved language:", savedLanguage);
|
|
71
|
-
|
|
72
|
-
// ✅ DEVICE LOCALE DETECTION: Use device locale on first launch
|
|
73
|
-
let languageCode: string;
|
|
74
|
-
if (savedLanguage && savedLanguage !== DEFAULT_LANGUAGE) {
|
|
75
|
-
// User has previously selected a language → Use their choice
|
|
76
|
-
languageCode = savedLanguage;
|
|
77
|
-
/* eslint-disable-next-line no-console */
|
|
78
|
-
if (__DEV__)
|
|
79
|
-
console.log(
|
|
80
|
-
"[LocalizationStore] Using saved language:",
|
|
81
|
-
languageCode,
|
|
82
|
-
);
|
|
83
|
-
} else {
|
|
84
|
-
/* eslint-disable-next-line no-console */
|
|
85
|
-
if (__DEV__)
|
|
86
|
-
console.log(
|
|
87
|
-
"[LocalizationStore] First launch, detecting device locale...",
|
|
88
|
-
);
|
|
89
|
-
// First launch → Detect device locale automatically
|
|
90
|
-
languageCode = getDeviceLocale();
|
|
91
|
-
/* eslint-disable-next-line no-console */
|
|
92
|
-
if (__DEV__)
|
|
93
|
-
console.log(
|
|
94
|
-
"[LocalizationStore] Detected device locale:",
|
|
95
|
-
languageCode,
|
|
96
|
-
);
|
|
97
|
-
// Save detected locale for future launches
|
|
98
|
-
await StorageWrapper.setString(STORAGE_KEYS.LANGUAGE, languageCode);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/* eslint-disable-next-line no-console */
|
|
102
|
-
if (__DEV__)
|
|
103
|
-
console.log("[LocalizationStore] Validating language code...");
|
|
104
|
-
// ✅ DEFENSIVE: Validate language exists, fallback to default
|
|
105
|
-
const language = getLanguageByCode(languageCode);
|
|
106
|
-
const finalLanguage = language ? languageCode : DEFAULT_LANGUAGE;
|
|
107
|
-
const finalLanguageObj = getLanguageByCode(finalLanguage);
|
|
108
|
-
/* eslint-disable-next-line no-console */
|
|
109
|
-
if (__DEV__)
|
|
110
|
-
console.log("[LocalizationStore] Final language:", finalLanguage);
|
|
111
|
-
|
|
112
|
-
/* eslint-disable-next-line no-console */
|
|
113
|
-
if (__DEV__) console.log("[LocalizationStore] Changing i18n language...");
|
|
114
|
-
// Only change language if i18n is available
|
|
115
|
-
if (i18n && typeof i18n.changeLanguage === "function") {
|
|
116
|
-
await i18n.changeLanguage(finalLanguage);
|
|
117
|
-
/* eslint-disable-next-line no-console */
|
|
118
|
-
if (__DEV__) console.log("[LocalizationStore] i18n language changed");
|
|
119
|
-
} else {
|
|
120
|
-
/* eslint-disable-next-line no-console */
|
|
121
|
-
if (__DEV__)
|
|
122
|
-
console.warn(
|
|
123
|
-
"[LocalizationStore] i18n not available, skipping language change",
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
set({
|
|
128
|
-
currentLanguage: finalLanguage,
|
|
129
|
-
isRTL: finalLanguageObj?.rtl || false,
|
|
130
|
-
isInitialized: true, // ✅ Always set true to unblock UI
|
|
131
|
-
});
|
|
132
|
-
/* eslint-disable-next-line no-console */
|
|
133
|
-
if (__DEV__)
|
|
134
|
-
console.log(
|
|
135
|
-
"[LocalizationStore] Initialization completed successfully",
|
|
136
|
-
);
|
|
137
|
-
} catch (error) {
|
|
138
|
-
/* eslint-disable-next-line no-console */
|
|
139
|
-
if (__DEV__)
|
|
140
|
-
console.error("[LocalizationStore] Initialization error:", error);
|
|
141
|
-
/* eslint-disable-next-line no-console */
|
|
142
|
-
if (__DEV__)
|
|
143
|
-
console.error("[LocalizationStore] Error details:", {
|
|
144
|
-
message: error instanceof Error ? error.message : String(error),
|
|
145
|
-
stack: error instanceof Error ? error.stack : "No stack",
|
|
146
|
-
name: error instanceof Error ? error.name : "Unknown",
|
|
147
|
-
});
|
|
148
|
-
// Set initialized even on error to prevent blocking UI
|
|
149
|
-
set({
|
|
150
|
-
isInitialized: true,
|
|
151
|
-
});
|
|
152
|
-
throw error;
|
|
35
|
+
// ✅ CRITICAL FIX: Don't reset isInitialized if already initialized
|
|
36
|
+
// This prevents UI flash on re-initialization
|
|
37
|
+
const { isInitialized: alreadyInitialized } = get();
|
|
38
|
+
if (alreadyInitialized) return;
|
|
39
|
+
|
|
40
|
+
// Get saved language preference
|
|
41
|
+
const savedLanguage = await StorageWrapper.getString(STORAGE_KEYS.LANGUAGE, DEFAULT_LANGUAGE);
|
|
42
|
+
|
|
43
|
+
// ✅ DEVICE LOCALE DETECTION: Use device locale on first launch
|
|
44
|
+
let languageCode: string;
|
|
45
|
+
if (savedLanguage && savedLanguage !== DEFAULT_LANGUAGE) {
|
|
46
|
+
// User has previously selected a language → Use their choice
|
|
47
|
+
languageCode = savedLanguage;
|
|
48
|
+
} else {
|
|
49
|
+
// First launch → Detect device locale automatically
|
|
50
|
+
languageCode = getDeviceLocale();
|
|
51
|
+
// Save detected locale for future launches
|
|
52
|
+
await StorageWrapper.setString(STORAGE_KEYS.LANGUAGE, languageCode);
|
|
153
53
|
}
|
|
54
|
+
|
|
55
|
+
// ✅ DEFENSIVE: Validate language exists, fallback to default
|
|
56
|
+
const language = getLanguageByCode(languageCode);
|
|
57
|
+
const finalLanguage = language ? languageCode : DEFAULT_LANGUAGE;
|
|
58
|
+
const finalLanguageObj = getLanguageByCode(finalLanguage);
|
|
59
|
+
|
|
60
|
+
await i18n.changeLanguage(finalLanguage);
|
|
61
|
+
set({
|
|
62
|
+
currentLanguage: finalLanguage,
|
|
63
|
+
isRTL: finalLanguageObj?.rtl || false,
|
|
64
|
+
isInitialized: true, // ✅ Always set true to unblock UI
|
|
65
|
+
});
|
|
154
66
|
},
|
|
155
67
|
|
|
156
68
|
/**
|
|
@@ -163,10 +75,8 @@ export const useLocalizationStore = create<LocalizationState>((set, get) => ({
|
|
|
163
75
|
// ✅ DEFENSIVE: Early return if unsupported language
|
|
164
76
|
if (!language) return;
|
|
165
77
|
|
|
166
|
-
// Update i18n
|
|
167
|
-
|
|
168
|
-
await i18n.changeLanguage(languageCode);
|
|
169
|
-
}
|
|
78
|
+
// Update i18n
|
|
79
|
+
await i18n.changeLanguage(languageCode);
|
|
170
80
|
|
|
171
81
|
// Update state
|
|
172
82
|
set({
|
|
@@ -174,7 +84,7 @@ export const useLocalizationStore = create<LocalizationState>((set, get) => ({
|
|
|
174
84
|
isRTL: language.rtl || false,
|
|
175
85
|
});
|
|
176
86
|
|
|
177
|
-
//
|
|
87
|
+
// Persist language preference
|
|
178
88
|
await StorageWrapper.setString(STORAGE_KEYS.LANGUAGE, languageCode);
|
|
179
89
|
},
|
|
180
90
|
}));
|
|
@@ -195,19 +105,8 @@ export const useLocalization = () => {
|
|
|
195
105
|
|
|
196
106
|
const currentLanguageObject = getLanguageByCode(currentLanguage);
|
|
197
107
|
|
|
198
|
-
// Safe translation function - returns key if i18n not available
|
|
199
|
-
const t = (key: string, options?: any): string => {
|
|
200
|
-
if (i18n && typeof i18n.t === "function") {
|
|
201
|
-
const result = i18n.t(key, options);
|
|
202
|
-
// i18n.t can return string or object, ensure we return string
|
|
203
|
-
return typeof result === "string" ? result : key;
|
|
204
|
-
}
|
|
205
|
-
// Fallback: return key if i18n not available
|
|
206
|
-
return key;
|
|
207
|
-
};
|
|
208
|
-
|
|
209
108
|
return {
|
|
210
|
-
t,
|
|
109
|
+
t: i18n.t.bind(i18n), // Translation function
|
|
211
110
|
currentLanguage,
|
|
212
111
|
currentLanguageObject,
|
|
213
112
|
isRTL,
|