@umituz/react-native-localization 2.6.0 → 2.8.0
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/LICENSE +0 -0
- package/README.md +0 -0
- package/package.json +2 -2
- package/src/domain/repositories/ILocalizationRepository.ts +0 -0
- package/src/index.ts +3 -0
- package/src/infrastructure/components/LanguageSwitcher.tsx +0 -0
- package/src/infrastructure/components/LocalizationProvider.tsx +11 -3
- package/src/infrastructure/components/useLanguageNavigation.ts +0 -0
- package/src/infrastructure/config/I18nInitializer.ts +13 -66
- package/src/infrastructure/config/NamespaceResolver.ts +36 -0
- package/src/infrastructure/config/ResourceBuilder.ts +43 -0
- package/src/infrastructure/config/TranslationLoader.ts +0 -0
- package/src/infrastructure/config/i18n.ts +0 -0
- package/src/infrastructure/config/languages.ts +0 -0
- package/src/infrastructure/config/languagesData.ts +0 -0
- package/src/infrastructure/hooks/TranslationHook.ts +0 -0
- package/src/infrastructure/hooks/useTranslation.ts +0 -0
- package/src/infrastructure/locales/en-US/alerts.json +0 -0
- package/src/infrastructure/locales/en-US/auth.json +0 -0
- package/src/infrastructure/locales/en-US/branding.json +0 -0
- package/src/infrastructure/locales/en-US/clipboard.json +0 -0
- package/src/infrastructure/locales/en-US/common.json +0 -0
- package/src/infrastructure/locales/en-US/datetime.json +0 -0
- package/src/infrastructure/locales/en-US/device.json +0 -0
- package/src/infrastructure/locales/en-US/editor.json +0 -0
- package/src/infrastructure/locales/en-US/errors.json +0 -0
- package/src/infrastructure/locales/en-US/general.json +0 -0
- package/src/infrastructure/locales/en-US/goals.json +0 -0
- package/src/infrastructure/locales/en-US/haptics.json +0 -0
- package/src/infrastructure/locales/en-US/home.json +0 -0
- package/src/infrastructure/locales/en-US/index.ts +0 -0
- package/src/infrastructure/locales/en-US/navigation.json +0 -0
- package/src/infrastructure/locales/en-US/onboarding.json +0 -0
- package/src/infrastructure/locales/en-US/projects.json +0 -0
- package/src/infrastructure/locales/en-US/settings.json +0 -0
- package/src/infrastructure/locales/en-US/sharing.json +0 -0
- package/src/infrastructure/locales/en-US/templates.json +0 -0
- package/src/infrastructure/scripts/createLocaleLoaders.js +0 -0
- package/src/infrastructure/storage/AsyncStorageWrapper.ts +0 -0
- package/src/infrastructure/storage/LanguageInitializer.ts +0 -0
- package/src/infrastructure/storage/LanguageSwitcher.ts +0 -0
- package/src/infrastructure/storage/LocalizationStore.ts +0 -0
- package/src/presentation/screens/LanguageSelectionScreen.tsx +204 -0
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-localization",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "English-only localization system for React Native apps with i18n support",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|
|
36
|
-
"url": "https://github.com/umituz/react-native-localization"
|
|
36
|
+
"url": "git+https://github.com/umituz/react-native-localization.git"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"expo-localization": "~15.0.0",
|
|
File without changes
|
package/src/index.ts
CHANGED
|
@@ -26,5 +26,8 @@ export {
|
|
|
26
26
|
searchLanguages,
|
|
27
27
|
} from './infrastructure/config/languages';
|
|
28
28
|
|
|
29
|
+
// Presentation
|
|
30
|
+
export { LanguageSelectionScreen } from './presentation/screens/LanguageSelectionScreen';
|
|
31
|
+
|
|
29
32
|
// Types
|
|
30
33
|
export type { Language, ILocalizationRepository } from './domain/repositories/ILocalizationRepository';
|
|
File without changes
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LocalizationProvider Component
|
|
3
|
-
* Initializes localization system
|
|
3
|
+
* Initializes localization system with app translations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React, { useEffect, ReactNode } from 'react';
|
|
7
7
|
import { useLocalizationStore } from '../storage/LocalizationStore';
|
|
8
|
+
import { I18nInitializer } from '../config/I18nInitializer';
|
|
8
9
|
|
|
9
10
|
interface LocalizationProviderProps {
|
|
10
11
|
children: ReactNode;
|
|
12
|
+
translations: Record<string, any>;
|
|
13
|
+
defaultLanguage?: string;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
|
-
export const LocalizationProvider: React.FC<LocalizationProviderProps> = ({
|
|
16
|
+
export const LocalizationProvider: React.FC<LocalizationProviderProps> = ({
|
|
17
|
+
children,
|
|
18
|
+
translations,
|
|
19
|
+
defaultLanguage = 'en-US',
|
|
20
|
+
}) => {
|
|
14
21
|
const initialize = useLocalizationStore((state) => state.initialize);
|
|
15
22
|
|
|
16
23
|
useEffect(() => {
|
|
24
|
+
I18nInitializer.initialize(translations, defaultLanguage);
|
|
17
25
|
initialize();
|
|
18
|
-
}, [initialize]);
|
|
26
|
+
}, [translations, defaultLanguage, initialize]);
|
|
19
27
|
|
|
20
28
|
return <>{children}</>;
|
|
21
29
|
};
|
|
File without changes
|
|
@@ -8,70 +8,16 @@
|
|
|
8
8
|
import i18n from 'i18next';
|
|
9
9
|
import { initReactI18next } from 'react-i18next';
|
|
10
10
|
import { DEFAULT_LANGUAGE } from './languages';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
const DEFAULT_NAMESPACE = 'common';
|
|
11
|
+
import { ResourceBuilder } from './ResourceBuilder';
|
|
12
|
+
import { NamespaceResolver } from './NamespaceResolver';
|
|
14
13
|
|
|
15
14
|
export class I18nInitializer {
|
|
16
15
|
private static reactI18nextInitialized = false;
|
|
17
|
-
private static appTranslations: Record<string, any> = {};
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Register app translations (call before initialize)
|
|
21
|
-
*/
|
|
22
|
-
static registerAppTranslations(translations: Record<string, any>): void {
|
|
23
|
-
this.appTranslations = translations;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Build resources with package + registered app translations
|
|
28
|
-
*/
|
|
29
|
-
private static buildResources(): Record<string, Record<string, any>> {
|
|
30
|
-
const packageTranslations = TranslationLoader.loadPackageTranslations();
|
|
31
|
-
|
|
32
|
-
const resources: Record<string, Record<string, any>> = {
|
|
33
|
-
'en-US': {},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const enUSPackage = packageTranslations['en-US'] || {};
|
|
37
|
-
|
|
38
|
-
// Add package namespaces
|
|
39
|
-
for (const [namespace, translations] of Object.entries(enUSPackage)) {
|
|
40
|
-
resources['en-US'][namespace] = translations;
|
|
41
|
-
}
|
|
42
16
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
resources['en-US'][namespace],
|
|
48
|
-
translations
|
|
49
|
-
);
|
|
50
|
-
} else {
|
|
51
|
-
resources['en-US'][namespace] = translations;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return resources;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private static getNamespaces(): string[] {
|
|
59
|
-
const packageTranslations = TranslationLoader.loadPackageTranslations();
|
|
60
|
-
const enUSPackage = packageTranslations['en-US'] || {};
|
|
61
|
-
|
|
62
|
-
const namespaces = new Set([
|
|
63
|
-
...Object.keys(enUSPackage),
|
|
64
|
-
...Object.keys(this.appTranslations),
|
|
65
|
-
]);
|
|
66
|
-
|
|
67
|
-
if (!namespaces.has(DEFAULT_NAMESPACE)) {
|
|
68
|
-
namespaces.add(DEFAULT_NAMESPACE);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return Array.from(namespaces);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
static initialize(): void {
|
|
17
|
+
static initialize(
|
|
18
|
+
appTranslations: Record<string, any>,
|
|
19
|
+
languageCode: string = DEFAULT_LANGUAGE
|
|
20
|
+
): void {
|
|
75
21
|
if (i18n.isInitialized) {
|
|
76
22
|
return;
|
|
77
23
|
}
|
|
@@ -82,16 +28,17 @@ export class I18nInitializer {
|
|
|
82
28
|
this.reactI18nextInitialized = true;
|
|
83
29
|
}
|
|
84
30
|
|
|
85
|
-
const resources =
|
|
86
|
-
const namespaces =
|
|
31
|
+
const resources = ResourceBuilder.buildResources(appTranslations, languageCode);
|
|
32
|
+
const namespaces = NamespaceResolver.getNamespaces(appTranslations, languageCode);
|
|
33
|
+
const defaultNamespace = NamespaceResolver.getDefaultNamespace();
|
|
87
34
|
|
|
88
35
|
i18n.init({
|
|
89
36
|
resources,
|
|
90
|
-
lng:
|
|
91
|
-
fallbackLng:
|
|
37
|
+
lng: languageCode,
|
|
38
|
+
fallbackLng: languageCode,
|
|
92
39
|
ns: namespaces,
|
|
93
|
-
defaultNS:
|
|
94
|
-
fallbackNS:
|
|
40
|
+
defaultNS: defaultNamespace,
|
|
41
|
+
fallbackNS: defaultNamespace,
|
|
95
42
|
interpolation: { escapeValue: false },
|
|
96
43
|
react: { useSuspense: false },
|
|
97
44
|
compatibilityJSON: 'v3',
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Namespace Resolver
|
|
3
|
+
* Resolves available namespaces from translations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { TranslationLoader } from './TranslationLoader';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_NAMESPACE = 'common';
|
|
9
|
+
|
|
10
|
+
export class NamespaceResolver {
|
|
11
|
+
/**
|
|
12
|
+
* Get all available namespaces from package and app translations
|
|
13
|
+
*/
|
|
14
|
+
static getNamespaces(
|
|
15
|
+
appTranslations: Record<string, any>,
|
|
16
|
+
languageCode: string
|
|
17
|
+
): string[] {
|
|
18
|
+
const packageTranslations = TranslationLoader.loadPackageTranslations();
|
|
19
|
+
const packageLang = packageTranslations[languageCode] || {};
|
|
20
|
+
|
|
21
|
+
const namespaces = new Set([
|
|
22
|
+
...Object.keys(packageLang),
|
|
23
|
+
...Object.keys(appTranslations),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
if (!namespaces.has(DEFAULT_NAMESPACE)) {
|
|
27
|
+
namespaces.add(DEFAULT_NAMESPACE);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return Array.from(namespaces);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static getDefaultNamespace(): string {
|
|
34
|
+
return DEFAULT_NAMESPACE;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Builder
|
|
3
|
+
* Builds i18n resources from package and app translations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { TranslationLoader } from './TranslationLoader';
|
|
7
|
+
|
|
8
|
+
export class ResourceBuilder {
|
|
9
|
+
/**
|
|
10
|
+
* Build resources with package + app translations
|
|
11
|
+
*/
|
|
12
|
+
static buildResources(
|
|
13
|
+
appTranslations: Record<string, any>,
|
|
14
|
+
languageCode: string
|
|
15
|
+
): Record<string, Record<string, any>> {
|
|
16
|
+
const packageTranslations = TranslationLoader.loadPackageTranslations();
|
|
17
|
+
|
|
18
|
+
const resources: Record<string, Record<string, any>> = {
|
|
19
|
+
[languageCode]: {},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const packageLang = packageTranslations[languageCode] || {};
|
|
23
|
+
|
|
24
|
+
// Add package namespaces
|
|
25
|
+
for (const [namespace, translations] of Object.entries(packageLang)) {
|
|
26
|
+
resources[languageCode][namespace] = translations;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Merge app translations (app overrides package)
|
|
30
|
+
for (const [namespace, translations] of Object.entries(appTranslations)) {
|
|
31
|
+
if (resources[languageCode][namespace]) {
|
|
32
|
+
resources[languageCode][namespace] = TranslationLoader.mergeTranslations(
|
|
33
|
+
resources[languageCode][namespace],
|
|
34
|
+
translations
|
|
35
|
+
);
|
|
36
|
+
} else {
|
|
37
|
+
resources[languageCode][namespace] = translations;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return resources;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language Selection Screen
|
|
3
|
+
*
|
|
4
|
+
* Language picker with search functionality
|
|
5
|
+
*
|
|
6
|
+
* App Factory - Universal Language Selector
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React, { useState, useMemo } from 'react';
|
|
10
|
+
import {
|
|
11
|
+
View,
|
|
12
|
+
StyleSheet,
|
|
13
|
+
FlatList,
|
|
14
|
+
TouchableOpacity,
|
|
15
|
+
TextInput,
|
|
16
|
+
} from 'react-native';
|
|
17
|
+
import { useNavigation } from '@react-navigation/native';
|
|
18
|
+
import { useAppDesignTokens, withAlpha, STATIC_TOKENS, type DesignTokens } from '@umituz/react-native-design-system-theme';
|
|
19
|
+
import { AtomicIcon, AtomicText } from '@umituz/react-native-design-system-atoms';
|
|
20
|
+
import { ScreenLayout } from '@umituz/react-native-design-system-organisms';
|
|
21
|
+
import { useLocalization, searchLanguages, Language, LANGUAGES } from '@umituz/react-native-localization';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Language Selection Screen Component
|
|
25
|
+
*/
|
|
26
|
+
export const LanguageSelectionScreen: React.FC = () => {
|
|
27
|
+
const navigation = useNavigation();
|
|
28
|
+
const { t, currentLanguage, setLanguage } = useLocalization();
|
|
29
|
+
const tokens = useAppDesignTokens();
|
|
30
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
31
|
+
const [selectedCode, setSelectedCode] = useState(currentLanguage);
|
|
32
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
33
|
+
|
|
34
|
+
const filteredLanguages = useMemo(() => {
|
|
35
|
+
return searchLanguages(searchQuery);
|
|
36
|
+
}, [searchQuery]);
|
|
37
|
+
|
|
38
|
+
const handleLanguageSelect = async (code: string) => {
|
|
39
|
+
setSelectedCode(code);
|
|
40
|
+
await setLanguage(code);
|
|
41
|
+
navigation.goBack();
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const renderLanguageItem = ({ item }: { item: Language }) => {
|
|
45
|
+
const isSelected = selectedCode === item.code;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<TouchableOpacity
|
|
49
|
+
style={StyleSheet.flatten([
|
|
50
|
+
styles.languageItem,
|
|
51
|
+
{
|
|
52
|
+
borderColor: isSelected
|
|
53
|
+
? tokens.colors.primary
|
|
54
|
+
: tokens.colors.borderLight,
|
|
55
|
+
backgroundColor: isSelected
|
|
56
|
+
? withAlpha(tokens.colors.primary, 0.1)
|
|
57
|
+
: tokens.colors.surface,
|
|
58
|
+
},
|
|
59
|
+
])}
|
|
60
|
+
onPress={() => handleLanguageSelect(item.code)}
|
|
61
|
+
activeOpacity={0.7}
|
|
62
|
+
>
|
|
63
|
+
<View style={styles.languageContent}>
|
|
64
|
+
<AtomicText style={StyleSheet.flatten([STATIC_TOKENS.typography.headingLarge, styles.flag])}>
|
|
65
|
+
{item.flag}
|
|
66
|
+
</AtomicText>
|
|
67
|
+
<View style={styles.languageText}>
|
|
68
|
+
<AtomicText
|
|
69
|
+
style={StyleSheet.flatten([
|
|
70
|
+
STATIC_TOKENS.typography.bodyMedium,
|
|
71
|
+
styles.nativeName,
|
|
72
|
+
])}
|
|
73
|
+
>
|
|
74
|
+
{item.nativeName}
|
|
75
|
+
</AtomicText>
|
|
76
|
+
<AtomicText style={StyleSheet.flatten([{ color: tokens.colors.textSecondary }])}>
|
|
77
|
+
{item.name}
|
|
78
|
+
</AtomicText>
|
|
79
|
+
</View>
|
|
80
|
+
</View>
|
|
81
|
+
{isSelected && (
|
|
82
|
+
<AtomicIcon
|
|
83
|
+
name="CircleCheck"
|
|
84
|
+
size="md"
|
|
85
|
+
color="primary"
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
88
|
+
</TouchableOpacity>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<ScreenLayout scrollable={false} testID="language-selection-screen">
|
|
94
|
+
{/* Search Input */}
|
|
95
|
+
<View
|
|
96
|
+
style={StyleSheet.flatten([
|
|
97
|
+
styles.searchContainer,
|
|
98
|
+
{
|
|
99
|
+
borderColor: isFocused ? tokens.colors.primary : tokens.colors.borderLight,
|
|
100
|
+
borderWidth: isFocused ? 2 : 1.5,
|
|
101
|
+
backgroundColor: tokens.colors.surface,
|
|
102
|
+
},
|
|
103
|
+
])}
|
|
104
|
+
>
|
|
105
|
+
<AtomicIcon
|
|
106
|
+
name="Search"
|
|
107
|
+
size="md"
|
|
108
|
+
color="secondary"
|
|
109
|
+
style={styles.searchIcon}
|
|
110
|
+
/>
|
|
111
|
+
<TextInput
|
|
112
|
+
style={StyleSheet.flatten([styles.searchInput, { color: tokens.colors.textPrimary }])}
|
|
113
|
+
placeholder={t('settings.languageSelection.searchPlaceholder')}
|
|
114
|
+
placeholderTextColor={tokens.colors.textSecondary}
|
|
115
|
+
value={searchQuery}
|
|
116
|
+
onChangeText={setSearchQuery}
|
|
117
|
+
onFocus={() => setIsFocused(true)}
|
|
118
|
+
onBlur={() => setIsFocused(false)}
|
|
119
|
+
autoCapitalize="none"
|
|
120
|
+
autoCorrect={false}
|
|
121
|
+
/>
|
|
122
|
+
{searchQuery.length > 0 && (
|
|
123
|
+
<TouchableOpacity
|
|
124
|
+
onPress={() => setSearchQuery('')}
|
|
125
|
+
style={styles.clearButton}
|
|
126
|
+
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
127
|
+
>
|
|
128
|
+
<AtomicIcon
|
|
129
|
+
name="X"
|
|
130
|
+
size="sm"
|
|
131
|
+
color="secondary"
|
|
132
|
+
/>
|
|
133
|
+
</TouchableOpacity>
|
|
134
|
+
)}
|
|
135
|
+
</View>
|
|
136
|
+
|
|
137
|
+
{/* Language List */}
|
|
138
|
+
<FlatList
|
|
139
|
+
data={filteredLanguages}
|
|
140
|
+
renderItem={renderLanguageItem}
|
|
141
|
+
keyExtractor={item => item.code}
|
|
142
|
+
contentContainerStyle={styles.listContent}
|
|
143
|
+
showsVerticalScrollIndicator={false}
|
|
144
|
+
keyboardShouldPersistTaps="handled"
|
|
145
|
+
/>
|
|
146
|
+
</ScreenLayout>
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const styles = StyleSheet.create({
|
|
151
|
+
searchContainer: {
|
|
152
|
+
flexDirection: 'row',
|
|
153
|
+
alignItems: 'center',
|
|
154
|
+
marginHorizontal: 20,
|
|
155
|
+
marginBottom: 24,
|
|
156
|
+
paddingHorizontal: 16,
|
|
157
|
+
paddingVertical: 8,
|
|
158
|
+
borderRadius: STATIC_TOKENS.borders.radius.lg,
|
|
159
|
+
},
|
|
160
|
+
searchIcon: {
|
|
161
|
+
marginRight: 8,
|
|
162
|
+
},
|
|
163
|
+
searchInput: {
|
|
164
|
+
flex: 1,
|
|
165
|
+
fontSize: STATIC_TOKENS.typography.bodyMedium.fontSize,
|
|
166
|
+
padding: 0,
|
|
167
|
+
fontWeight: '500',
|
|
168
|
+
},
|
|
169
|
+
clearButton: {
|
|
170
|
+
padding: STATIC_TOKENS.spacing.xs,
|
|
171
|
+
},
|
|
172
|
+
listContent: {
|
|
173
|
+
paddingHorizontal: 20,
|
|
174
|
+
paddingBottom: 32,
|
|
175
|
+
},
|
|
176
|
+
languageItem: {
|
|
177
|
+
flexDirection: 'row',
|
|
178
|
+
alignItems: 'center',
|
|
179
|
+
justifyContent: 'space-between',
|
|
180
|
+
padding: STATIC_TOKENS.spacing.md,
|
|
181
|
+
borderRadius: STATIC_TOKENS.borders.radius.lg,
|
|
182
|
+
borderWidth: 2,
|
|
183
|
+
marginBottom: 8,
|
|
184
|
+
},
|
|
185
|
+
languageContent: {
|
|
186
|
+
flexDirection: 'row',
|
|
187
|
+
alignItems: 'center',
|
|
188
|
+
flex: 1,
|
|
189
|
+
gap: 16,
|
|
190
|
+
},
|
|
191
|
+
flag: {
|
|
192
|
+
fontSize: STATIC_TOKENS.typography.headingLarge.fontSize,
|
|
193
|
+
},
|
|
194
|
+
languageText: {
|
|
195
|
+
flex: 1,
|
|
196
|
+
gap: 2,
|
|
197
|
+
},
|
|
198
|
+
nativeName: {
|
|
199
|
+
fontWeight: '600',
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
export default LanguageSelectionScreen;
|
|
204
|
+
|