Adding RTL & Arabic Support to React Native Apps Without Tears

By Rafat Saqqa · 6 min read

A practical pattern for shipping Arabic alongside English in a React Native app what I18nManager actually does, where it bites, and how to test it.

Adding right-to-left and Arabic support to a React Native app is one of those tasks that sounds easy on paper and then humiliates you for two weeks. This is the pattern we landed on after shipping it for real.

What I18nManager actually does

I18nManager.forceRTL(true) flips the entire layout direction at the native level. This affects:

  • flexDirection: 'row' becomes effectively row-reverse.
  • marginLeft becomes marginRight and vice versa (unless you explicitly use marginStart/marginEnd).
  • TextInputs align right.
  • ScrollView indicators flip.

What it does NOT do:

  • Translate any text. You still need an i18n library for that.
  • Re-render existing components instantly. The flag is read at native layout time, so a full app reload is required for the flip to fully apply.
  • Flip absolute-positioned elements. left: 16 is still on the screen-left side. Use start: 16 for direction-aware positioning.

Pattern 1: hand-rolled i18n is fine for small apps

For apps under 1000 strings, you don't need react-i18next or i18n-js. A useT hook reading from a flat dictionary object is enough:

import { en } from './en';
import { ar } from './ar';

export function useT() {
  const lang = useAppSelector((s) => s.settings.language);
  const t = useCallback(
    (key: string, params?: Record<string, string | number>) => {
      const dict = lang === 'ar' ? ar : en;
      const resolved = key.split('.').reduce((acc, k) => acc?.[k], dict);
      if (typeof resolved !== 'string') return key;
      return interpolate(resolved, params);
    },
    [lang]
  );
  return { t, lang };
}

This is 30 lines, has no dependencies, and supports interpolation. You only outgrow it when you need plural rules, gender, or context-aware translations.

Pattern 2: prompt for restart on first RTL flip

Because I18nManager.forceRTL doesn't apply until the JS bundle reloads, surface this honestly:

const willFlipRTL = (next === 'ar') !== I18nManager.isRTL;
if (willFlipRTL) {
  Alert.alert(
    'Restart required',
    'Switching language requires reloading the app for full effect.',
    [{ text: 'Got it', onPress: () => dispatch(setLanguage(next)) }]
  );
}

In Expo, the bundler picks up the change automatically. In a production build, the user must close and reopen the app there's no graceful way around this. Don't pretend otherwise.

Pattern 3: use logical properties everywhere

Stop writing marginLeft and marginRight. Write marginStart and marginEnd. They mean the same thing in LTR languages and automatically flip in RTL. This single rule eliminates 80% of layout bugs when you flip the direction.

For padding, paddingStart/paddingEnd work identically.

Pattern 4: don't over-translate mock content

In a template, leave restaurant names and menu items in English even when the language flips to Arabic. The buyer of the template is going to replace this content with their own anyway, and Arabic restaurant names that don't match real menu items in Arabic are uncanny.

What to translate: UI labels, buttons, headers, placeholders, errors, time/distance formats. What not to translate: mock data the buyer will overwrite.

Pattern 5: test with the system language

Build a development version, set your phone's system language to Arabic, and open the app. Look specifically at:

  • Are icons that should "lead" still on the leading edge? (Back arrows should point right in RTL.)
  • Are numerical values still readable? (Phone numbers, prices, times these stay LTR even in RTL contexts. Use writingDirection: 'ltr' on those Text nodes.)
  • Do animations still feel right? (Swipe gestures, slide-in transitions verify the directions.)

Final note: Arabic typography is its own thing

Default system fonts on iOS handle Arabic beautifully. On Android, the default font (Roboto) covers Arabic but the kerning is loose. Consider bundling a proper Arabic typeface if you're shipping to a primarily Arabic-speaking market. expo-font makes this a one-liner.

The full RTL story is more nuanced than this biRTL (mixed direction) text input, complex script segmentation, BiDi algorithm edge cases but for 95% of apps, the patterns above are enough to ship.