Adding RTL support to an existing React Native app in 2020

Parsa Nasirimehr
4 min readMar 26, 2020

In the wake of new cross-platform frameworks like React native and flutter, there has been a surge of demands for apps written using these technologies. Whether a simple Shop app for a customer to connect their small online business to or Microsoft’s own Skype messenger, these apps can make development for multiple platforms much, much easier. However, as many can attest, not everything is rosy.

Recently, i was given a task to add a new language system to our current React-Native app. Some of which, like Arabic, were RTL. Having never done such a thing, i began searching the internet for solutions to this problem, only to realize that the most recent piece of information i could find in React-Native’s own website was this article from 2016!

The rest of the internet was not much help either. It seems that for whatever reason, everyone is either using third party libraries like react-native-i18n (which has been deprecated) or react-native-rtl-layout. The few very helpful articles i could find (like this article from Nir levy) while helpful, did not explain everything.

So, about a month in, and having figured out most of the issues one could come across, i have decided to share whatever little knowledge i have gathered here in hopes that it ends up helping a few developers along the way. So, without further ado, let’s get started.

Setting up the languages

It is best for you to choose how to generate and keep the translations for every text in your app. For this part, my work was already a lot easier than most.

Every single one of our English and Spanish texts were kept inside their own JavaScript object and accessed via a simple component which, based on which language we had chosen, would select were to read the data from.

I later modified this system and converted the English version into a JSON object and gave it to our translation tool as a template so that all future additions to the file would create similar translations for other languages.

Flipping the UI

Now this, this is the hard part. Not because the code is difficult or that data about it can not be found (far from it), but because i needed to put together parts of what others had done to get what i wanted. So lets go through this step by step:

  1. The React Native team has implemented an object called I18nManager into React Native’s library.
  2. This object has a couple of good methods and properties: isRTL, forceRTL(bool), allowRTL(bool)
  3. Using I18nManager.forceRTL(true), the Core of react native will switch start from left to right and end from right to left. Using I18nManager.forceRTL(false) will return it back to it’s original setting.
  4. Once you do this however, the app will NOT flip the UI. As the UI has already rendered. What you need to do instead is reload the app. You can use libraries like React Native Restart to do this while the app is running in production mode.
  5. Once the app reloads, it will be rendered from left to right.

For example, this is my method for changing language:

import RNRestart from "react-native-restart";
...
import {I18nManager} from "react-native";

export const languageRestart = async () => {
//changing language based on what was chosen
if (//selected language is LTR) {
if (I18nManager.isRTL) {
await I18nManager.forceRTL(false);
}
} else {
if (!I18nManager.isRTL) {
await I18nManager.forceRTL(true);
}
}
RNRestart.Restart();
};

Simple, Right? So what was the problem?

Weeeeell, not so fast. As anyone who is using React Navigation’s drawer can attest, that just BROKE the app.

You see there are a couple of small but important points here that took up my actual time:

a) React Navigation has a separate prop in createDrawerNavigation called drawerPosition. Once the app starts to load, YOU CAN NOT CHANGE THIS PROPERTY. So the best way to make sure the position is correct is to use I18nManager.isRTL:

const drawer = createDrawerNavigation({
...
},
{
....
drawerPosition : I18nManager.isRTL ? 'right' : 'left'
});

which brings us to the second point

b) If you switch RTL, I18nManager will REMEMBER what you had chosen. So you do NOT need to call I18nManager.forceRTL() at the start of your app every time. Just when you want to switch the language.

c) There is a weird issue on iOS which i am gonna quote the original blog from react native here:

In iOS, the default text alignment depends on the active language bundle, they are consistently on one side. In Android, the default text alignment depends on the language of the text content, i.e. English will be left-aligned and Arabic will be right-aligned.

What this means is that in order for your iOS version to start writing text from left to right, you need to add a

writingDirection: "rtl" 

for when the app is being rendered as RTL just for iOS (this style will have no effect on android as it is already writing it in the correct format).

Final thoughts

This has been a fun journey for me. Although things did turn bleak at times, the end result was more than worth it. The process did show however that development on RTL has been minimal at best.

The fact that for whatever reason i could not find any reference to I18nManager within React Native’s own document or that React Navigation has RTL as a limitation within their own document shows that these features simply do not have enough mainstream appeal to be addressed properly.

If you guys have a problem, comment below this article. I will try my best to address them.

Happy Coding

--

--