I18n + react navigation question

Hi all, i find that this is an awesome community where people find time proactively to help others, unlike RNav’s github’s page where they tell you to switch to stackoverflow, which is actually right too, i mean the question has been probably asked too many times ( i did go through a few and couldn’t really find what’s wrong besides sending props this or that way), and they are being bombarded about zillions of questions, so anyone would do that. Okay well, let me get down to the question.

I’m setting locale in componentWillMount(), its doing it alright. I can get the right context of locale correctly and display the switched languages correctly as well within the component. Now, in the nav options when i pass title: I18n.t(‘greeting’), it would only load the EN version, not the locale that i’ve set?

now my conclusion is its doing that prior to component mounting, i mean the navigation is probably happening in some other context?

the primary question is if i can set locale prior to navigation mount? or rerender it somehow? i have a language toggle button, so i’d like to toggle languages and then rerender, the component works fine, the nav bar would only load ‘en’ version, so how do i go on about that.

here’s the code.

...some imports
import I18n from 'ex-react-native-i18n';
I18n.fallbacks = true
I18n.translations = {
  en: {
    greeting: 'Hi!'
    ar: {
	greeting: 'الرئيسية'


export default class SignupScreen extends Component {
	static navigationOptions = {
		title: I18n.t('greeting'),
		headerStyle: {
			paddingTop: Constants.statusBarHeight,
			height: 60 + Constants.statusBarHeight
	state = {
		arabic: false,
		fullname: null,

	async componentWillMount() {
		I18n.defaultLocale = "ar";
		I18n.locale = "ar";
	_onArabicButton = () => {
			arabic: !this.state.arabic 

	render() {
		return (
			<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
				<Image source={require('../assets/img/bg/bg.png')} style={styles.bg}>
					<View style={styles.container}>
						{Platform.OS === 'android' &&
									height: Constants.statusBarHeight,
									backgroundColor: '#050B7A'
						<KeyboardAvoidingView behavior="padding">
								placeholder="Full Name"
								onSubmitEditing={() => this._idInput.focus()}
								onChangeText={fullname => this.setState({ fullname })}


						<TouchableOpacity onPress={this._onNew}>
							<View style={styles.button}>
								<Text style={styles.buttonText}>
								{I18n.t('greeting')} Save <FontAwesome name="save" size={24} color="white" />
						<View style={styles.buttonRow}>
							<TouchableOpacity onPress={this._onHelpButton}>
								<View style={styles.buttonMark}>
									<Text style={styles.buttonText}> ? </Text>

							<TouchableOpacity onPress={this._onArabicButton}>
								<View style={styles.buttonArabic}>
									<Text style={styles.buttonText}>العربية</Text>
					{this.state.loading &&
						<View style={styles.loading}>
							<ActivityIndicator size="large" />

const styles = StyleSheet.create({
	...some style

can you put your code in a snack so its possible to play around with it and modify your example?

i resolved this by removing component lifecycle changes,
instead made it all toggle with a button.

unfortunately, i no longer have the older code since the issue was resolved as i’d have loved to understand what i was doing wrong.

1 Like

glad its resolved and working for you now at least.

Ok I am having the same problem, I changed my language on the emulator and on my tablet ant it does not work

import I18n from ‘ex-react-native-i18n’

export default class Home extends React.Component {

static navigationOptions = {
    title: 'Home'

async componentWillMount() {

render() {
    return (
        <View style={styles.LoginContainer}>
            <Button onPress={signInWithGoogleAsync.bind(this)}

    async function signInWithGoogleAsync() {
        try {
            const result = await Expo.Google.logInAsync({
                androidClientId: testAndroid,
                iosClientId: testIOS,
                androidStandaloneAppClientId: androidID,
                iosStandaloneAppClientId: iosId,
                webClientId: webID,
                scopes: ['profile', 'email'],

            if (result.type === 'success') {

                let details = {
                    'domainName': 'ispcloudservices.com',
                    'userEmail': result.user.email,
                    'langId': deviceLocale,
                    'userToken': result.accessToken


                let formBody = [];
                for (let property in details) {
                    let encodedKey = encodeURIComponent(property);
                    let encodedValue = encodeURIComponent(details[property]);
                    formBody.push(encodedKey + "=" + encodedValue);
                formBody = formBody.join("&");

                let postData = {
                    method: 'POST',
                    headers: {
                        'User-Agent': 'ToogleBoxMobile',
                        'referer': 'https://toogleboxmobile.com',
                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                    body: formBody

                fetch(url, postData)
                    .then((response) => response.json())
                    .then((responseJson) => {
                        this.props.navigation.navigate('Second', {responseJson})

            } else {
                return {cancelled: true};
        } catch (e) {
            return {error: true};


I18n.fallbacks = true;

I18n.translations = {
en: {
buttonTranslation: ‘Sing-in with google’
es: {
buttonTranslation: ‘Regístrese con Google’
pt: {
buttonTranslation: ‘Criar sua Conta do Google’