Bilingual Next.js: Lessons from Shipping Persian and RTL
Niloofar AhmadiFrontend Engineer
Real Persian support is much more than dir="rtl". This note distills what we've learned across several bilingual projects.
Rule one: no strings in components
Every piece of text — including accessibility labels and error messages — must come from the translation catalog. We use next-intl, and a CI script fails the build when a hardcoded string shows up in JSX.
Rule two: CSS logical properties
Use margin-inline-start instead of margin-left; inset-inline-start instead of left. Layouts then work in both directions with zero conditionals. Directional icons (arrows) are the only exception — they flip with rtl:rotate-180.
Rule three: native numbers and dates
The Persian calendar via Intl.DateTimeFormat('fa-IR-u-ca-persian') and Persian digits via Intl.NumberFormat('fa-IR') are available natively — no extra library needed.
The result? A site that doesn't feel translated to Persian speakers — it feels Persian-first.