facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.05k stars 24.19k forks source link

React-native I18nManager.forceRTL doesn't applies changes in first app load #17867

Closed m0agh closed 6 years ago

m0agh commented 6 years ago

Is this a bug report?

Probably!

Environment

Environment: OS: Linux 4.4 Node: 7.10.1 Yarn: 1.0.1 npm: 4.2.0 Watchman: 4.7.0 Xcode: N/A Android Studio: Not Found

Packages: (wanted => installed) react: 16.2.0 => 16.2.0 react-native: 0.52.2 => 0.52.2

Target Platform: Android

Expected Behavior

I have an app that created by awesome React-native and my layout designed to be in RTL mode. I've set up an option for forcing the layout to be RTL.

Actual Behavior

But my option doesn't works in first app load after installing. This feature applies in second run I wrote this option in our index.js:

import React, { Component } from 'react';
import { I18nManager } from 'react-native';
import { Provider } from 'react-redux';

I18nManager.forceRTL(true);

class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <PersistGate loading={null} persistor={persistor}>
          <MainStack />
        </PersistGate>
      </Provider>
    );
  }
}

export default App;
m0agh commented 6 years ago

After a week finally i found a logicly way to solve this issue with using Redux & react-native-restart plugin. I'm also use a nice splash screen to user don't show a restarting progress for this purpose.

So let's dive into code:

Redux action:

export const GET_APP_LAYOUT_DIRECTION = 'GET_APP_LAYOUT_DIRECTION';
export const SET_APP_LAYOUT_DIRECTION = 'SET_APP_LAYOUT_DIRECTION';

export const getAppLayoutDirection = () => ({
  type: GET_APP_LAYOUT_DIRECTION,
});

export const setAppLayoutDirection = direction => ({
  type: SET_APP_LAYOUT_DIRECTION,
  direction
});

Redux Reducer:

import {
    GET_APP_LAYOUT_DIRECTION,
    SET_APP_LAYOUT_DIRECTION,
} from '../actions/app';

const initialState = {
    layout: 'ltr',
};

const reducer = (state = initialState, action) => {
    switch (action.type) {
      case GET_APP_LAYOUT_DIRECTION:
        return {
          ...state,
        };
      case SET_APP_LAYOUT_DIRECTION:
        return {
          ...state,
          layout: action.direction,
        };
      default:
        return state;
    }
};

export default reducer;

Home Screen:

import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import RNRestart from 'react-native-restart'; // Import package from node modules
import { getAppLayoutDirection, setAppLayoutDirection } from '../actions/app';

class Home extends PureComponent {
   constructor(props) {
     super(props);

     this.props.dispatch(getAppLayoutDirection());
     if(this.props.layout === 'ltr'){
       this.props.dispatch(setAppLayoutDirection('rtl'));
       RNRestart.Restart();
     }
  }

  componentDidMount() {
     if(this.props.layout && this.props.layout === 'rtl'){
        SplashScreen.hide();
     }
  }
} 

const mapStateToProps = (state) => {
  const { layout } = state.app;
  return {
    layout
  };
}

export default connect(mapStateToProps)(Home);
momobalon commented 6 years ago

works great!!! BTW layout can also be check by. if (!I18nManager.isRTL) { RNRestart.Restart(); }

coreform commented 6 years ago

In my case, react-native-restart is not an option because it yields a memory leak within RN itself (on Android after restarting, seemingly related to OKHTTP). The app can land in a terrible constant-restart-then-crash state (which can detriment an app's rating on Google Play). So beware of relying on programmatically restarting an app!

omidgharib commented 6 years ago

I have a same issue. Is there any solution to force app to RTL ?

itskevinsam commented 5 years ago

ping.. (has the same issue)

PS: As rn-core devs tend to close critical issues posted by users strategically after a particular period of inactivity in a ticket.

coreform commented 5 years ago

Warning about using react-native-restart for this (and in general): if any problem occurs during your restart process, the app can fall into crash-restart loop that may see your app get rated as poor quality on app stores. It often works, but it isn't a good solution to this LTR<>RTL problem.

matanelgabsi commented 5 years ago

Another workaround would be adding: I18nUtil.getInstance().allowRTL(this, false); to public void onCreate() { in your MainApplication.java file

HossamSamir commented 5 years ago

Also, don't forget to add import com.facebook.react.modules.i18nmanager.I18nUtil; at the top of your MainApplication.java

sm2017 commented 5 years ago

Another workaround would be adding: I18nUtil.getInstance().allowRTL(this, false); to public void onCreate() { in your MainApplication.java file

@matanelgabsi , @HossamSamir What about iOS?

assaf-malki commented 5 years ago

@sm2017 Add the following

#import <React/RCTI18nUtil.h>

and

  [[RCTI18nUtil sharedInstance] allowRTL:YES];
  [[RCTI18nUtil sharedInstance] forceRTL:YES];

inside didFinishLaunchingWithOptions