Arabic first
Arabic is not a translation layer bolted on at the end.
The two languages carry an identical set of 3,838 keys, right-to-left comes from the platform’s own layout direction rather than from a mirrored stylesheet, and a category or a dish carries a real Arabic name in a table of its own instead of a Latin one with Arabic appended to it.
01
Every word of the interface exists in both languages
All the apps share one set of words. Each language holds 3,838 phrases across twenty-five areas of the product, and the two sets are identical — not approximately, exactly. That is enforced rather than hoped for, because a missing Arabic phrase is not the kind of fault that announces itself: translation libraries fall back to English silently, so an Arabic-speaking cashier just sees an English button and nobody ever reports it.
- A phrase present in one language and absent from the other cannot ship, and neither can one that is a group on one side and a sentence on the other, or one that lost a placeholder in translation.
- An Arabic value still identical to the English one cannot ship either — that is the shape untranslated filler actually takes, and it is the shape that survives a proofread.
- The check runs against the whole product, not a sample, so a screen added on a Tuesday is held to the same rule on the Tuesday.
- Every one of those phrases is written by a person. None of it is machine output waiting for someone to notice.
02
Direction comes from the platform, not from a stylesheet
On the mobile apps the layout direction is set on the platform’s own layout engine, which is why switching language asks for a restart rather than pretending the change is free. On the web the direction is an attribute on the document and the spacing is written in logical properties, so the layout mirrors because the browser mirrors it.
- One function decides direction for web and native alike, from one table of locales.
- The exceptions are the things a layout engine must not mirror: a QR code is pinned left-to-right inside a right-to-left build, because a mirrored QR code does not scan.
- A directional arrow is flipped with a transform rather than shipped as a second piece of artwork, so the two builds cannot drift apart.
- Arabic is caseless and cursive, so the tracking and the uppercasing that Latin display type wants are switched off for it rather than applied and hoped for.
03
Mixed script is isolated, not hoped for
A line that mixes scripts is where bidirectional text quietly goes wrong. A table code turns itself around, a price and its quantity swap ends, and the bug is invisible to anyone reading the other language. The values are wrapped in isolation marks at the point they are built, once, rather than patched at each place they are displayed.
- A table code stays a table code inside an Arabic sentence rather than reversing into something that is not on any table.
- A price and its multiplier keep their order rather than trading places at the end of the line.
- The wrapping is not conditional on the current language, because a mixed line is a mixed line in either direction.
04
Menu content is translated in the database
Interface strings are one problem and the venue’s own words are another. Categories and catalog items carry translation rows keyed by language, resolved when the menu is read and falling back to the base row when a translation is missing, so an untranslated dish appears in its original name rather than disappearing.
- A category translates its name; an item translates its name and its description.
- The language a guest is served in travels on the request itself, and the server also honours the browser’s own preference where nothing more specific was sent.
- The catalog can be listed by what is still untranslated in a given language, which is the list a venue actually works from.
- The spreadsheet importer reads Arabic column headings, and normalises the alef and the taa marbuta so that either spelling of a heading matches the same column.
05
Language is on the record, not on the session
A locale is a property of a tenant, a member of staff, a customer and a notification, rather than a setting on whoever happens to be logged in. Timezone sits on the tenant and on the branch, which is what lets a menu window and a report both mean the venue’s own day.
- Money is formatted from the currency rather than from an assumption: the number of decimal places comes from the currency’s own definition, so a three-decimal currency is not rounded to two.
- Dates and times are formatted through the reading language, in the venue’s timezone.
- A menu availability window is evaluated in the branch’s zone, so a schedule written as eight to four means eight to four where the branch is.
- A cached menu is keyed by language, so the Arabic menu and the English one are two entries and never overwrite each other.
06
Every status and every permission, named in both languages
The words on the buttons are one problem; the words the system uses for its own states are another, and they are the ones a venue actually argues about. Every labelled set of states in the product — an order’s, a payment’s, a table’s, a session’s — carries a full set of names in both languages, and the list of those sets is derived from the system itself rather than kept by hand, so one added this month is covered this month.
- Each labelled set is matched against the real states it names, so a list that has drifted from the states it labels is caught rather than passing because it is still the right length.
- Where a screen deliberately shows only some of a set, that is written down as deliberate — an exemption a person decided on, not a silence nobody noticed.
- Every permission in the system carries a name in both languages, read from the real permission catalogue rather than from a copy of it that can fall behind.
- So an Arabic-speaking cashier reads an Arabic reason when something is refused, instead of an English constant with the underscores taken out.
Questions about Arabic
What happens if a string is missing in Arabic?
It cannot ship, which is the point. Translation libraries fall back to English silently, so a missing phrase is not an error anyone sees — it is an English button in an Arabic interface that nobody reports. The two language sets are checked against each other in full: a phrase in one and not the other, a group on one side and a sentence on the other, a dropped placeholder, a blank value, or an Arabic value still identical to the English one all stop a release. Both sets hold 3,838 phrases.
Does the interface actually flip, or is it only translated?
It flips, and it flips at the platform level rather than through a mirrored stylesheet. The mobile apps set the layout direction on the platform’s own layout engine, which is why switching language prompts for a restart instead of pretending the change is free; the web apps set the direction on the document and write their spacing in logical properties, so mirroring is the browser’s job. The exceptions are the things that must not mirror, like a QR code, which is pinned in place because a mirrored one does not scan.
Will a guest see the menu in their own language?
Yes, where the venue has translated it. Categories carry a translated name and items carry a translated name and description, keyed by language in tables of their own; the language travels on the request, and the server also honours the browser’s stated preference when nothing more specific arrives. An item with no translation falls back to its base name rather than vanishing, and the catalog can be listed by what is still untranslated so the venue can see the gap.
Read it in Arabic first.
This page exists in both languages, like every other page here, and so does the product. The switch is in the header, and the argument is the same either way.
A time, a screen share, and your own floor plan on the screen.
[email protected]