DEV Community

ömer koşar
ömer koşar

Posted on

Beyond Translation: Mastering RTL Layouts with i18next and Radix UI

Translating your app is easy. Localizing your User Experience is the real challenge.

When we talk about Internationalization (i18n), most developers think about JSON files and translation keys. But for millions of users speaking Arabic, Hebrew, or Persian, translation is only half the battle. The entire UI needs to "flip."

In this article, I’ll show you how to build a robust, production ready RTL (Right to Left) system using i18next, Tailwind CSS, and Radix UI.

1. The Source of Truth: Centralizing Language Data

Don’t just store language codes. Your language configuration should dictate the visual direction of your application. By adding a dir property to your supported languages, you create a single source of truth for your UI.

export const SUPPORTED_LANGUAGES = [
  { code: "en", label: "English (US)", flag: "🇺🇸", dir: "ltr" },
  { code: "tr", label: "Türkçe", flag: "🇹🇷", dir: "ltr" },
  { code: "ar", label: "العربية", flag: "🇸🇦", dir: "rtl" },
  { code: "he", label: "עברית", flag: "🇮🇱", dir: "rtl" },
] as const;
Enter fullscreen mode Exit fullscreen mode

2. Syncing i18next with the DOM

To make your CSS work globally, the browser needs to know the direction of the document. We can automate this by listening to i18next events. When the language changes, we update the dir attribute on the <html> element.

i18n.on('languageChanged', (lng) => {
  const currentLang = SUPPORTED_LANGUAGES.find(l => l.code === lng);
  const direction = currentLang?.dir || 'ltr';

  document.documentElement.dir = direction;
  document.documentElement.lang = lng;
});
Enter fullscreen mode Exit fullscreen mode

3. Tailwind CSS: The Power of Logical Properties

If you are still using left-0 or pl-4 (padding-left), you'll have a nightmare manually overriding styles for RTL. Modern Tailwind (and CSS) uses Logical Properties. These properties automatically adjust based on the text direction.

  • Instead of left-0 / right-0: Use start-0 and end-0.
  • Instead of pl-4 / pr-4: Use ps-4 (padding-start) and pe-4 (padding-end).
  • Instead of border-l: Use border-s.

By using start and end, your layout "just works" when the dir="rtl" attribute is applied. No extra classes needed.

4. The Secret Sauce: Radix UI DirectionProvider

Standard CSS flips your text, but complex UI components like Dropdowns, Popovers, and Sliders often calculate positions based on fixed coordinates.

If you use Radix UI, simply wrapping your app in the DirectionProvider ensures that all primitives behave correctly. A dropdown that opens to the right in English will intelligently open to the left in Arabic.

import * as Direction from "@radix-ui/react-direction";

function App() {
  const { i18n } = useTranslation();
  const currentDir = i18n.dir(); 

  return (
    <Direction.Provider dir="{currentDir}">
      <div dir={currentDir}>
         <YourAppContent/>
      </div>
    </Direction.Provider>
  );
}
Enter fullscreen mode Exit fullscreen mode

5. Real World Implementation & SEO

I implemented this exact architecture in my latest project, Barcode Generator. When dealing with global tools that handle asset creation and labeling, ensuring that the UI respects the user's local direction isn't just a feature, it's a necessity for professional workflows.

From an SEO perspective, this is vital. Search engines analyze your Semantics. Using the correct dir attribute helps screen readers and crawlers interpret your content order correctly, reducing bounce rates from international users who expect a native experience.

Conclusion

Building a truly global application means making every user feel at home. By shifting from fixed directions (left/right) to logical ones (start/end) and integrating directionality into your i18n workflow, you move beyond mere "translation" and into true "localization."

Are you handling RTL in your React projects? Have you made the switch to logical properties yet? Let’s discuss in the comments!

Top comments (0)