Published · 3 min read
Arabic is a layout problem, not a translation problem
Six RTL sites later, here is the short list of what actually breaks when you add Arabic to a Next.js app, and the fixes that held up in production.
Every bilingual site I've shipped for Saudi and Egyptian clients went through the same arc. The translation arrives, you flip dir="rtl", and the page is suddenly wrong in twenty small ways. None of them are about words. They're about layout, fonts, numbers, and URLs.
This is the checklist I now run before a client sees the Arabic version. It comes from Aevenda, HotSpot, CPS, Athenas, Midex, and Edge, all Next.js App Router sites with a [locale] segment.
1. Stop using left and right in CSS
Physical properties (margin-left, padding-right, left: 0, text-align: left) don't flip. Logical ones do. In Tailwind that means:
| Physical | Logical |
|---|---|
ml-4 / mr-4 | ms-4 / me-4 |
pl-4 / pr-4 | ps-4 / pe-4 |
left-0 / right-0 | start-0 / end-0 |
text-left | text-start |
rounded-l-lg | rounded-s-lg |
Grep for the physical ones before you ship:
grep -rnoE '\b(ml|mr|pl|pr|left|right)-[a-z0-9.\[\]/-]+|\btext-(left|right)\b' srcAnything left over should be inside an element you've deliberately kept left-to-right.
2. Some things must stay LTR
A diagram, a code block, a phone number, an email address, a URL. Wrap each one:
<span dir="ltr" className="inline-block">+20 100 700 4828</span>The inline-block matters. Without it the bidi algorithm will still reorder punctuation around the number in some browsers.
3. The font you have doesn't have the glyphs
Geist, Inter, and Space Grotesk ship no Arabic. The browser falls back to whatever the OS has, which is usually fine on iOS and ugly on Windows. Pick an Arabic face on purpose and load it only on the Arabic routes:
// app/[locale]/layout.tsx
import { Cairo } from "next/font/google";
const arabic = Cairo({ variable: "--font-arabic", subsets: ["arabic", "latin"], weight: ["400", "500", "700"] });
<html lang={locale} dir="rtl" className={locale === "ar" ? `${arabic.variable} font-ar` : ""}>Then swap the stack in CSS instead of touching every component:
html.font-ar {
--font-display: var(--font-arabic), system-ui, sans-serif;
--font-sans: var(--font-arabic), system-ui, sans-serif;
}
html.font-ar .display { letter-spacing: 0; line-height: 1.35; }Two details people miss: Latin display faces use negative tracking, which makes Arabic unreadable, and Arabic needs more line height because of the marks above and below the baseline.
4. Numbers and dates
Intl will give you Arabic-Indic digits (٣ instead of 3) for ar-EG. Clients in Saudi Arabia and Egypt almost always prefer Western digits on the web. Force them with a locale extension:
new Intl.DateTimeFormat("ar-EG-u-nu-latn", { hour: "2-digit", minute: "2-digit" });Use the same trick for Intl.NumberFormat and Intl.RelativeTimeFormat.
5. Mirror the icons that mean direction
Arrows that mean "next" or "open" should flip. Icons that depict a real object (a phone, a play button, a logo) should not. In Tailwind, rtl:rotate-180 on the arrow is enough.
6. URLs are part of the layout
Keep slugs translated and ASCII-safe. /ar/services/led-screens ranks, /ar/خدمات/شاشات-led is a support ticket waiting to happen in half the tools you'll integrate with. Put the Arabic keyword in the title and the H1, not in the path.
For SEO, every page needs hreflang links for all languages plus x-default, the same URLs in the sitemap, and og:locale set to ar_EG or ar_SA. Next's metadata API does this cleanly with alternates.languages.
7. Test on a real phone keyboard
The last bug is always in a form. A visitor types their name in Arabic, a pattern attribute written for Latin rejects it, and you never hear from them. Validate on the server with Zod, keep client-side constraints to required and type="email", and read the error messages aloud in Arabic once.
What I'd do again
Logical properties from day one. A dedicated Arabic font loaded per route. Western digits unless the client asks. And one native speaker reading the final copy before launch, because a layout can be perfect and the sentence still wrong.