ForceRTL on iOS isn't working in React Native App

51 Views Asked by At

Android is responding well to direction change, however iOS isn't switching RTL correctly, iOS keep restarting and when I checked the state of isRTL is doesn't change

 useEffect(() => {
    initializingSet(true);
    const languageSetter = async () => {
      const storageLang = await AsyncStorage.getItem("appLang");
      const systemLanguage = getLocales()[0].languageCode;
      const { isRTL } = I18nManager;
      console.log(
        storageLang,
        storageLang,
        appLang,
        I18nManager.isRTL,
        "<<=Lang"
      );
      if (appLang) {
        changeLanguage(appLang);
        if (appLang !== storageLang) {
          AsyncStorage.setItem("appLang", appLang);
        }
        if ((appLang === "en" && isRTL) || (appLang !== "en" && !isRTL)) {
          I18nManager.allowRTL(!isRTL);
          I18nManager.forceRTL(!isRTL); // FIXNOW: iOS not switching to RTL
          RNRestart.restart();
        }
        initializingSet(false);
      } else {
        if (storageLang) {
          appLangSet(storageLang as AppLanguagesType);
        } else {
          if (systemLanguage) {
            AsyncStorage.setItem("appLang", systemLanguage).finally(() =>
              appLangSet(systemLanguage as AppLanguagesType)
            );
          } else {
            appLangSet("en");
          }
        }
      }
    };

    languageSetter();
  }, [appLang]);

my app.json has the supportsRTL

   "extra": {
      "supportsRTL": true,
           }

The same app run on Android just fine! Any thoughts?

3

There are 3 best solutions below

0
Wisam Jbori On BEST ANSWER

After alot of search I found this issue https://github.com/expo/expo/issues/26532

removing expo-localization fixed it, now I am using native modules to detect language

const systemLanguage = (
        (Platform.OS === "ios"
          ? NativeModules.SettingsManager.settings.AppleLocale ||
            NativeModules.SettingsManager.settings.AppleLanguages[0] //iOS 13
          : NativeModules.I18nManager.localeIdentifier) as string | undefined
      )?.substring(0, 2) as AppLanguagesType | undefined;
2
Jonas Beck On

I recommend you to add it in AppDelegate.mm on iOS project.

#import <React/RCTI18nUtil.h>
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
 [[RCTI18nUtil sharedInstance] allowRTL:YES];
...
}
1
Aqeel Ahmad On

I think you are missing i18n in this line: changeLanguage(appLang)

Replace it something like this: i18n.changeLanguage('ar')

Example My Language Switching Tabs:

import React from 'react';
import {Text, View, Pressable, I18nManager} from 'react-native';
import {useDispatch, useSelector} from 'react-redux';
import {useTranslation} from 'react-i18next';
import {useInjectReducer} from 'redux-injectors';
import RNRestart from 'react-native-restart';

import {GlobalSelector} from '../../store/selector';
import globalReducer, {setLanguage} from '../../store/global';
import {SaveLanguage} from '../../utils/languageStorage';
import LanguageTabStyle from './style';
import AppColor from '../../constants/Colors';

const LanguageTabs = ({containerStyle}) => {
  const {t, i18n} = useTranslation();
  const {BLACK} = AppColor();

  useInjectReducer({key: 'global', reducer: globalReducer});

  const dispatch = useDispatch();
  const {language} = useSelector(GlobalSelector);
  const styles = LanguageTabStyle();

  return (
    <View style={[styles.mainContainer, {...containerStyle}]}>
      <Pressable
        onPress={async () => {
          i18n.changeLanguage('en');
          dispatch(setLanguage('English'));
          if (I18nManager.isRTL) {
            await I18nManager.forceRTL(false);
            await SaveLanguage('English');
            RNRestart.Restart();
          }
        }}
        style={
          language === 'English' ? styles.activeButton : styles.inActiveButton
        }>
        <Text style={[styles.text, {color: BLACK}]}>{t('English')}</Text>
      </Pressable>
      <Pressable
        onPress={async () => {
          i18n.changeLanguage('ar');
          dispatch(setLanguage('Arabic'));
          await SaveLanguage('Arabic');
          if (!I18nManager.isRTL) {
            await I18nManager.forceRTL(true);
            await SaveLanguage('Arabic');
            RNRestart.Restart();
          }
        }}
        style={
          language === 'Arabic' ? styles.activeButton : styles.inActiveButton
        }>
        <Text style={[styles.text, {color: BLACK}]}>{t('Arabic')}</Text>
      </Pressable>
    </View>
  );
};

export default LanguageTabs;

Hopefully it will help you.