Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native, how to update view after language change

I want to support language change (manually by user). I'm using react-native-i18n for that. I found how to change the displayed language at run time but I didn't find how to update the current view.

My Code

enter image description here

Environment

Environment:

  • Node: 8.9.4
  • Yarn: 1.3.2
  • npm: 4.0.5

Expected Behavior

When I use I18n.locale ='en'; not in function.. just as it is, the text will be in English and when I use I18n.locale ='he'; the text will be in Hebrew. However I need to change the language at run time. So I want that when I click each button the language will change and will be displayed.

Actual Behavior

Nothing happened.. I assume I need to reload / re-render / update the view but I didn't find how to.

like image 508
Omri Attiya Avatar asked Mar 01 '18 17:03

Omri Attiya


2 Answers

You can try something like this

<View style={styles.container}>
    <Button onPress={this.setLocale()} title={strings('test.b1')}> 
</View>

public setLocale() {
    this.setState({stateOfLocale: 'en'});
    I18n.locale = stateOfLocale;
}
like image 174
Mertcan Diken Avatar answered Oct 13 '22 08:10

Mertcan Diken


On the page where I have the button or Select to change the language, nothing will happen unless the texts are dependant on the language.

On every string I can pass the locale as an optional parameter like this {I18n.t("email", { locale: language })} and this will cause a rerender immediately if it changes.

No restart or refresh needed.

In the example below, I am using a select to modify the language in the state. The text field is dependant on it because of the optional locale parameter and will immediately re-render.

To persist the changes, I've implemented a Save button that will save the locale to AsyncStorage and call a changeLanguage function defined in a separate i18n.js file

import React, { useState } from "react";
import { View, Text, Button } from "react-native";
import I18n, { changeLanguage } from "../i18n/i18n";
import RNPickerSelect as Select from 'react-native-picker-select';
import AsyncStorage from '@react-native-async-storage/async-storage';

function ProfileScreen() {
  const locale = I18n.currentLocale();
  const [language, setLanguage] = useState(locale);

  const saveProfile = async () => {
    if (locale !== language) {
      AsyncStorage.setItem("language", language);
      changeLanguage(language);
    }
  }
  
  return (
  <View>
    <Text>{I18n.t("email", { locale: language })}</Text>
    <Select 
      value={language}
      onValueChange={(value) => setLanguage(value)}
      placeholder={I18n.t("selectAppLanguage")}
      items={[
        { label: I18n.t("English", { locale: language }), value: "en" },
        { label: I18n.t("Finnish", { locale: language }), value: "fi" },
        { label: I18n.t("Swedish", { locale: language }), value: "se" },
      ]}
    />
    <Button
      title={I18n.t("save", { locale: language })}
      onPress={saveProfile} 
    />    
  </View>
  );
}
export default ProfileScreen;

here is my i18n.js file. I am using react-native-localize as react-native-i18n is not maintained anymore and creates problems on Android once released. Changing the language is as simple as I18n.locale = lang

//i18n/i18n.js
import I18n from "i18n-js";
import * as RNLocalize from "react-native-localize";
import en from './languages/en';
import fi from './languages/fi';
import se from './languages/se';

const locales = RNLocalize.getLocales();

if (Array.isArray(locales)) {
  I18n.locale = locales[0].languageCode;
}

export const changeLanguage = lang => {
  if (lang) {
    I18n.locale = lang;
  } else if (Array.isArray(locales)) {
    I18n.locale = locales[0].languageCode;
  }
}

I18n.fallbacks = true;

I18n.translations = {
  en,
  fi,
  se,
};

export default I18n;

One last thing, in App.js, at app start, I am retrieving the language from local storage inside useEffect and overriding the device's language. So language is persisted.

//App.js
import React, { useEffect } from "react";
import I18n, { changeLanguage } from "./src/i18n/i18n";
import AsyncStorage from '@react-native-async-storage/async-storage';

function App() {
  useEffect(() => {
    const setLanguage = async () => {
      const language = await AsyncStorage.getItem("language");
      changeLanguage(language)
    }
    setLanguage()
  }, [])
  return ( // ...navigation, etc.
  );
}
export default <App />
like image 45
Raphael Pinel Avatar answered Oct 13 '22 07:10

Raphael Pinel