@umituz/react-native-localization 1.2.1 → 1.3.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/lib/index.d.ts CHANGED
@@ -4,6 +4,8 @@
4
4
  */
5
5
  export { useLocalization, useLocalizationStore } from './infrastructure/storage/LocalizationStore';
6
6
  export { LocalizationProvider } from './infrastructure/components/LocalizationProvider';
7
+ export { LanguageSwitcher } from './infrastructure/components/LanguageSwitcher';
8
+ export { useLanguageNavigation } from './infrastructure/components/useLanguageNavigation';
7
9
  export { default as i18n } from './infrastructure/config/i18n';
8
10
  export { SUPPORTED_LANGUAGES, DEFAULT_LANGUAGE, getLanguageByCode, isLanguageSupported, getDefaultLanguage, getDeviceLocale, } from './infrastructure/config/languages';
9
11
  export type { Language, ILocalizationRepository } from './domain/repositories/ILocalizationRepository';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAGnG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kDAAkD,CAAC;AAGxF,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,mCAAmC,CAAC;AAG3C,YAAY,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAGnG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kDAAkD,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mDAAmD,CAAC;AAG1F,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,mCAAmC,CAAC;AAG3C,YAAY,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC"}
package/lib/index.js CHANGED
@@ -6,6 +6,8 @@
6
6
  export { useLocalization, useLocalizationStore } from './infrastructure/storage/LocalizationStore';
7
7
  // Components
8
8
  export { LocalizationProvider } from './infrastructure/components/LocalizationProvider';
9
+ export { LanguageSwitcher } from './infrastructure/components/LanguageSwitcher';
10
+ export { useLanguageNavigation } from './infrastructure/components/useLanguageNavigation';
9
11
  // Configuration
10
12
  export { default as i18n } from './infrastructure/config/i18n';
