I am using expo, react-native, redux, react-navigation, and react-intl. Expo has this async Localization.getCurrentLocaleAsync()
function to retrieve the locale asynchronously. I encountered problem propagating changes of locale and messages down to child components.
For example, if I set initial locale to "es" in "Root.js", when the Localization.getCurrentLocaleAsync()
kick in and set the locale to "en", the updated messages was not reflected in the child component "Login.js". As such, the simulator throws a console.error: Missing message: "Login.login" for locale: "es", using default message as fallback
while I updated the locale and message in the root.js
state Here's my code:
root.js
import React from 'react';
import { Provider } from 'react-redux';
import { StyleSheet, Text, View, Alert } from 'react-native';
import { DangerZone } from 'expo';
import { IntlProvider, addLocaleData, injectIntl } from 'react-intl';
import { createBottomTabNavigator, createSwitchNavigator } from 'react-navigation';
import { PersistGate } from 'redux-persist/integration/react';
import AuthLoadingPage from './containers/authLoading';
import LoginPage from './containers/login';
import SignupPage from './containers/signup';
import HomePage from './containers/home';
import NotFoundPage from './containers/notFound';
import configureStore from './configureStore';
import en from 'react-intl/locale-data/en';
import es from 'react-intl/locale-data/es';
import localeData from './build/data.json';
addLocaleData([...en, ...es]);
const { Localization } = DangerZone;
const { persistor, store } = configureStore();
const AuthTab = createBottomTabNavigator({
login: { screen: LoginPage },
signup: { screen: SignupPage },
},{
navigationOptions: {
tabBarVisible: false,
},
lazyLoad: true,
});
const MainNavigator = createSwitchNavigator({
authLoading: AuthLoadingPage,
main: { screen: HomePage},
auth: AuthTab,
},{
initialRouteName: 'authLoading',
});
class Root extends React.Component {
constructor(p) {
super(p);
this.state = {
currentLocale: 'es',
messages: localeData['es'],
};
}
componentDidMount() {
Localization.getCurrentLocaleAsync()
.then(currentLocale => {
console.log("currentLocale is >>>", currentLocale);
this.setState({
currentLocale,
messages: localeData[currentLocale],
});
});
}
render() {
console.log("this.state.message???", this.state.messages);
return (
<IntlProvider
locale={this.state.currentLocale}
key={this.state.currentLocale}
messages={this.state.messages}
textComponent={Text}
>
<Provider store={store}>
<PersistGate
loading={<NotFoundPage />}
onBeforeLift={() => {}}
persistor={persistor}
>
<MainNavigator />
</PersistGate>
</Provider>
</IntlProvider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default Root;
and "containers/Login.js":
import React, { Component } from 'react';
import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import {
View,
Text,
TextInput,
Image,
Dimensions,
KeyboardAvoidingView,
StyleSheet,
Button,
TouchableOpacity
} from 'react-native';
import { FormLabel, FormInput } from 'react-native-elements';
import { authenticate } from '../modules/auth/actions';
const SCREEN_WIDTH = Dimensions.get('window').width;
class LoginPage extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
}
handleSubmit(e) {
e.preventDefault();
const { email, password } = this.state;
const { navigation } = this.props;
this.props.dispatch(authenticate(email, password))
.then(() => {
navigation.navigate('main');
})
}
gotoSignup(e) {
e.preventDefault();
const { navigation } = this.props;
navigation.navigate('signup');
}
render() {
const { isAuthenticated, navigation } = this.props;
return (
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.loginLogo}>
<FormattedMessage
id={ 'Login.login' }
defaultMessage={ 'Welcome to login screen!' }
/>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
width: Dimensions.get('window').width,
},
loginLogo: {
flex:1,
},
loginForm: {
flex: 2,
},
loginFormContainer: {
flex: 1,
padding: 20,
},
input: {
height: 40,
backgroundColor: 'rgba(255,255,255, 0.8)',
paddingLeft: 10,
marginBottom: 15,
},
buttoncontainer: {
backgroundColor: '#23618C',
marginTop: 10,
paddingVertical: 15,
},
buttontext: {
textAlign: 'center',
color: '#fff',
fontWeight: 'bold',
},
});
function mapStateToProps(state) {
const { auth } = state;
const { loading, isAuthenticated } = auth;
return {
loading,
isAuthenticated
};
}
export default connect(mapStateToProps)(LoginPage);
you can also find the relavent code in github: root.js: https://github.com/7seven7lst/mobile-client-new/blob/master/root.js containers/Login.js: https://github.com/7seven7lst/mobile-client-new/blob/master/containers/login.js