1

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>
)
  }
}
melaku
  • 89
  • 2
  • 11

2 Answers2

2

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

Ali Hayder
  • 315
  • 1
  • 9
  • @Oliver D here is the code on snack https://snack.expo.io/@melaku/reactnative---language-select – melaku May 08 '20 at 15:43
  • Thanks for your answer but i dont know how to integrate it on my code , can you please help me with this – melaku May 08 '20 at 15:45
  • @ https://stackoverflow.com/users/8799922/ali-hayder where do i need to write the code do i need to write on index.js or SettingScreen.js – melaku May 08 '20 at 15:48
  • 1
    @melaku you need to set language in AsyncStorage while you change the language on settings screen. And when you reopen the app, just get the language from AsyncStorage on index.js and change the language same way but this time using the language you have got from AsyncStorage. – Ali Hayder May 08 '20 at 16:00
  • AsyncStorage is react native's local storage which keeps the data even if you close or kill the application – Ali Hayder May 08 '20 at 16:01
  • when i try as yoyu said i got error message can not use keyword 'await ' outside an async function error – melaku May 08 '20 at 16:04
  • make your function async just like this "async yourFunction(){.....}" or if you are using arrow function then this way "yourFunction = async ()=>{......}" – Ali Hayder May 08 '20 at 16:07
  • I tried but it did not worked for me, still the app starts with the default language. may i need to delete onChangeLanguage(languageSelected){ this.setState({ languageSelected }) I18n.locale = languageSelected } – melaku May 08 '20 at 16:20
  • thanks. It is good to hear from you . I worked upon this tutorails https://medium.com/codespace69/reactnative-how-to-change-language-of-my-app-in-run-time-when-user-selects-the-language-2e75bd134119 – melaku May 08 '20 at 16:27
0

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.

Ali Hayder
  • 315
  • 1
  • 9
  • sorry still app starts with the default language – melaku May 08 '20 at 17:02
  • Can you share code that how you are changing the language on index.js? – Ali Hayder May 08 '20 at 17:07
  • ('import {changeLanguage} from './TranslationManager'; import{translate} from './TranslationManager' import en from './en'; import am from './am'; import or from './or'; import tg from './tg'; melalang = async () => { let language = await AsyncStorage.getItem('language'); changeLanguage(language); } const locales = RNLocalize.getLocales(); if (Array.isArray(locales)) { I18n.locale = locales[0].languageTag; } I18n.fallbacks = true; I18n.translations = { default: en, 'en-US': en, en, am, or, tg, sl, }; export default I18n;'?) – melaku May 08 '20 at 17:30