11
13
  export { SUPPORTED_LANGUAGES, DEFAULT_LANGUAGE, getLanguageByCode, isLanguageSupported, getDefaultLanguage, getDeviceLocale, } from './infrastructure/config/languages';
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,QAAQ;AACR,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAEnG,aAAa;AACb,OAAO,EAAE,oBAAoB,EAAE,MAAM,kDAAkD,CAAC;AAExF,gBAAgB;AAChB,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,QAAQ;AACR,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAEnG,aAAa;AACb,OAAO,EAAE,oBAAoB,EAAE,MAAM,kDAAkD,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mDAAmD,CAAC;AAE1F,gBAAgB;AAChB,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ interface LanguageSwitcherProps {
3
+ showName?: boolean;
4
+ showFlag?: boolean;
5
+ color?: string;
6
+ navigationScreen?: string;
7
+ style?: any;
8
+ textStyle?: any;
9
+ }
10
+ export declare const LanguageSwitcher: React.FC<LanguageSwitcherProps>;
11
+ export default LanguageSwitcher;
12
+ //# sourceMappingURL=LanguageSwitcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageSwitcher.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/components/LanguageSwitcher.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,SAAS,CAAC,EAAE,GAAG,CAAC;CACjB;AAQD,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAwC5D,CAAC;AAqBF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import { TouchableOpacity, Text, StyleSheet } from 'react-native';
3
+ // @ts-ignore - Optional peer dependency
4
+ import { useNavigation } from '@react-navigation/native';
5
+ import { useLocalization } from '../storage/LocalizationStore';
6
+ import { getLanguageByCode, getDefaultLanguage } from '../config/languages';
7
+ const languageSwitcherConfig = {
8
+ defaultIconSize: 20,
9
+ defaultNavigationScreen: 'LanguageSelection',
10
+ hitSlop: { top: 10, bottom: 10, left: 10, right: 10 },
11
+ };
12
+ export const LanguageSwitcher = ({ showName = false, showFlag = true, color, navigationScreen = languageSwitcherConfig.defaultNavigationScreen, style, textStyle, }) => {
13
+ const navigation = useNavigation();
14
+ const { currentLanguage } = useLocalization();
15
+ const currentLang = getLanguageByCode(currentLanguage) || getDefaultLanguage();
16
+ const navigateToLanguageSelection = () => {
17
+ if (navigation && navigationScreen) {
18
+ navigation.navigate(navigationScreen);
19
+ }
20
+ };
21
+ const iconColor = color || '#000000';
22
+ return (<TouchableOpacity style={[styles.container, style]} onPress={navigateToLanguageSelection} activeOpacity={0.7} hitSlop={languageSwitcherConfig.hitSlop}>
23
+ {showFlag && (<Text style={[styles.flag, textStyle]}>{currentLang.flag}</Text>)}
24
+ {showName && (<Text style={[styles.languageName, { color: iconColor }, textStyle]}>
25
+ {currentLang.nativeName}
26
+ </Text>)}
27
+ {!showName && !showFlag && (<Text style={[styles.icon, { color: iconColor }]}>🌐</Text>)}
28
+ </TouchableOpacity>);
29
+ };
30
+ const styles = StyleSheet.create({
31
+ container: {
32
+ flexDirection: 'row',
33
+ alignItems: 'center',
34
+ gap: 8,
35
+ paddingHorizontal: 4,
36
+ },
37
+ flag: {
38
+ fontSize: 20,
39
+ },
40
+ languageName: {
41
+ fontSize: 14,
42
+ fontWeight: '600',
43
+ },
44
+ icon: {
45
+ fontSize: 20,
46
+ },
47
+ });
48
+ export default LanguageSwitcher;
49
+ //# sourceMappingURL=LanguageSwitcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageSwitcher.js","sourceRoot":"","sources":["../../../src/infrastructure/components/LanguageSwitcher.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { Language } from '../../domain/repositories/ILocalizationRepository';
2
+ export declare const useLanguageNavigation: (navigationScreen: string) => {
3
+ currentLang: Language;
4
+ navigateToLanguageSelection: () => void;
5
+ };
6
+ //# sourceMappingURL=useLanguageNavigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLanguageNavigation.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/components/useLanguageNavigation.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,mDAAmD,CAAC;AAE7E,eAAO,MAAM,qBAAqB,GAAI,kBAAkB,MAAM;;;CAY7D,CAAC"}
@@ -0,0 +1,16 @@
1
+ // @ts-ignore - Optional peer dependency
2
+ import { useNavigation } from '@react-navigation/native';
3
+ import { useLocalization } from '../storage/LocalizationStore';
4
+ import { getLanguageByCode, getDefaultLanguage } from '../config/languages';
5
+ export const useLanguageNavigation = (navigationScreen) => {
6
+ const navigation = useNavigation();
7
+ const { currentLanguage } = useLocalization();
8
+ const currentLang = getLanguageByCode(currentLanguage) || getDefaultLanguage();
9
+ const navigateToLanguageSelection = () => {
10
+ if (navigation && navigationScreen) {
11
+ navigation.navigate(navigationScreen);
12
+ }
13
+ };
14
+ return { currentLang, navigateToLanguageSelection };
15
+ };
16
+ //# sourceMappingURL=useLanguageNavigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLanguageNavigation.js","sourceRoot":"","sources":["../../../src/infrastructure/components/useLanguageNavigation.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,gBAAwB,EAAE,EAAE;IAChE,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAAC;IAC9C,MAAM,WAAW,GAAG,iBAAiB,CAAC,eAAe,CAAC,IAAI,kBAAkB,EAAE,CAAC;IAE/E,MAAM,2BAA2B,GAAG,GAAG,EAAE;QACvC,IAAI,UAAU,IAAI,gBAAgB,EAAE,CAAC;YACnC,UAAU,CAAC,QAAQ,CAAC,gBAAyB,CAAC,CAAC;QACjD,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC;AACtD,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/config/i18n.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,SAAS,CAAC;AAmD3B,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/config/i18n.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,SAAS,CAAC;AA6F3B,eAAe,IAAI,CAAC"}
@@ -32,18 +32,61 @@ const resources = {
32
32
  };
33
33
  /**
34
34
  * Initialize i18next
35
+ * Deferred initialization to avoid React Native renderer conflicts
35
36
  */
