Skip to main content
Tutorial

Building Bilingual Arabic/English Websites with Next.js and RTL Support

5 min read

How to build bilingual RTL websites with Next.js (and avoid the hair-pulling moments)

nextjsrtli18ntypescriptsaudi-frontend

Last year, I had to build a bilingual website for a client in Dubai who wanted both Arabic and English support with flawless RTL alignment. The deadline was tight, and the team had zero experience with RTL layouts. I remember staring at a chunk of CSS that looked fine in English but made the Arabic version look like a jumbled mess. That project became my crash course in handling bilingual, RTL-aware websites with Next.js—and I learned more about the quirks of browser text alignment than I ever expected to.

If you’ve ever tried to retrofit RTL support into a framework built primarily for LTR languages, you know the pain. Next.js itself does a decent job abstracting some complexity through next-i18next, but the real headaches start when your layout has to flip just right without breaking third-party components or animations. Let me walk you through how I got this working, with enough detail that you don’t have to repeat my mistakes.

Setting up i18n Basics in Next.js

The first step is always the internationalization config. For one project—an event booking platform that serves users in Saudi Arabia and Qatar—I chose next-i18next because it’s battle-tested. Setting up next.config.js with supported locales feels straightforward until you realize the ordering matters to Google’s SEO crawlers. We put Arabic (ar-SA) first because the client’s local users default to it, but I’ve seen enterprise clients do the reverse depending on business priorities.

Translation files live in /public/locales/ar-SA and /public/locales/en-US. The catch? Dynamic routes that rely on client-side locale switches need to avoid full page reloads. We got burned by this when a client’s marketing team wanted real-time language switching on their landing page analytics—they’d get two separate data sets otherwise.

Handling RTL Styling in React

CSS-in-JS works fine for small projects, but when I built the dashboard for Tawasul Limo (a luxury car booking platform here in Abu Dhabi), I ended up switching to styled-jsx with postcss-rtlcss for a cleaner workflow. The idea is to generate mirrored CSS for RTL languages instead of writing redundant classes by hand.

You might ask, why not use CSS logical properties like start and end instead of left or right? In theory, it’s the future-forward approach. In practice, third-party libraries (looking at you, Swiper) don’t always respect those, and debugging that afterhours is no fun. We eventually stuck to a mix of postcss-rtlcss for layout and inline logical props for edge cases.

The HTML `dir` Attribute Quirk

This one bit me twice: browser text alignment isn’t just about CSS direction. There’s no way your won’t affect how certain form elements render (yes, even in 2026). For one project, the client wanted dropdown menus to open to the left in Arabic mode. The team used a useEffect to toggle the dir attribute on document.documentElement based on the selected locale. Seems logical—except it caused hydration mismatches in Next.js’s App Router. We eventually fixed this by setting the dir in a custom Document component.

tsx
// _document.tsx
<HTML dir={locale === 'ar-SA' ? 'rtl' : 'ltr'}>

It works, but I still hate how brittle this feels. Changing directionality at the document level feels like touching the DOM directly—hacky but necessary.

Real-World RTL Gotchas

Animation is the sneaky villain here. On Greeny Corner (a plant care app for UAE iOS users), we had a slide-in component that played in reverse when switching to Arabic. Our solution? Wrap everything in a layout component that flips transform values conditionally. Not elegant, but it works:

jsx
const getAnimationStyles = (rtl: boolean) => {
  return { transition: rtl ? 'margin-right 0.3s' : 'margin-left 0.3s' }
}

The deeper issue? Browsers don’t auto-flip transform functions. We ended up using a separate CSS class for RTL animations, which felt like a compromise but saved time during testing.

SEO & URL Strategy for Bilingual Sites

The UAE market doesn’t tolerate half-baked SEO. Clients will ask why their Arabic content isn’t ranking despite perfect keyword placement—so I make sure every bilingual site has clear hreflang tags. For static pages, this means injecting language metadata in getStaticProps. For dynamically rendered pages (like real estate listings on Reach Home Properties), we pass language headers through middleware to generate the correct canonical URLs.

Subdomains (ar.yourdomain.com) work, but GCC users tend to expect subpaths like /ar/properties/dubai. The trick is configuring your server or CDN to handle redirects based on Accept-Language headers while letting users manually override without getting stuck in loops. I’ve seen redirect chains tank a site’s search visibility quickly—test early.

Why UAE Clients Care About This Stuff

If you’re building for Saudi or Qatari companies, realize that many of their users still default to mobile browsers with older JavaScript engines. RTL layout quirks often show up on Android WebView or iOS Safari even after passing Chrome/Firefox testing. One client in Jeddah noticed a text overflow issue only on Samsung keyboards—turns out Android’s keyboard rendering engine ignored our text-align values. We ended up writing a tiny patch for those cases.

A Few Things That Still Suck

Form labels in RTL. Seriously. I thought we’d moved beyond needing label htmlFor="someInput" to be mirrored, but some design systems slap inputs right next to their labels. You’ll find yourself adjusting flex-direction values constantly in login/register forms.

Also, input type="search" in Safari adds its own margin in RTL mode. You can’t style it cleanly. Our workaround? Replace it with a text input and add a manual search icon. Welcome to 2026’s browser compatibility hell.

Wrapping Up

Is building bilingual websites with Next.js and RTL support fun? No. Is it necessary for developers in the GCC? Hell yes. Clients here don’t tolerate flimsy language support, and neither should you. If you’re fighting with PostCSS RTL configurations or dealing with a third-party component that refuses to flip, remember: you’re not alone. I’ve been there, and I’m still fixing these issues two projects later.

If you’ve got a Next.js bilingual project in the pipeline, feel free to reach out. I’ve made enough mistakes to save you a few hours of frustration.

S

Sarah

Senior Full-Stack Developer & PMP-Certified Project Lead — Abu Dhabi, UAE

7+ years building web applications for UAE & GCC businesses. Specialising in Laravel, Next.js, and Arabic RTL development.

Work with Sarah