@fadyshawky/react-native-magic 1.0.7 → 1.0.9
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/.vscode/settings.json +7 -0
- package/CHANGELOG.md +9 -0
- package/package.json +1 -1
- package/template/App.tsx +30 -9
- package/template/package-lock.json +170 -123
- package/template/package.json +1 -0
- package/template/src/common/ImageResources.g.ts +3 -5
- package/template/src/common/components/Background.tsx +66 -28
- package/template/src/common/components/Cards.tsx +116 -0
- package/template/src/common/components/Container.tsx +145 -0
- package/template/src/common/components/FlatListWrapper.tsx +1 -0
- package/template/src/common/components/ImageCropPickerButton.tsx +1 -1
- package/template/src/common/components/OTPInput.tsx +107 -0
- package/template/src/common/components/PhotoTakingButton.tsx +1 -4
- package/template/src/common/components/PrimaryButton.tsx +171 -157
- package/template/src/common/components/RTLAwareText.tsx +42 -0
- package/template/src/common/components/RTLAwareView.tsx +179 -0
- package/template/src/common/components/RadioButton.tsx +1 -3
- package/template/src/common/components/RadioIcon.tsx +1 -2
- package/template/src/common/components/SearchBar.tsx +179 -0
- package/template/src/common/components/Separator.tsx +7 -4
- package/template/src/common/components/TouchablePlatform.tsx +1 -3
- package/template/src/common/components/TryAgain.tsx +3 -3
- package/template/src/common/helpers/inAppReviewHelper.ts +0 -1
- package/template/src/common/helpers/stringsHelpers.ts +10 -0
- package/template/src/common/hooks/useFlatListActions.ts +1 -1
- package/template/src/common/localization/LocalizationProvider.tsx +152 -0
- package/template/src/common/localization/README.md +488 -0
- package/template/src/common/localization/localization.ts +12 -0
- package/template/src/common/localization/translations/homeLocalization.ts +1 -0
- package/template/src/common/localization/translations/profileLocalization.ts +24 -0
- package/template/src/common/validations/errorValidations.ts +1 -6
- package/template/src/common/validations/examples/TextInputWithValidation.tsx +229 -0
- package/template/src/common/validations/index.ts +28 -0
- package/template/src/common/validations/regex.js +83 -0
- package/template/src/common/validations/regexValidator.ts +240 -0
- package/template/src/common/validations/validationConstants.ts +2 -2
- package/template/src/core/api/errorHandler.ts +39 -0
- package/template/src/core/api/responseHandlers.ts +1 -26
- package/template/src/core/api/serverHeaders.ts +13 -23
- package/template/src/core/store/app/appSlice.ts +1 -2
- package/template/src/core/store/user/userSlice.ts +1 -0
- package/template/src/core/theme/ThemeProvider.tsx +63 -0
- package/template/src/core/theme/colors.ts +31 -42
- package/template/src/core/theme/commonConsts.ts +1 -1
- package/template/src/core/theme/commonStyles.ts +267 -210
- package/template/src/core/theme/fonts.ts +17 -1
- package/template/src/core/theme/scaling.ts +101 -0
- package/template/src/core/theme/themes.ts +214 -0
- package/template/src/core/theme/types.ts +51 -0
- package/template/src/navigation/AuthStack.tsx +25 -30
- package/template/src/navigation/HeaderComponents.tsx +18 -58
- package/template/src/navigation/MainNavigation.tsx +5 -6
- package/template/src/navigation/MainStack.tsx +6 -27
- package/template/src/navigation/RootNavigation.tsx +1 -7
- package/template/src/navigation/TabBar.tsx +2 -2
- package/template/src/navigation/TopTabBar.tsx +1 -1
- package/template/src/screens/Login/Login.tsx +3 -3
- package/template/src/screens/home/HomeScreen.tsx +107 -0
- package/template/src/screens/home/components/CarouselSection.tsx +79 -0
- package/template/src/screens/home/components/FeaturedCarousel.tsx +128 -0
- package/template/src/screens/home/hooks/useHomeData.ts +60 -0
- package/template/src/screens/home/types.ts +7 -0
- package/template/src/screens/registration/RegistrationScreen.tsx +2 -2
- package/template/src/screens/resetPassword/ForgotPasswordScreen.tsx +2 -2
- package/template/src/utils/stringBuilder.js +25 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
# Localization System
|
|
2
|
+
|
|
3
|
+
This document explains how to use the localization system in the application.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The localization system is built using `react-native-localization` and provides a simple way to translate text throughout the application. It supports multiple languages (English and Arabic) and provides a consistent API for accessing translations. The system also includes RTL (Right-to-Left) support for Arabic language.
|
|
8
|
+
|
|
9
|
+
## Structure
|
|
10
|
+
|
|
11
|
+
The localization system consists of the following components:
|
|
12
|
+
|
|
13
|
+
- **LocalizationProvider**: A React context provider that manages the current language and provides translation functions.
|
|
14
|
+
- **Translation Files**: JSON files containing translations for different parts of the application.
|
|
15
|
+
- **Hooks**: Custom hooks for accessing translations in components.
|
|
16
|
+
- **RTL Components**: Utility components for handling RTL layouts.
|
|
17
|
+
|
|
18
|
+
## Translation Files
|
|
19
|
+
|
|
20
|
+
Translation files are organized by feature and stored in the `src/common/localization/translations` directory:
|
|
21
|
+
|
|
22
|
+
- `commonLocalization.ts`: Common translations used throughout the app
|
|
23
|
+
- `loginLocalization.ts`: Translations for the login screen
|
|
24
|
+
- `homeLocalization.ts`: Translations for the home screen
|
|
25
|
+
- `otpLocalization.ts`: Translations for the OTP verification screen
|
|
26
|
+
- `passwordLocalization.ts`: Translations for password-related screens
|
|
27
|
+
- `navigationLocalization.ts`: Translations for navigation elements (screen names, tab names)
|
|
28
|
+
- `mainNavigationLocalization.ts`: Translations for main navigation tabs and screens
|
|
29
|
+
- etc.
|
|
30
|
+
|
|
31
|
+
Each translation file follows this structure:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
export const featureLocalization = {
|
|
35
|
+
en: {
|
|
36
|
+
key1: 'Translation 1',
|
|
37
|
+
key2: 'Translation 2',
|
|
38
|
+
// Nested translations
|
|
39
|
+
nestedSection: {
|
|
40
|
+
key3: 'Translation 3',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
ar: {
|
|
44
|
+
key1: 'الترجمة 1',
|
|
45
|
+
key2: 'الترجمة 2',
|
|
46
|
+
// Nested translations
|
|
47
|
+
nestedSection: {
|
|
48
|
+
key3: 'الترجمة 3',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Using Translations in Components
|
|
55
|
+
|
|
56
|
+
### 1. Using the `useTranslation` Hook
|
|
57
|
+
|
|
58
|
+
The easiest way to use translations is with the `useTranslation` hook:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import {useTranslation} from '../../common/localization/LocalizationProvider';
|
|
62
|
+
|
|
63
|
+
function MyComponent() {
|
|
64
|
+
const t = useTranslation();
|
|
65
|
+
|
|
66
|
+
return <Text>{t('welcome', 'login')}</Text>;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The `t` function takes two parameters:
|
|
71
|
+
|
|
72
|
+
- `key`: The translation key
|
|
73
|
+
- `section` (optional): The section/feature the translation belongs to (defaults to 'common')
|
|
74
|
+
|
|
75
|
+
### 2. Using Dot Notation for Nested Translations
|
|
76
|
+
|
|
77
|
+
For nested translations, you can use dot notation:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// Access nestedSection.key3 in the login section
|
|
81
|
+
t('nestedSection.key3', 'login');
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Screen Label Localization
|
|
85
|
+
|
|
86
|
+
The application supports localized screen labels and tab names. This is implemented in the navigation configuration.
|
|
87
|
+
|
|
88
|
+
### 1. Screen Names in Navigation Stacks
|
|
89
|
+
|
|
90
|
+
Screen names are localized using the `navigation` translation section:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// In AuthStack.tsx
|
|
94
|
+
import {useTranslation} from '../common/localization/LocalizationProvider';
|
|
95
|
+
|
|
96
|
+
export function AuthStack() {
|
|
97
|
+
const t = useTranslation();
|
|
98
|
+
|
|
99
|
+
const AuthScreens = [
|
|
100
|
+
{
|
|
101
|
+
id: 'Login',
|
|
102
|
+
component: Login,
|
|
103
|
+
options: {
|
|
104
|
+
headerShown: false,
|
|
105
|
+
title: t('screens.Login', 'navigation'), // Localized screen title
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
// Other screens...
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
// ...
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 2. Tab Names in Bottom Tab Navigator
|
|
116
|
+
|
|
117
|
+
Tab names are localized using the `mainNavigation` translation section:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// In MainStack.tsx
|
|
121
|
+
import {useTranslation} from '../common/localization/LocalizationProvider';
|
|
122
|
+
|
|
123
|
+
function MainTabs() {
|
|
124
|
+
const t = useTranslation();
|
|
125
|
+
|
|
126
|
+
const MainScreens = [
|
|
127
|
+
{
|
|
128
|
+
id: 'Main',
|
|
129
|
+
component: HomeScreen,
|
|
130
|
+
options: {
|
|
131
|
+
tabBarLabel: t('tabs.Main', 'mainNavigation'), // Localized tab label
|
|
132
|
+
headerShown: false,
|
|
133
|
+
icon: ImageResources.services,
|
|
134
|
+
selectedIcon: ImageResources.services,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
// Other tabs...
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
// ...
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The TabBar component also supports localization by using the translation hook:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// In TabBar.tsx
|
|
148
|
+
import {
|
|
149
|
+
useTranslation,
|
|
150
|
+
useRTL,
|
|
151
|
+
} from '../common/localization/LocalizationProvider';
|
|
152
|
+
|
|
153
|
+
export function TabBar({state, descriptors, navigation}) {
|
|
154
|
+
const t = useTranslation();
|
|
155
|
+
const isRTL = useRTL();
|
|
156
|
+
|
|
157
|
+
// ...
|
|
158
|
+
|
|
159
|
+
// Get localized tab name if not provided in options
|
|
160
|
+
const localizedName = t(`tabs.${route.name}`, 'mainNavigation');
|
|
161
|
+
|
|
162
|
+
// ...
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 3. RTL Support in TabBar
|
|
167
|
+
|
|
168
|
+
The TabBar component has full RTL support, automatically adjusting the tab order and layout for RTL languages:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
export function TabBar({state, descriptors, navigation}) {
|
|
172
|
+
const isRTL = useRTL();
|
|
173
|
+
|
|
174
|
+
// Create a copy of routes array to avoid modifying the original
|
|
175
|
+
const routesToRender = [...state.routes];
|
|
176
|
+
|
|
177
|
+
// If RTL, reverse the order of tabs
|
|
178
|
+
if (isRTL) {
|
|
179
|
+
routesToRender.reverse();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<RTLAwareView style={styles.container}>
|
|
184
|
+
{routesToRender.map((route, index) => {
|
|
185
|
+
// Calculate the correct index in the original array for focused state
|
|
186
|
+
const originalIndex = isRTL ? state.routes.length - 1 - index : index;
|
|
187
|
+
const isFocused = state.index === originalIndex;
|
|
188
|
+
|
|
189
|
+
// ... render tab
|
|
190
|
+
})}
|
|
191
|
+
</RTLAwareView>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
This implementation ensures that:
|
|
197
|
+
|
|
198
|
+
- Tabs are displayed in the correct order for both LTR and RTL languages
|
|
199
|
+
- The focused state is preserved when switching between LTR and RTL
|
|
200
|
+
- Tab labels are properly aligned based on the text direction
|
|
201
|
+
- The entire tab bar layout adapts to the current language direction
|
|
202
|
+
|
|
203
|
+
### 4. Adding New Screen Names
|
|
204
|
+
|
|
205
|
+
To add a new screen name translation:
|
|
206
|
+
|
|
207
|
+
1. Add the screen name to the appropriate translation file:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
// For auth screens
|
|
211
|
+
export const navigationLocalization = {
|
|
212
|
+
en: {
|
|
213
|
+
screens: {
|
|
214
|
+
NewScreen: 'New Screen',
|
|
215
|
+
// Other screen names...
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
ar: {
|
|
219
|
+
screens: {
|
|
220
|
+
NewScreen: 'شاشة جديدة',
|
|
221
|
+
// Other screen names...
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// For main navigation tabs
|
|
227
|
+
export const mainNavigationLocalization = {
|
|
228
|
+
en: {
|
|
229
|
+
tabs: {
|
|
230
|
+
NewTab: 'New Tab',
|
|
231
|
+
// Other tab names...
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
ar: {
|
|
235
|
+
tabs: {
|
|
236
|
+
NewTab: 'تبويب جديد',
|
|
237
|
+
// Other tab names...
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
2. Use the translation in your navigation configuration:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
{
|
|
247
|
+
id: 'NewScreen',
|
|
248
|
+
component: NewScreenComponent,
|
|
249
|
+
options: {
|
|
250
|
+
title: t('screens.NewScreen', 'navigation'),
|
|
251
|
+
// For tabs
|
|
252
|
+
tabBarLabel: t('tabs.NewTab', 'mainNavigation'),
|
|
253
|
+
},
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## RTL Support
|
|
258
|
+
|
|
259
|
+
The application supports Right-to-Left (RTL) languages like Arabic. The system automatically handles RTL layout when the language is set to Arabic.
|
|
260
|
+
|
|
261
|
+
### 1. Using RTL-aware Components
|
|
262
|
+
|
|
263
|
+
Use the provided RTL-aware components to automatically handle RTL layout:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import {RTLAwareText} from '../../common/components/RTLAwareText';
|
|
267
|
+
import {RTLAwareView} from '../../common/components/RTLAwareView';
|
|
268
|
+
import {useRTL} from '../../common/localization/LocalizationProvider';
|
|
269
|
+
|
|
270
|
+
function MyComponent() {
|
|
271
|
+
const isRTL = useRTL();
|
|
272
|
+
|
|
273
|
+
return (
|
|
274
|
+
<RTLAwareView style={{flexDirection: 'row'}}>
|
|
275
|
+
<RTLAwareText style={{textAlign: 'left'}}>
|
|
276
|
+
This text will be properly aligned in RTL mode
|
|
277
|
+
</RTLAwareText>
|
|
278
|
+
</RTLAwareView>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### 2. Using the `useRTL` Hook
|
|
284
|
+
|
|
285
|
+
You can use the `useRTL` hook to check if the current language is RTL:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import {useRTL} from '../../common/localization/LocalizationProvider';
|
|
289
|
+
|
|
290
|
+
function MyComponent() {
|
|
291
|
+
const isRTL = useRTL();
|
|
292
|
+
|
|
293
|
+
return (
|
|
294
|
+
<View
|
|
295
|
+
style={{
|
|
296
|
+
flexDirection: isRTL ? 'row-reverse' : 'row',
|
|
297
|
+
alignItems: 'center',
|
|
298
|
+
}}>
|
|
299
|
+
{/* Your content */}
|
|
300
|
+
</View>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 3. Using the `rtlStyles` Helper
|
|
306
|
+
|
|
307
|
+
You can use the `rtlStyles` helper to create RTL-aware styles:
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import {useRTL} from '../../common/localization/LocalizationProvider';
|
|
311
|
+
import {rtlStyles} from '../../common/components/RTLAwareView';
|
|
312
|
+
|
|
313
|
+
function MyComponent() {
|
|
314
|
+
const isRTL = useRTL();
|
|
315
|
+
const rtlStyle = rtlStyles(isRTL);
|
|
316
|
+
|
|
317
|
+
return (
|
|
318
|
+
<View style={[rtlStyle.row, rtlStyle.textLeft]}>{/* Your content */}</View>
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### 4. RTL in Navigation Components
|
|
324
|
+
|
|
325
|
+
Navigation components like the TabBar have special RTL handling to ensure proper layout and interaction:
|
|
326
|
+
|
|
327
|
+
- Tab order is reversed in RTL mode
|
|
328
|
+
- Focus state is preserved when switching between LTR and RTL
|
|
329
|
+
- Text alignment is automatically adjusted
|
|
330
|
+
- Icons and other visual elements are properly positioned
|
|
331
|
+
|
|
332
|
+
## Adding New Translations
|
|
333
|
+
|
|
334
|
+
To add new translations:
|
|
335
|
+
|
|
336
|
+
1. Add the translation key and value to the appropriate translation file for both English and Arabic
|
|
337
|
+
2. If creating a new feature, create a new translation file in the `translations` directory
|
|
338
|
+
3. Register the new translation file in `localization.ts`
|
|
339
|
+
|
|
340
|
+
Example of adding a new translation file:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// 1. Create the file: src/common/localization/translations/newFeatureLocalization.ts
|
|
344
|
+
export const newFeatureLocalization = {
|
|
345
|
+
en: {
|
|
346
|
+
title: 'New Feature',
|
|
347
|
+
description: 'This is a new feature',
|
|
348
|
+
},
|
|
349
|
+
ar: {
|
|
350
|
+
title: 'ميزة جديدة',
|
|
351
|
+
description: 'هذه ميزة جديدة',
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// 2. Register in localization.ts
|
|
356
|
+
import {newFeatureLocalization} from './translations/newFeatureLocalization';
|
|
357
|
+
|
|
358
|
+
export const localization = {
|
|
359
|
+
// Existing localizations...
|
|
360
|
+
newFeature: new LocalizedStrings(newFeatureLocalization),
|
|
361
|
+
};
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Changing the Language
|
|
365
|
+
|
|
366
|
+
To change the application language:
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
import {useLocalization} from '../../common/localization/LocalizationProvider';
|
|
370
|
+
import {Languages} from '../../common/localization/localization';
|
|
371
|
+
|
|
372
|
+
function LanguageSelector() {
|
|
373
|
+
const {changeLanguage} = useLocalization();
|
|
374
|
+
|
|
375
|
+
return (
|
|
376
|
+
<>
|
|
377
|
+
<Button title="English" onPressIn={() => changeLanguage(Languages.en)} />
|
|
378
|
+
<Button title="العربية" onPressIn={() => changeLanguage(Languages.ar)} />
|
|
379
|
+
</>
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### App Restart on Language Change
|
|
385
|
+
|
|
386
|
+
When changing between RTL and LTR languages (e.g., from English to Arabic or vice versa), the app will automatically restart to properly apply the layout changes. This is necessary because React Native requires a restart to fully apply RTL layout changes, especially on Android.
|
|
387
|
+
|
|
388
|
+
The restart is handled automatically by the `LocalizationProvider` when you call the `changeLanguage` function. No additional code is needed in your components to handle the restart.
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
// Inside LocalizationProvider
|
|
392
|
+
const changeLanguage = (language: Languages) => {
|
|
393
|
+
if (language !== currentLanguage) {
|
|
394
|
+
setCurrentLanguage(language);
|
|
395
|
+
|
|
396
|
+
// Set RTL configuration and restart the app
|
|
397
|
+
const shouldBeRTL = language === Languages.ar;
|
|
398
|
+
if (I18nManager.isRTL !== shouldBeRTL) {
|
|
399
|
+
I18nManager.allowRTL(shouldBeRTL);
|
|
400
|
+
I18nManager.forceRTL(shouldBeRTL);
|
|
401
|
+
|
|
402
|
+
// Restart the app to apply RTL/LTR changes properly
|
|
403
|
+
try {
|
|
404
|
+
// Check if RNRestart is available
|
|
405
|
+
if (RNRestart && typeof RNRestart.restart === 'function') {
|
|
406
|
+
RNRestart.restart();
|
|
407
|
+
} else if (Platform.OS === 'android') {
|
|
408
|
+
// Fallback for Android using DevSettings
|
|
409
|
+
const DevSettings = NativeModules.DevSettings;
|
|
410
|
+
if (DevSettings && DevSettings.reload) {
|
|
411
|
+
DevSettings.reload();
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
} catch (error) {
|
|
415
|
+
console.error('Failed to restart the app:', error);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
#### Confirmation Dialog
|
|
423
|
+
|
|
424
|
+
When changing the language in the Profile screen, a confirmation dialog is shown to inform the user that the app will restart:
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
// In Profile.tsx
|
|
428
|
+
const handleLanguageToggle = () => {
|
|
429
|
+
Alert.alert(
|
|
430
|
+
t('changeLanguage', 'profile'),
|
|
431
|
+
t('changeLanguageConfirmation', 'profile'),
|
|
432
|
+
[
|
|
433
|
+
{
|
|
434
|
+
text: t('cancel', 'common'),
|
|
435
|
+
style: 'cancel',
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
text: t('change', 'common'),
|
|
439
|
+
onPress: () => {
|
|
440
|
+
changeLanguage(isArabic ? Languages.en : Languages.ar);
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
{cancelable: true},
|
|
445
|
+
);
|
|
446
|
+
};
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
This provides a better user experience by informing the user about the restart before it happens.
|
|
450
|
+
|
|
451
|
+
## Best Practices
|
|
452
|
+
|
|
453
|
+
1. **Use RTL-aware components**: Always use `RTLAwareText` and `RTLAwareView` instead of regular `Text` and `View` for content that needs to adapt to RTL languages.
|
|
454
|
+
2. **Use the translation hook**: Always use the `useTranslation` hook instead of directly accessing the localization object.
|
|
455
|
+
3. **Organize translations by feature**: Keep translations organized by feature to make them easier to maintain.
|
|
456
|
+
4. **Use meaningful keys**: Use descriptive keys that make it clear what the translation is for.
|
|
457
|
+
5. **Provide default values**: When a translation is missing, the key will be displayed as a fallback.
|
|
458
|
+
6. **Add comments**: Add comments to explain the context of translations when necessary.
|
|
459
|
+
7. **Test in both LTR and RTL modes**: Always test your UI in both Left-to-Right and Right-to-Left modes to ensure it looks correct in both.
|
|
460
|
+
8. **Localize screen labels**: Always localize screen titles and tab names for a consistent user experience.
|
|
461
|
+
9. **Separate navigation translations**: Keep auth navigation and main navigation translations separate for better organization.
|
|
462
|
+
10. **Handle RTL in navigation components**: Ensure navigation components like TabBar properly handle RTL layout and interaction.
|
|
463
|
+
|
|
464
|
+
## Adding a New Language
|
|
465
|
+
|
|
466
|
+
To add a new language:
|
|
467
|
+
|
|
468
|
+
1. Update the `Languages` enum in `localization.ts`:
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
export enum Languages {
|
|
472
|
+
en = 'en',
|
|
473
|
+
fr = 'fr', // Add new language
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
2. Add translations for the new language in each translation file:
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
export const commonLocalization = {
|
|
481
|
+
en: {
|
|
482
|
+
welcome: 'Welcome',
|
|
483
|
+
},
|
|
484
|
+
fr: {
|
|
485
|
+
welcome: 'Bienvenue',
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
```
|
|
@@ -8,9 +8,11 @@ import {setDateLocale} from './dateFormatter';
|
|
|
8
8
|
import {loginLocalization} from './translations/loginLocalization';
|
|
9
9
|
import {homeLocalization} from './translations/homeLocalization';
|
|
10
10
|
import {profileLocalization} from './translations/profileLocalization';
|
|
11
|
+
import {I18nManager} from 'react-native';
|
|
11
12
|
|
|
12
13
|
export enum Languages {
|
|
13
14
|
en = 'en',
|
|
15
|
+
ar = 'ar',
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export const localization = {
|
|
@@ -47,5 +49,15 @@ export function setLanguage(language?: Languages): void {
|
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
// Set RTL for Arabic language
|
|
53
|
+
const isRTL = localizationLanguage === Languages.ar;
|
|
54
|
+
if (I18nManager.isRTL !== isRTL) {
|
|
55
|
+
I18nManager.allowRTL(isRTL);
|
|
56
|
+
I18nManager.forceRTL(isRTL);
|
|
57
|
+
}
|
|
58
|
+
|
|
50
59
|
setDateLocale(localizationLanguage);
|
|
51
60
|
}
|
|
61
|
+
|
|
62
|
+
// Default language is Arabic
|
|
63
|
+
export const DEFAULT_LANGUAGE = Languages.ar;
|
|
@@ -2,5 +2,29 @@ export const profileLocalization = {
|
|
|
2
2
|
en: {
|
|
3
3
|
studentProfile: 'Student Profile',
|
|
4
4
|
allDetails: 'All Details',
|
|
5
|
+
settings: 'Settings',
|
|
6
|
+
darkMode: 'Dark Mode',
|
|
7
|
+
language: 'Language',
|
|
8
|
+
account: 'Account',
|
|
9
|
+
editProfile: 'Edit Profile',
|
|
10
|
+
changePassword: 'Change Password',
|
|
11
|
+
logout: 'Logout',
|
|
12
|
+
changeLanguage: 'Change Language',
|
|
13
|
+
changeLanguageConfirmation:
|
|
14
|
+
'Are you sure you want to change the language? The app will restart to apply changes.',
|
|
15
|
+
},
|
|
16
|
+
ar: {
|
|
17
|
+
studentProfile: 'الملف الشخصي للطالب',
|
|
18
|
+
allDetails: 'جميع التفاصيل',
|
|
19
|
+
settings: 'الإعدادات',
|
|
20
|
+
darkMode: 'الوضع الداكن',
|
|
21
|
+
language: 'اللغة',
|
|
22
|
+
account: 'الحساب',
|
|
23
|
+
editProfile: 'تعديل الملف الشخصي',
|
|
24
|
+
changePassword: 'تغيير كلمة المرور',
|
|
25
|
+
logout: 'تسجيل الخروج',
|
|
26
|
+
changeLanguage: 'تغيير اللغة',
|
|
27
|
+
changeLanguageConfirmation:
|
|
28
|
+
'هل أنت متأكد أنك تريد تغيير اللغة؟ سيتم إعادة تشغيل التطبيق لتطبيق التغييرات.',
|
|
5
29
|
},
|
|
6
30
|
};
|
|
@@ -3,8 +3,7 @@ import {unwrapResult} from '@reduxjs/toolkit';
|
|
|
3
3
|
import {Alert} from 'react-native';
|
|
4
4
|
import {IErrorResult, ErrorRepresentationType} from '../../../types';
|
|
5
5
|
import Snackbar from 'react-native-snackbar';
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {NewColors} from '../../core/theme/colors';
|
|
8
7
|
export function handlePromiseResult(
|
|
9
8
|
promiseAction: Promise<any>,
|
|
10
9
|
successMessage?: string,
|
|
@@ -19,8 +18,6 @@ export function handlePromiseResult(
|
|
|
19
18
|
Snackbar.show({
|
|
20
19
|
text: successMessage,
|
|
21
20
|
duration: Snackbar.LENGTH_SHORT,
|
|
22
|
-
textColor: Colors.white,
|
|
23
|
-
backgroundColor: Colors.green,
|
|
24
21
|
});
|
|
25
22
|
successAction && successAction();
|
|
26
23
|
})
|
|
@@ -45,8 +42,6 @@ export function handleErrorPostProcessing(
|
|
|
45
42
|
Snackbar.show({
|
|
46
43
|
text: error.message,
|
|
47
44
|
duration: Snackbar.LENGTH_SHORT,
|
|
48
|
-
textColor: Colors.white,
|
|
49
|
-
backgroundColor: Colors.red,
|
|
50
45
|
});
|
|
51
46
|
break;
|
|
52
47
|
default:
|