Reputation: 61
I am developing a multi-language App using i18n.js and expo-localization. The default language is the system default and users can select their preferred language. But after the language is selected, only those screens under StackActions.replace('MyDrawer') are refreseed and the language changed. Other screens still use the default langauge. I wonder if there are any ways to refresh all screens in React Navigation?
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import i18n from 'i18n-js';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { StackActions } from '@react-navigation/native';
const LanguagePicker = ({navigation, route}) => {
const [languageSelected, setLanguageSelected] = useState(null)
const handleSelectLanguage = (n) => {
setLanguageSelected(n)
AsyncStorage.setItem('storedLanguage', n)
navigation.dispatch(
StackActions.replace('MyDrawer'))
}
i18n.locale = languageSelected
console.log("i18n.locale in language picker", i18n.locale)
return(
<View style={styles.container}>
<TouchableOpacity onPress={() => {handleSelectLanguage('pt')}}>
<Text style={styles.text}>Português</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {handleSelectLanguage('en')}}>
<Text style={styles.text}>English</Text>
</TouchableOpacity>
</View>
)}
Upvotes: 1
Views: 2356
Reputation: 61
I eventually use Context to manage the global state of language.
In Context.js
import React, {useState, useEffect} from 'react'
import AsyncStorage from '@react-native-async-storage/async-storage';
import i18n from '../config/i18n';
const Context = React.createContext()
export const Provider =({children}) => {
const [language, setLanguage] = useState(i18n.locale)
// In the beginning of App, check if user has selected language before.
// If not, use system default language
useEffect(()=> {
AsyncStorage.getItem('storedLanguage').then(data => {
if (data === null) {
setLanguage(Localization.locale)
}
else {setLanguage(data)}
console.log('language inside useEffect', language)
}).catch((error) => console.log(error))
}, [])
const userChangeLanguage = async (language) => {
setLanguage(language)
await AsyncStorage.setItem('storedLanguage', language)
}
return (
<Context.Provider value={{data: language, userChangeLanguage}}>
{children}
</Context.Provider>)
}
export default Context
And then wrap the App.js inside the provider like so:
import React from 'react'
import Navigation from './scr/navigation/Navigation'
import { Provider } from './scr/context/Context'
const App = () => {
return (
<Navigation/>
)
}
export default () => {
return <Provider>
<App/>
</Provider>
}
In the LanguagePicker.js screen:
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import Context from '../context/Context';
import React, { useContext } from 'react';
import { StackActions } from '@react-navigation/native';
const LanguagePicker = ({navigation}) => {
const {userChangeLanguage} = useContext(Context)
const handleChangeLanguage = (language) => {
userChangeLanguage(language);
navigation.dispatch(StackActions.replace('MyDrawer'))
}
return(
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={()=>handleChangeLanguage('zh')}>
<Text style={styles.text}>繁體中文</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={() => handleChangeLanguage('zh-Hans')}>
<Text style={styles.text}>简体中文</Text>
</TouchableOpacity>
etc...
Lastly, in Navigation.js, get data (language) from Context and set i18n.locale = data
const Navigation = () => {
const {data} = useContext(Context)
i18n.locale= data;
Alternatively, could use expo updates. This is definitely an overkill to force the whole app to check for latest update just to refresh language. Once press a language, the app will restart. Not the smoothest UX, but not too bad. Considering it only takes one line of code so I will still count it as a quick and dirty solution.
const [languageSelected, setLanguageSelected] = useState(i18n.locale)
const handleSelectLanguage = (n) => {
setLanguageSelected(n)
AsyncStorage.setItem('storedLanguage', n)
Updates.reloadAsync()
}
i18n.locale = languageSelected
Upvotes: 3