How to make react native app save the selected language when i restart the app

6.7k Views Asked by At

I want my app contain a setting screen so that i can change the language from the picker. I want language change is reflected on the whole app and i want the app to remember last selected language. Given below my index.js that import my key value pair language for en, am, or, tg,

index.js

import * as RNLocalize from 'react-native-localize';
import I18n from 'i18n-js';
import memoize from 'lodash.memoize'; 

import en from './en';
import am from './am';
import or from './or';
import tg from './tg';

const locales = RNLocalize.getLocales();
if (Array.isArray(locales)) {
  I18n.locale = locales[0].languageTag;
}

I18n.translations = {
  default: en,
  'en-US': en,
  en,
  am,
  or,
  tg,

};

I18n.fallbacks = true;
export default I18n;

I want to change language of the app from my SettingScreen. where i prepared a picker to choose language from. given below my setting screen code.

SettingScreen.js

import I18n from './../i18n/locales';

const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;

const listLanguage = [
  {key:'en', label:'En'}, {key:'am', label:'Am'} ,{key:'or', label: 'OR'}, {key:'tg', label:'TG'},] 

export default class SettingsScreen extends React.Component {
  constructor(props) {
    super(props);
    this.state = { visible: true ,
                  languageSelected: 'en'
    };
  }

  backToMain() {
    this.props.navigation.navigate('LocationTrackingScreen', {});
  }

  handleBackPress = () => {
    this.props.navigation.navigate('LocationTrackingScreen', {});
    return true;
  };

  hideSpinner() {
    this.setState({ visible: false });
  }

  componentDidMount() {
    BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
  }

  componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
  }

  onChangeLanguage(languageSelected){
    this.setState({
      languageSelected
    })
       I18n.locale = languageSelected 
  }

  render() {
    const {languageSelected} = this.state

    return (
      <SafeAreaView style={styles.container}>

      <View style={styles.containerDropdown}>
              <DropdownLanguage language={languageSelected} onChangeLanguage={this.onChangeLanguage.bind(this)}></DropdownLanguage>

      </View>
    </SafeAreaView>
    );
  }
}
class DropdownLanguage extends React.Component {
  constructor(props) {
    super(props)  
  }

  render() {
    return (
<View style={styles.dropdown}>
              <Picker
                mode="dropdown"
                iosHeader={''} 
                style={{ width: width,height:70,}}
                selectedValue={this.props.language}
                onValueChange={this.props.onChangeLanguage.bind(this)}
              >
                {listLanguage.map((languageItem, i) => {
                    return <Picker.Item key={i} value={languageItem.key} label= {languageItem.label} />
                })}
              </Picker>

            </View>
)
  }
}
2

There are 2 best solutions below

3
On

just make a file named TranslationManager.js and paste the following code in it

import * as RNLocalize from 'react-native-localize';
import i18n from 'i18n-js';
import memoize from 'lodash.memoize';
import {I18nManager, AsyncStorage} from 'react-native';

const translationGetters = {
  // lazy requires (metro bundler does not support symlinks)
  en: () => require('./Languages/en.json'),
  ar: () => require('./Languages/ar.json'),
};
export const translate = memoize((key, config) => i18n.t(key, config));
// export const translate = text => {
//   console.log(i18n.t(text));
// };

export const setI18nConfig = lang => {
  // fallback if no available language fits
  const fallback = {languageTag: 'en', isRTL: false};

  const {isRTL, languageTag} =
    RNLocalize.findBestAvailableLanguage(Object.keys(translationGetters)) ||
    fallback;

  // clear translation cache
  translate.cache.clear();
  // update layout directio
  // set i18n-js config
  I18nManager.forceRTL(false);
  i18n.translations = {['en']: translationGetters.en()};
  i18n.locale = 'en';

  if (lang) {
    i18n.translations = {[lang]: translationGetters[lang]()};
    i18n.locale = lang;
  } else {
    i18n.translations = {['en']: translationGetters.en()};
    i18n.locale = 'en';
  }
};

export const changeLanguage = async lang => {
  setI18nConfig(lang);
  AsyncStorage.setItem('language', lang);
};

export const isRTL = () => {
  return translate('lang') === 'ar' ? true : false;
};

No you have a separate class to change the language of the application. Just import this changeLanguage function where ever you want and change the language like this:

import {changeLanguage} from '../../Translations/TranslationManager';
let language = await AsyncStorage.getItem('language');
changeLanguage(language);

You can show your translated text this way:

import {translate} from '../../Translations/TranslationManager';
<Text>translate('ForumScreen.title')</Text>

Hope it will help you now and in future.

9
On

You can save the selected language in AsyncStorage and when the user opens the app you can check the last selected language from AsyncStorage and set it as the app language. This is an example how I do in my projects:

On laguage change set the language in AsyncStorage like this

    export const changeLanguage = async lang => {
         setI18nConfig(lang);
         AsyncStorage.setItem('language', lang);
     };

And when the user reopens the app just get the language on first screen and set it as the app language like this

let language = await AsyncStorage.getItem('language');
changeLanguage(language);

I hope this will help you