@umituz/react-native-localization 3.5.57 → 3.5.59
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 +1 -1
- package/src/infrastructure/components/LanguageSwitcher.tsx +31 -38
- package/src/infrastructure/components/useLanguageNavigation.ts +2 -2
- package/src/presentation/components/LanguageItem.styles.ts +4 -10
- package/src/presentation/components/LanguageItem.tsx +23 -15
- package/src/presentation/components/LanguageSection.tsx +3 -4
- package/src/presentation/screens/LanguageSelectionScreen.styles.ts +4 -3
- package/src/presentation/screens/LanguageSelectionScreen.tsx +46 -14
package/package.json
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React, { useMemo } from 'react';
|
|
7
|
-
import { TouchableOpacity,
|
|
7
|
+
import { TouchableOpacity, View } from 'react-native';
|
|
8
|
+
// @ts-ignore - Optional peer dependency
|
|
9
|
+
import { useAppDesignTokens, AtomicText } from '@umituz/react-native-design-system';
|
|
8
10
|
import { useLanguageSwitcher } from './useLanguageSwitcher';
|
|
9
11
|
import { styles, DEFAULT_CONFIG_VALUES } from './LanguageSwitcher.styles';
|
|
10
12
|
|
|
@@ -21,41 +23,6 @@ export interface LanguageSwitcherProps {
|
|
|
21
23
|
accessibilityLabel?: string;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
const renderContent = (
|
|
25
|
-
showFlag: boolean,
|
|
26
|
-
showName: boolean,
|
|
27
|
-
flag: string | undefined,
|
|
28
|
-
nativeName: string,
|
|
29
|
-
color: string | undefined,
|
|
30
|
-
iconStyle: any,
|
|
31
|
-
textStyle: any
|
|
32
|
-
) => {
|
|
33
|
-
if (showFlag && showName) {
|
|
34
|
-
return (
|
|
35
|
-
<>
|
|
36
|
-
<Text style={[styles.flag, iconStyle]}>{flag}</Text>
|
|
37
|
-
<Text style={[styles.languageName, { color }, textStyle]}>
|
|
38
|
-
{nativeName}
|
|
39
|
-
</Text>
|
|
40
|
-
</>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (showFlag) {
|
|
45
|
-
return <Text style={[styles.flag, iconStyle]}>{flag}</Text>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (showName) {
|
|
49
|
-
return (
|
|
50
|
-
<Text style={[styles.languageName, { color }, textStyle]}>
|
|
51
|
-
{nativeName}
|
|
52
|
-
</Text>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return <Text style={[styles.icon, { color }, iconStyle]}>🌐</Text>;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
26
|
export const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({
|
|
60
27
|
showName = false,
|
|
61
28
|
showFlag = true,
|
|
@@ -68,6 +35,7 @@ export const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({
|
|
|
68
35
|
disabled = false,
|
|
69
36
|
accessibilityLabel,
|
|
70
37
|
}) => {
|
|
38
|
+
const tokens = useAppDesignTokens();
|
|
71
39
|
const { currentLang, handlePress } = useLanguageSwitcher({ onPress, disabled });
|
|
72
40
|
|
|
73
41
|
const accessibilityProps = useMemo(() => ({
|
|
@@ -77,9 +45,16 @@ export const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({
|
|
|
77
45
|
accessible: true,
|
|
78
46
|
}), [accessibilityLabel, currentLang.nativeName, disabled]);
|
|
79
47
|
|
|
48
|
+
const textColor = color || tokens.colors.textPrimary;
|
|
49
|
+
|
|
80
50
|
return (
|
|
81
51
|
<TouchableOpacity
|
|
82
|
-
style={[
|
|
52
|
+
style={[
|
|
53
|
+
styles.container,
|
|
54
|
+
{ gap: tokens.spacing.xs },
|
|
55
|
+
style,
|
|
56
|
+
disabled && styles.disabled
|
|
57
|
+
]}
|
|
83
58
|
onPress={handlePress}
|
|
84
59
|
activeOpacity={disabled ? 1 : DEFAULT_CONFIG_VALUES.activeOpacity}
|
|
85
60
|
hitSlop={DEFAULT_CONFIG_VALUES.hitSlop}
|
|
@@ -87,9 +62,27 @@ export const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({
|
|
|
87
62
|
disabled={disabled}
|
|
88
63
|
{...accessibilityProps}
|
|
89
64
|
>
|
|
90
|
-
{
|
|
65
|
+
{showFlag && (
|
|
66
|
+
<AtomicText style={[styles.flag, iconStyle]}>
|
|
67
|
+
{currentLang.flag || '🌐'}
|
|
68
|
+
</AtomicText>
|
|
69
|
+
)}
|
|
70
|
+
{showName && (
|
|
71
|
+
<AtomicText
|
|
72
|
+
type="bodySmall"
|
|
73
|
+
style={[styles.languageName, { color: textColor, fontWeight: '600' }, textStyle]}
|
|
74
|
+
>
|
|
75
|
+
{currentLang.nativeName}
|
|
76
|
+
</AtomicText>
|
|
77
|
+
)}
|
|
78
|
+
{!showFlag && !showName && (
|
|
79
|
+
<AtomicText style={[styles.icon, { color: textColor }, iconStyle]}>
|
|
80
|
+
🌐
|
|
81
|
+
</AtomicText>
|
|
82
|
+
)}
|
|
91
83
|
</TouchableOpacity>
|
|
92
84
|
);
|
|
93
85
|
};
|
|
94
86
|
|
|
95
87
|
export default LanguageSwitcher;
|
|
88
|
+
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// @ts-ignore - Optional peer dependency
|
|
2
|
-
import {
|
|
2
|
+
import { useAppNavigation } from '@umituz/react-native-design-system';
|
|
3
3
|
import { useLocalization } from '../hooks/useLocalization';
|
|
4
4
|
import { languageRepository } from '../repository/LanguageRepository';
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
export const useLanguageNavigation = (navigationScreen: string) => {
|
|
8
|
-
const navigation =
|
|
8
|
+
const navigation = useAppNavigation();
|
|
9
9
|
const { currentLanguage } = useLocalization();
|
|
10
10
|
const currentLang = languageRepository.getLanguageByCode(currentLanguage) || languageRepository.getDefaultLanguage();
|
|
11
11
|
|
|
@@ -9,10 +9,7 @@ export const styles = StyleSheet.create({
|
|
|
9
9
|
flexDirection: 'row',
|
|
10
10
|
alignItems: 'center',
|
|
11
11
|
justifyContent: 'space-between',
|
|
12
|
-
padding: 16,
|
|
13
|
-
borderRadius: 12,
|
|
14
12
|
borderWidth: 1,
|
|
15
|
-
marginBottom: 8,
|
|
16
13
|
},
|
|
17
14
|
selectedLanguageItem: {
|
|
18
15
|
borderWidth: 2,
|
|
@@ -29,18 +26,15 @@ export const styles = StyleSheet.create({
|
|
|
29
26
|
languageText: {
|
|
30
27
|
flex: 1,
|
|
31
28
|
flexShrink: 1,
|
|
32
|
-
marginRight: 12,
|
|
33
29
|
},
|
|
34
30
|
nativeName: {
|
|
35
|
-
|
|
36
|
-
fontWeight: '600',
|
|
37
|
-
marginBottom: 4,
|
|
31
|
+
// Styling moved to themedStyles in component for token support
|
|
38
32
|
},
|
|
39
33
|
languageName: {
|
|
40
|
-
|
|
34
|
+
// Styling moved to themedStyles in component for token support
|
|
41
35
|
},
|
|
42
36
|
checkIcon: {
|
|
43
|
-
|
|
44
|
-
fontWeight: 'bold',
|
|
37
|
+
// Replaced by AtomicIcon
|
|
45
38
|
},
|
|
46
39
|
});
|
|
40
|
+
|
|
@@ -9,13 +9,12 @@ import React, { useMemo } from 'react';
|
|
|
9
9
|
import {
|
|
10
10
|
View,
|
|
11
11
|
TouchableOpacity,
|
|
12
|
-
Text,
|
|
13
12
|
type StyleProp,
|
|
14
13
|
type ViewStyle,
|
|
15
14
|
type TextStyle,
|
|
16
15
|
} from 'react-native';
|
|
17
16
|
// @ts-ignore - Optional peer dependency
|
|
18
|
-
import { useAppDesignTokens } from '@umituz/react-native-design-system';
|
|
17
|
+
import { useAppDesignTokens, AtomicText, AtomicIcon } from '@umituz/react-native-design-system';
|
|
19
18
|
import type { Language } from '../../infrastructure/storage/types/Language';
|
|
20
19
|
import { styles } from './LanguageItem.styles';
|
|
21
20
|
|
|
@@ -42,22 +41,24 @@ export const LanguageItem: React.FC<LanguageItemProps> = ({
|
|
|
42
41
|
|
|
43
42
|
const themedStyles = useMemo(() => ({
|
|
44
43
|
languageItem: {
|
|
44
|
+
padding: tokens.spacing.md,
|
|
45
|
+
borderRadius: tokens.borders.radius.md,
|
|
45
46
|
backgroundColor: tokens.colors.backgroundSecondary,
|
|
46
47
|
borderColor: tokens.colors.border,
|
|
48
|
+
marginBottom: tokens.spacing.sm,
|
|
47
49
|
} as ViewStyle,
|
|
48
50
|
selectedLanguageItem: {
|
|
49
51
|
borderColor: tokens.colors.primary,
|
|
50
|
-
backgroundColor: tokens.colors.
|
|
52
|
+
backgroundColor: tokens.colors.primaryContainer,
|
|
53
|
+
borderWidth: 2,
|
|
51
54
|
} as ViewStyle,
|
|
52
55
|
nativeName: {
|
|
53
56
|
color: tokens.colors.textPrimary,
|
|
57
|
+
marginBottom: tokens.spacing.xs / 2,
|
|
54
58
|
} as TextStyle,
|
|
55
59
|
languageName: {
|
|
56
60
|
color: tokens.colors.textSecondary,
|
|
57
61
|
} as TextStyle,
|
|
58
|
-
checkIcon: {
|
|
59
|
-
color: tokens.colors.primary,
|
|
60
|
-
} as TextStyle,
|
|
61
62
|
}), [tokens]);
|
|
62
63
|
|
|
63
64
|
return (
|
|
@@ -66,28 +67,35 @@ export const LanguageItem: React.FC<LanguageItemProps> = ({
|
|
|
66
67
|
style={[
|
|
67
68
|
styles.languageItem,
|
|
68
69
|
themedStyles.languageItem,
|
|
69
|
-
customStyles?.languageItem,
|
|
70
70
|
isSelected ? [styles.selectedLanguageItem, themedStyles.selectedLanguageItem] : undefined,
|
|
71
|
+
customStyles?.languageItem,
|
|
71
72
|
]}
|
|
72
73
|
onPress={() => onSelect(item.code)}
|
|
73
74
|
activeOpacity={0.7}
|
|
74
75
|
>
|
|
75
76
|
<View style={[styles.languageContent, customStyles?.languageContent]}>
|
|
76
|
-
<
|
|
77
|
+
<AtomicText style={[styles.flag, customStyles?.flag]}>
|
|
77
78
|
{item.flag || '🌐'}
|
|
78
|
-
</
|
|
79
|
-
<View style={[styles.languageText, customStyles?.languageText]}>
|
|
80
|
-
<
|
|
79
|
+
</AtomicText>
|
|
80
|
+
<View style={[styles.languageText, { gap: tokens.spacing.xs / 2 }, customStyles?.languageText]}>
|
|
81
|
+
<AtomicText
|
|
82
|
+
type="bodyMedium"
|
|
83
|
+
style={[themedStyles.nativeName, { fontWeight: '700' }, customStyles?.nativeName]}
|
|
84
|
+
>
|
|
81
85
|
{item.nativeName}
|
|
82
|
-
</
|
|
83
|
-
<
|
|
86
|
+
</AtomicText>
|
|
87
|
+
<AtomicText
|
|
88
|
+
type="labelMedium"
|
|
89
|
+
style={[themedStyles.languageName, customStyles?.nativeName]}
|
|
90
|
+
>
|
|
84
91
|
{item.name}
|
|
85
|
-
</
|
|
92
|
+
</AtomicText>
|
|
86
93
|
</View>
|
|
87
94
|
</View>
|
|
88
95
|
{isSelected && (
|
|
89
|
-
<
|
|
96
|
+
<AtomicIcon name="checkmark" size="sm" color="primary" />
|
|
90
97
|
)}
|
|
91
98
|
</TouchableOpacity>
|
|
92
99
|
);
|
|
93
100
|
};
|
|
101
|
+
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View, StyleSheet, type ViewStyle } from 'react-native';
|
|
3
3
|
// @ts-ignore - Optional peer dependency
|
|
4
|
-
import { useNavigation } from '@react-navigation/native';
|
|
5
|
-
// @ts-ignore - Optional peer dependency
|
|
6
4
|
import {
|
|
7
5
|
useAppDesignTokens,
|
|
8
6
|
AtomicText,
|
|
9
|
-
ListItem
|
|
7
|
+
ListItem,
|
|
8
|
+
useAppNavigation,
|
|
10
9
|
} from '@umituz/react-native-design-system';
|
|
11
10
|
import { useLocalization } from '../../infrastructure/hooks/useLocalization';
|
|
12
11
|
import { getLanguageByCode } from '../../infrastructure/config/languages';
|
|
@@ -29,7 +28,7 @@ export const LanguageSection: React.FC<LanguageSectionProps> = ({
|
|
|
29
28
|
containerStyle,
|
|
30
29
|
sectionTitle,
|
|
31
30
|
}) => {
|
|
32
|
-
const navigation =
|
|
31
|
+
const navigation = useAppNavigation();
|
|
33
32
|
const tokens = useAppDesignTokens();
|
|
34
33
|
const { t, currentLanguage } = useLocalization();
|
|
35
34
|
|
|
@@ -6,10 +6,11 @@ import { StyleSheet } from 'react-native';
|
|
|
6
6
|
|
|
7
7
|
export const styles = StyleSheet.create({
|
|
8
8
|
container: {
|
|
9
|
-
|
|
9
|
+
// Styling handled by ScreenLayout
|
|
10
10
|
},
|
|
11
11
|
listContent: {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
// Horizontal padding handled by ScreenLayout contentWrapper
|
|
13
|
+
// Bottom padding handled in component using tokens
|
|
14
14
|
},
|
|
15
15
|
});
|
|
16
|
+
|
|
@@ -4,11 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from 'react';
|
|
7
|
-
import {
|
|
7
|
+
import { FlatList } from 'react-native';
|
|
8
8
|
// @ts-ignore - Optional peer dependency
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
import {
|
|
10
|
+
useAppDesignTokens,
|
|
11
|
+
SearchBar,
|
|
12
|
+
ScreenLayout,
|
|
13
|
+
NavigationHeader,
|
|
14
|
+
useAppNavigation,
|
|
15
|
+
} from '@umituz/react-native-design-system';
|
|
12
16
|
import { useLanguageSelection } from '../../infrastructure/hooks/useLanguageSelection';
|
|
13
17
|
import { LanguageItem } from '../components/LanguageItem';
|
|
14
18
|
import type { Language } from '../../infrastructure/storage/types/Language';
|
|
@@ -17,7 +21,8 @@ import { styles } from './LanguageSelectionScreen.styles';
|
|
|
17
21
|
interface LanguageSelectionScreenProps {
|
|
18
22
|
renderLanguageItem?: (item: Language, isSelected: boolean, onSelect: (code: string) => void) => React.ReactNode;
|
|
19
23
|
renderSearchInput?: (value: string, onChange: (value: string) => void, placeholder: string) => React.ReactNode;
|
|
20
|
-
|
|
24
|
+
headerTitle?: string;
|
|
25
|
+
onBackPress?: () => void;
|
|
21
26
|
styles?: {
|
|
22
27
|
container?: any;
|
|
23
28
|
searchContainer?: any;
|
|
@@ -38,12 +43,13 @@ interface LanguageSelectionScreenProps {
|
|
|
38
43
|
export const LanguageSelectionScreen: React.FC<LanguageSelectionScreenProps> = ({
|
|
39
44
|
renderLanguageItem,
|
|
40
45
|
renderSearchInput,
|
|
41
|
-
|
|
46
|
+
headerTitle,
|
|
47
|
+
onBackPress,
|
|
42
48
|
styles: customStyles,
|
|
43
49
|
searchPlaceholder = "settings.languageSelection.searchPlaceholder",
|
|
44
50
|
testID = 'language-selection-screen',
|
|
45
51
|
}) => {
|
|
46
|
-
const navigation =
|
|
52
|
+
const navigation = useAppNavigation();
|
|
47
53
|
const tokens = useAppDesignTokens();
|
|
48
54
|
const {
|
|
49
55
|
searchQuery,
|
|
@@ -84,27 +90,53 @@ export const LanguageSelectionScreen: React.FC<LanguageSelectionScreenProps> = (
|
|
|
84
90
|
value={searchQuery}
|
|
85
91
|
onChangeText={setSearchQuery}
|
|
86
92
|
placeholder={searchPlaceholder}
|
|
87
|
-
containerStyle={
|
|
93
|
+
containerStyle={[
|
|
94
|
+
{ marginBottom: tokens.spacing.md },
|
|
95
|
+
customStyles?.searchContainer
|
|
96
|
+
]}
|
|
88
97
|
inputStyle={customStyles?.searchInput}
|
|
89
98
|
/>
|
|
90
99
|
);
|
|
91
100
|
};
|
|
92
101
|
|
|
93
|
-
const
|
|
94
|
-
|
|
102
|
+
const handleBack = () => {
|
|
103
|
+
if (onBackPress) {
|
|
104
|
+
onBackPress();
|
|
105
|
+
} else {
|
|
106
|
+
navigation.goBack();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<ScreenLayout
|
|
112
|
+
testID={testID}
|
|
113
|
+
scrollable={false}
|
|
114
|
+
edges={['top', 'bottom', 'left', 'right']}
|
|
115
|
+
backgroundColor={tokens.colors.backgroundPrimary}
|
|
116
|
+
header={
|
|
117
|
+
<NavigationHeader
|
|
118
|
+
title={headerTitle || ""}
|
|
119
|
+
onBackPress={handleBack}
|
|
120
|
+
/>
|
|
121
|
+
}
|
|
122
|
+
containerStyle={customStyles?.container}
|
|
123
|
+
>
|
|
95
124
|
{renderSearchComponent()}
|
|
96
125
|
<FlatList
|
|
97
126
|
data={filteredLanguages}
|
|
98
127
|
renderItem={renderItem}
|
|
99
128
|
keyExtractor={item => item.code}
|
|
100
|
-
contentContainerStyle={[
|
|
129
|
+
contentContainerStyle={[
|
|
130
|
+
styles.listContent,
|
|
131
|
+
{ paddingBottom: tokens.spacing.xl },
|
|
132
|
+
customStyles?.listContent
|
|
133
|
+
]}
|
|
101
134
|
showsVerticalScrollIndicator={false}
|
|
102
135
|
keyboardShouldPersistTaps="handled"
|
|
103
136
|
/>
|
|
104
|
-
</
|
|
137
|
+
</ScreenLayout>
|
|
105
138
|
);
|
|
106
|
-
|
|
107
|
-
return Container ? <Container>{content}</Container> : content;
|
|
108
139
|
};
|
|
109
140
|
|
|
110
141
|
export default LanguageSelectionScreen;
|
|
142
|
+
|