Ingegneria
Three languages, one codebase, and one that reads right to left
Translating the words is the easy part. The URL builder, the logical CSS, the icons that must not mirror, and the variable names hiding a direction.
Di Injamam Ahmed6 min di lettura
This site is in English, Italian and Arabic. The Arabic version is not a translation bolted onto the side — it reads right to left, and every layout decision on the site had to survive that.
We built it this way because the agency has an office in Italy and sells into Arabic-speaking markets, so it was going to be our own problem before it was a client's. This post is what actually turned out to be hard, which was mostly not the translating.
One place that builds a URL
The first decision, and the one that prevents the most bugs, is that exactly one function in the codebase knows how to build a URL.
English lives at the root. Italian is under /it/, Arabic under /ar/. Every link on the site — navigation, case studies, the footer, the sitemap, hreflang tags, the redirects — goes through the same builder. Nothing anywhere else concatenates a locale and a path.
This is unglamorous and it is the whole game. The moment two places build URLs, they disagree, and the disagreement shows up as a 404 in the language you test least.
We know because ours disagreed anyway. A helper that stripped the locale prefix returned the path unchanged for English, which was correct in every case except the one where the framework handed it a path that still carried /en. The result was links like /it/en/work/ — valid-looking, entirely broken, and only on one locale. It was a five-line fix and it would never have existed if that helper had not been a second opinion about URL shape.
Every URL ends in a slash, except when it must not
The old site was indexed with trailing slashes, so the new one keeps them. That is a one-line configuration setting and then a subtle bug.
A fragment is not a path segment. /#services must not become /#services/, which points at no element and silently breaks the link — no error, no 404, just an anchor that quietly stops working. The same is true of query strings.
So the URL builder splits the path at the first # or ?, normalises only the part before it, and reattaches the rest untouched. Three lines, and it is the kind of thing you find by clicking your own navigation rather than by running tests.
Right to left is a direction, not a stylesheet
The common way to add Arabic is a second stylesheet that flips things. It works until someone changes the first stylesheet.
The better approach is to write CSS that has no left and right in it at all. Modern CSS has logical properties: inset-inline-end instead of right, padding-inline-start instead of padding-left, border-start-start-radius instead of border-top-left-radius. Set dir="rtl" on the document and the entire layout mirrors, from one attribute, with no second stylesheet to maintain.
The assistant panel on this site is a good test case. In English it sits bottom-right with a tail on the top-left of each bot message. In Arabic it is bottom-left with the tail on the top-right. There is no Arabic-specific CSS for any of that — it falls out of having written the original rules in logical properties.
The things that must not mirror
Direction mirroring is aggressive, and some of what it catches should not be flipped.
Icons split into two groups, and the distinction is worth stating clearly. An icon that indicates direction of travel must mirror: a send arrow points the way the text flows, so in Arabic it points left. An icon that is a thing must not: a logo, a brand mark, a play button, a clock. Mirrored, they become someone else's logo or a clock running backwards.
Numbers and Latin brand names inside Arabic text need care too. +8801931675044 should not be reordered by the bidirectional algorithm because it happens to sit at the end of an Arabic sentence. That is what <bdi> is for, and forgetting it produces a phone number that is subtly, unreproducibly wrong depending on the surrounding words.
The trap in your variable names
Our blog has previous-and-next post links. Or it did, until Arabic.
"Previous" and "next" are direction words disguised as time words. In a right-to-left layout the previous post is on the right, and any label, arrow or CSS that assumes otherwise is now lying to the reader.
We renamed them to newer and older. Those are true in every language, because they describe time rather than screen position, and once the names are honest the layout can mirror freely without the labels becoming wrong.
This is a general lesson and it costs nothing to apply early: if a variable name encodes a direction, check whether it actually means a direction. Most of the time it means order, and order is not direction.
Fonts, and not making two languages pay for each other
Arabic needs a typeface with proper Arabic support. Ours is Cairo, self-hosted.
If you load it globally, every English and Italian visitor downloads an Arabic font they will never render a glyph from. So it is declared but not preloaded, and only referenced under [dir="rtl"]. The Latin font is preloaded because most visitors need it immediately.
The general rule: a multilingual site should never make one language's visitors pay for another language's assets. It is easy to get wrong, invisible in development on a fast connection, and one of the larger performance wins available on a site like this.
What search engines need
Three things, and they are cheap once the URL builder exists.
Every page carries hreflang for all three locales plus x-default, and every one of those URLs is generated by the same builder as the links. Every page has a self-referencing canonical, so the Italian page points at itself rather than at English. And the lang and dir attributes on <html> are set per locale, which matters for screen readers before it matters for crawlers.
The failure mode when this is wrong is quiet: the pages are indexed, but the wrong language is served to the wrong country, and traffic goes to a page the visitor cannot read.
What we would tell someone starting
Decide the URL shape before you write a line of layout, and put it in one function that everything calls.
Write the CSS with no left or right in it from the first component, not as a retrofit. Retrofitting logical properties across a finished site is a genuinely miserable week.
Add the right-to-left language early, even if it launches last. Every wrong assumption in the layout surfaces the day you switch that attribute, and you want that day to be week two, not the week before launch.
And read your own variable names for hidden directions. newer and older cost nothing on day one and cannot be wrong later.
We build multilingual sites, including right-to-left, as first-class routes over shared content rather than as translated copies. If you are selling into more than one language market, we are happy to look at it with you.