@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 +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/infrastructure/components/LanguageSwitcher.d.ts +12 -0
- package/lib/infrastructure/components/LanguageSwitcher.d.ts.map +1 -0
- package/lib/infrastructure/components/LanguageSwitcher.js +49 -0
- package/lib/infrastructure/components/LanguageSwitcher.js.map +1 -0
- package/lib/infrastructure/components/useLanguageNavigation.d.ts +6 -0
- package/lib/infrastructure/components/useLanguageNavigation.d.ts.map +1 -0
- package/lib/infrastructure/components/useLanguageNavigation.js +16 -0
- package/lib/infrastructure/components/useLanguageNavigation.js.map +1 -0
- package/lib/infrastructure/config/i18n.d.ts.map +1 -1
- package/lib/infrastructure/config/i18n.js +55 -12
- package/lib/infrastructure/config/i18n.js.map +1 -1
- package/package.json +8 -2
- package/src/index.ts +2 -0
- package/src/infrastructure/components/LanguageSwitcher.tsx +86 -0
- package/src/infrastructure/components/useLanguageNavigation.ts +20 -0
- package/src/infrastructure/config/i18n.ts +54 -12
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';
|
package/lib/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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;
|
|
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;
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
42
|
-
resources,
|
|
43
|
-
lng: DEFAULT_LANGUAGE,
|
|
44
|
-
fallbackLng: DEFAULT_LANGUAGE,
|
|
42
|
+
let isInitialized = false;
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
},
|
|
44
|
+
const initializeI18n = () => {
|
|
45
|
+
if (isInitialized) return;
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
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;
|