36
- i18n.use(initReactI18next).init({
37
- resources,
38
- lng: DEFAULT_LANGUAGE,
39
- fallbackLng: DEFAULT_LANGUAGE,
40
- interpolation: {
41
- escapeValue: false, // React already escapes values
42
- },
43
- react: {
44
- useSuspense: false, // Disable suspense for React Native
45
- },
46
- compatibilityJSON: 'v4', // Use i18next v4 JSON format
47
- });
37
+ let isInitialized = false;
38
+ const initializeI18n = () => {
39
+ if (isInitialized)
40
+ return;
41
+ try {
42
+ /* eslint-disable-next-line no-console */
43
+ if (__DEV__)
44
+ console.log('[i18n] Initializing i18next...');
45
+ // Check if initReactI18next is available
46
+ if (!initReactI18next) {
47
+ throw new Error('initReactI18next is undefined');
48
+ }
49
+ /* eslint-disable-next-line no-console */
50
+ if (__DEV__)
51
+ console.log('[i18n] initReactI18next found, initializing...');
52
+ i18n.use(initReactI18next).init({
53
+ resources,
54
+ lng: DEFAULT_LANGUAGE,
55
+ fallbackLng: DEFAULT_LANGUAGE,
56
+ interpolation: {
57
+ escapeValue: false, // React already escapes values
58
+ },
59
+ react: {
60
+ useSuspense: false, // Disable suspense for React Native
61
+ },
62
+ compatibilityJSON: 'v4', // Use i18next v4 JSON format
63
+ });
64
+ isInitialized = true;
65
+ /* eslint-disable-next-line no-console */
66
+ if (__DEV__)
67
+ console.log('[i18n] i18next initialized successfully');
68
+ }
69
+ catch (error) {
70
+ /* eslint-disable-next-line no-console */
71
+ if (__DEV__)
72
+ console.error('[i18n] Initialization error:', error);
73
+ // Don't throw - allow app to continue without i18n
74
+ /* eslint-disable-next-line no-console */
75
+ if (__DEV__)
76
+ console.warn('[i18n] Continuing without i18n initialization');
77
+ }
78
+ };
79
+ // Defer initialization until React is ready
80
+ // React Native doesn't have window, so we check for global
81
+ if (typeof global !== 'undefined') {
82
+ // Use setTimeout to defer initialization
83
+ setTimeout(() => {
84
+ initializeI18n();
85
+ }, 0);
86
+ }
87
+ else {
88
+ // Fallback: initialize immediately
89
+ initializeI18n();
90
+ }
48
91
  export default i18n;
49
92
  //# sourceMappingURL=i18n.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../../src/infrastructure/config/i18n.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAuB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpE;;;;;;;;;;GAUG;AAEH,yDAAyD;AACzD,OAAO,gBAAgB,MAAM,kBAAkB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,SAAS,GAAG;IAChB,OAAO,EAAE;QACP,WAAW,EAAE;YACX,GAAG,gBAAgB;SACpB;KACF;CACF,CAAC;AAEF;;GAEG;AACH,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC;IAC9B,SAAS;IACT,GAAG,EAAE,gBAAgB;IACrB,WAAW,EAAE,gBAAgB;IAE7B,aAAa,EAAE;QACb,WAAW,EAAE,KAAK,EAAE,+BAA+B;KACpD;IAED,KAAK,EAAE;QACL,WAAW,EAAE,KAAK,EAAE,oCAAoC;KACzD;IAED,iBAAiB,EAAE,IAAI,EAAE,6BAA6B;CACvD,CAAC,CAAC;AAEH,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../../src/infrastructure/config/i18n.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAuB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpE;;;;;;;;;;GAUG;AAEH,yDAAyD;AACzD,OAAO,gBAAgB,MAAM,kBAAkB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,SAAS,GAAG;IAChB,OAAO,EAAE;QACP,WAAW,EAAE;YACX,GAAG,gBAAgB;SACpB;KACF;CACF,CAAC;AAEF;;;GAGG;AACH,IAAI,aAAa,GAAG,KAAK,CAAC;AAE1B,MAAM,cAAc,GAAG,GAAG,EAAE;IAC1B,IAAI,aAAa;QAAE,OAAO;IAE1B,IAAI,CAAC;QACH,yCAAyC;QACzC,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAE3D,yCAAyC;QACzC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnD,CAAC;QAED,yCAAyC;QACzC,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAE3E,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC;YAC9B,SAAS;YACT,GAAG,EAAE,gBAAgB;YACrB,WAAW,EAAE,gBAAgB;YAE7B,aAAa,EAAE;gBACb,WAAW,EAAE,KAAK,EAAE,+BAA+B;aACpD;YAED,KAAK,EAAE;gBACL,WAAW,EAAE,KAAK,EAAE,oCAAoC;aACzD;YAED,iBAAiB,EAAE,IAAI,EAAE,6BAA6B;SACvD,CAAC,CAAC;QAEH,aAAa,GAAG,IAAI,CAAC;QACrB,yCAAyC;QACzC,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yCAAyC;QACzC,IAAI,OAAO;YAAE,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QAClE,mDAAmD;QACnD,yCAAyC;QACzC,IAAI,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC,CAAC;AAEF,4CAA4C;AAC5C,2DAA2D;AAC3D,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;IAClC,yCAAyC;IACzC,UAAU,CAAC,GAAG,EAAE;QACd,cAAc,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,CAAC,CAAC;AACR,CAAC;KAAM,CAAC;IACN,mCAAmC;IACnC,cAAc,EAAE,CAAC;AACnB,CAAC;AAED,eAAe,IAAI,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-localization",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Universal localization system for React Native apps with i18n support",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -46,7 +46,13 @@
