Arabic and English in one product, without two codebases
Supporting a right-to-left language is usually costed as translation. Translation is the cheap part. The expensive parts are layout direction, numerals and mixed-direction text.
Engineering practice3 min read
The decision to support a second language is usually made in a planning meeting and costed as translation. Translation is the cheap part. On the Zain Islamic Bank work we shipped Arabic and English across native Android and iOS from a single services layer, and almost none of the difficulty was in the strings.
Mirroring is a layout property
A right-to-left build is a mirrored build. Navigation runs the other way, back means forward, progress fills from the right, and every chevron points the opposite direction. Any team that has hardcoded left or right in a layout discovers all of it at once. Using start and end for padding, margins, alignment and constraints from the first screen costs nothing at the beginning and becomes a sweep through the entire product later.
Some things must not mirror. Phone numbers, IBANs, account numbers, times of day and anything a customer will read aloud to a call centre keep their direction. Latin brand marks keep theirs. Media transport controls are a genuine judgement call, and the sensible way to settle it is to check the platform's own applications rather than argue about it in a design review.
Numerals are a separate decision from language
Arabic can be written with Arabic-Indic digits or with Western digits, and the correct answer depends on the market rather than on the language tag. Iraq, in our experience, expects Western digits in a banking context. Getting that wrong makes a balance screen look foreign to the person it was localised for. Currency formatting is the same question again: symbol placement, decimal separator, digit grouping, and whether a negative amount carries a sign or brackets.
All of it belongs in one formatting service that takes the locale as an input, tested against real examples per market, and none of it belongs in the view layer. The moment two screens format money differently, a customer notices, and then trusts neither of them.
Mixed direction is where it gets genuinely hard
A sentence containing an Arabic phrase and a Latin currency code has two directions inside it. The Unicode bidirectional algorithm resolves that automatically. It is usually right, and the exceptions are precisely the ones users see. Neutral characters take their direction from what surrounds them, so a full stop can land at the wrong end of a line and a bracket can flip. Isolating the embedded run fixes it. Assembling a sentence by concatenating fragments guarantees a meeting with the problem, which is one more reason to keep whole sentences in the translation file.
The reliable way to find these is a person who reads Arabic, on a real device, doing the actual task. Screenshot comparison catches layout drift. It does not catch a sentence that renders correctly and reads as nonsense.
The late surprises
- Generated documents. Receipts, statements and PDF exports use a different rendering path from the app, and get localised last or never.
- Outbound messages. SMS and push notifications are composed server-side, truncate at a byte limit that Arabic reaches sooner, and are rarely in anybody's test plan.
- Third-party components. A payment or chat SDK may not mirror at all, and that becomes visible after integration rather than before.
- Sorting and search. Ordering, and matching text with and without diacritics, behave differently and fail quietly.
- Dates. A second calendar system may be in use alongside the Gregorian one, and both may have to appear.
The fork is always available and always wrong
Under deadline pressure somebody will propose branching the codebase for the Arabic build. It is genuinely faster this month. It is also the last month in which the two products are the same. Every feature after that gets built twice, tested twice if you are lucky, and diverges in the details nobody has time to check. We have inherited forked localisations. The bug reports are the worst kind: a defect that exists in one language only, raised by a customer who cannot see the version everybody else is looking at.
The discipline that keeps a single codebase intact is decided at the start and it is short. No direction hardcoded. No sentence assembled from fragments. One formatting service. A tester who reads the language. Adding those in month six means doing the sweep anyway, with a live product attached.
More on engineering practice
All writingNovember 2025
What fifteen years of maintenance taught us about design
Fifteen years in, the systems we still maintain have taught us more than the ones we launched. Some early decisions aged quietly well. Others cost us for a decade.
August 2025
Senior engineers in a client's team, and the reporting line
Embedded engineering works when one question is settled in writing: who sets priority. Ambiguity there produces most of the friction people blame on culture or communication.
May 2024
Offline-first is a product decision
Queueing writes is the easy half. What happens when a representative returns from two days without signal is a product question, and it usually gets answered by whoever wrote the sync code.
Talk to our engineering team
Tell us what you need built, modernised or maintained. We will tell you whether we are the right firm for it and what it costs.