46
46
  },
47
47
  "peerDependencies": {
48
48
  "react": ">=18.2.0",
49
- "react-native": ">=0.74.0"
49
+ "react-native": ">=0.74.0",
50
+ "@react-navigation/native": "^6.0.0"
51
+ },
52
+ "peerDependenciesMeta": {
53
+ "@react-navigation/native": {
54
+ "optional": true
55
+ }
50
56
  },
51
57
  "devDependencies": {
52
58
  "typescript": "^5.3.3",
package/src/index.ts CHANGED
@@ -8,6 +8,8 @@ export { useLocalization, useLocalizationStore } from './infrastructure/storage/
8
8
 
9
9
  // Components
10
10
  export { LocalizationProvider } from './infrastructure/components/LocalizationProvider';
11
+ export { LanguageSwitcher } from './infrastructure/components/LanguageSwitcher';
12
+ export { useLanguageNavigation } from './infrastructure/components/useLanguageNavigation';
11
13
 
12
14
  // Configuration
13
15
  export { default as i18n } from './infrastructure/config/i18n';
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import { TouchableOpacity, Text, View, StyleSheet } from 'react-native';
3
+ // @ts-ignore - Optional peer dependency
4
+ import { useNavigation } from '@react-navigation/native';
5
+ import { useLocalization } from '../storage/LocalizationStore';
6
+ import { getLanguageByCode, getDefaultLanguage } from '../config/languages';
7
+ import { Language } from '../../domain/repositories/ILocalizationRepository';
8
+
9
+ interface LanguageSwitcherProps {
10
+ showName?: boolean;
11
+ showFlag?: boolean;
12
+ color?: string;
13
+ navigationScreen?: string;
14
+ style?: any;
15
+ textStyle?: any;
16
+ }
17
+
18
+ const languageSwitcherConfig = {
19
+ defaultIconSize: 20,
20
+ defaultNavigationScreen: 'LanguageSelection',
21
+ hitSlop: { top: 10, bottom: 10, left: 10, right: 10 },
22
+ };
23
+
24
+ export const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({
25
+ showName = false,
26
+ showFlag = true,
27
+ color,
28
+ navigationScreen = languageSwitcherConfig.defaultNavigationScreen,
29
+ style,
30
+ textStyle,
31
+ }) => {
32
+ const navigation = useNavigation();
33
+ const { currentLanguage } = useLocalization();
34
+ const currentLang = getLanguageByCode(currentLanguage) || getDefaultLanguage();
35
+
36
+ const navigateToLanguageSelection = () => {
37
+ if (navigation && navigationScreen) {
38
+ navigation.navigate(navigationScreen as never);
39
+ }
40
+ };
41
+
42
+ const iconColor = color || '#000000';
43
+
44
+ return (
45
+ <TouchableOpacity
46
+ style={[styles.container, style]}
47
+ onPress={navigateToLanguageSelection}
48
+ activeOpacity={0.7}
49
+ hitSlop={languageSwitcherConfig.hitSlop}
50
+ >
51
+ {showFlag && (
52
+ <Text style={[styles.flag, textStyle]}>{currentLang.flag}</Text>
53
+ )}
54
+ {showName && (
55
+ <Text style={[styles.languageName, { color: iconColor }, textStyle]}>
56
+ {currentLang.nativeName}
57
+ </Text>
58
+ )}
59
+ {!showName && !showFlag && (
60
+ <Text style={[styles.icon, { color: iconColor }]}>🌐</Text>
61
+ )}
62
+ </TouchableOpacity>
63
+ );
64
+ };
65
+
66
+ const styles = StyleSheet.create({
67
+ container: {
68
+ flexDirection: 'row',
69
+ alignItems: 'center',
70
+ gap: 8,
71
+ paddingHorizontal: 4,
72
+ },
73
+ flag: {
74
+ fontSize: 20,
75
+ },
76
+ languageName: {
77
+ fontSize: 14,
78
+ fontWeight: '600',
79
+ },
80
+ icon: {
81
+ fontSize: 20,
82
+ },
83
+ });
84
+
85
+ export default LanguageSwitcher;
86
+
@@ -0,0 +1,20 @@
1
+ // @ts-ignore - Optional peer dependency
2
+ import { useNavigation } from '@react-navigation/native';
3
+ import { useLocalization } from '../storage/LocalizationStore';
4
+ import { getLanguageByCode, getDefaultLanguage } from '../config/languages';
5
+ import { Language } from '../../domain/repositories/ILocalizationRepository';
6
+
7
+ export const useLanguageNavigation = (navigationScreen: string) => {
8
+ const navigation = useNavigation();
9
+ const { currentLanguage } = useLocalization();
10
+ const currentLang = getLanguageByCode(currentLanguage) || getDefaultLanguage();
11
+
12
+ const navigateToLanguageSelection = () => {
13
+ if (navigation && navigationScreen) {
14
+ navigation.navigate(navigationScreen as never);
15
+ }
16
+ };
17
+
18
+ return { currentLang, navigateToLanguageSelection };
19
+ };
20
+
@@ -37,21 +37,63 @@ const resources = {
37
37
 
38
38
  /**
39
39
  * Initialize i18next
40
+ * Deferred initialization to avoid React Native renderer conflicts
40
41
  */
41
- i18n.use(initReactI18next).init({
42
- resources,
43
- lng: DEFAULT_LANGUAGE,
44
- fallbackLng: DEFAULT_LANGUAGE,
42
+ let isInitialized = false;
45
43
 
46
- interpolation: {
47
- escapeValue: false, // React already escapes values
48
- },
44
+ const initializeI18n = () => {
45
+ if (isInitialized) return;
49
46
 
50
- react: {
51
- useSuspense: false, // Disable suspense for React Native
52
- },
47
+ try {
48
+ /* eslint-disable-next-line no-console */
49
+ if (__DEV__) console.log('[i18n] Initializing i18next...');
50
+
51
+ // Check if initReactI18next is available
52
+ if (!initReactI18next) {
53
+ throw new Error('initReactI18next is undefined');
54
+ }
55
+
56
+ /* eslint-disable-next-line no-console */
57
+ if (__DEV__) console.log('[i18n] initReactI18next found, initializing...');
58
+
59
+ i18n.use(initReactI18next).init({
60
+ resources,
61
+ lng: DEFAULT_LANGUAGE,
62
+ fallbackLng: DEFAULT_LANGUAGE,
63
+
64
+ interpolation: {
65
+ escapeValue: false, // React already escapes values
66
+ },
67
+
68
+ react: {
69
+ useSuspense: false, // Disable suspense for React Native
70
+ },
71
+
72
+ compatibilityJSON: 'v4', // Use i18next v4 JSON format
73
+ });
74
+
75
+ isInitialized = true;
76
+ /* eslint-disable-next-line no-console */
77
+ if (__DEV__) console.log('[i18n] i18next initialized successfully');
78
+ } catch (error) {
79
+ /* eslint-disable-next-line no-console */
80
+ if (__DEV__) console.error('[i18n] Initialization error:', error);
81
+ // Don't throw - allow app to continue without i18n
82
+ /* eslint-disable-next-line no-console */
83
+ if (__DEV__) console.warn('[i18n] Continuing without i18n initialization');
84
+ }
85
+ };
53
86
 
54
- compatibilityJSON: 'v4', // Use i18next v4 JSON format
55
- });
87
+ // Defer initialization until React is ready
88
+ // React Native doesn't have window, so we check for global
89
+ if (typeof global !== 'undefined') {
90
+ // Use setTimeout to defer initialization
91
+ setTimeout(() => {
92
+ initializeI18n();
93
+ }, 0);
94
+ } else {
95
+ // Fallback: initialize immediately
96
+ initializeI18n();
97
+ }
56
98
 
57
99
  export default i18n;