What Building a QR Menu Platform for Egyptian Restaurants Taught Me About Arabic-First Software
By Omar MohamedOct 2026
Every developer thinks they respect a language until they build for it. I thought I did. Then I built قائمة (Qa'ima) — a multi-tenant platform where Egyptian restaurants publish a QR-code menu and receive orders through their own WhatsApp — and discovered that "supporting Arabic" is not a translation file. It is an architectural stance you take on day one or spend the rest of the project apologizing for.
The idea came from watching how restaurants here actually work. A waiter writes an order on paper, someone types it into WhatsApp by hand, and the customer installs nothing because nobody wants another app for one restaurant. The product was obvious: a table QR that opens a menu and hands a structured order to the restaurant's WhatsApp. Cash and InstaPay support, a live order board, analytics. Nothing exotic. The interesting part was never the feature list — it was every quiet decision underneath it.
The first decision: Arabic by default, English as the variation. Arabic lives on the unprefixed URLs, English gets the /en prefix, and every dish, category and description exists bilingually at the database level, not the render level. This sounds cosmetic until you try it the other way. Retrofitting right-to-left into a finished English product is how you get a mirrored mess — drawers sliding the wrong way, charts reading backwards, dates formatting wrong. I started mirrored, which meant the design system itself had to be direction-aware: spacing, motion, transitions. When Arabic is the default, the platform stops feeling like a translation and starts feeling native. That is the entire product in one sentence.
The second decision: money is integers. Prices are stored as whole piastres, never decimals, and formatted through the platform's locale machinery for display. Floating-point currency bugs are a famous class of bug, and the cheapest way to never have them is to never allow them to exist. The same logic ran through time: opening hours are stored timezone-safe and evaluated against the restaurant's own timezone, so "closed" means closed at two in the afternoon in Giza, not in UTC. And it ran through tenancy: every row carries a restaurant ID inside composite foreign keys, so one restaurant cannot read another's data even by accident — the database enforces the boundary, not just the code. Orders are persisted with sequential numbers, unguessable public IDs and idempotency keys before anything is sent anywhere, because a WhatsApp handoff is a transport, not a source of truth. A flaky connection should be able to duplicate nothing and lose nothing.
None of this was glamorous, and the stack was deliberately boring: TypeScript, Next.js, Postgres, an ORM with committed migrations, invite-only authentication instead of public sign-up, because an open signup form on a multi-tenant restaurant platform is a spam magnet wearing a welcome mat. The boring stack let me spend the entire innovation budget on the one genuinely novel constraint: doing it all Arabic-first.
The challenges were the honest kind. Arabic has six plural categories, and the pluralization format I first wrote silently broke in the message parser — a bug that only shows up in a language most tutorials never test. A corrupted dev-server cache threw phantom database errors that had nothing to do with my schema, which taught me to distrust caches before distrusting my code. A hardcoded environment flag crashed production builds in containers, teaching me to never set what a framework can infer. Headless end-to-end tests refused to run inside containers until they got the exact flags they needed — and the payoff is a suite that catches broken ordering flows before any guest does. Each bug cost an evening. Each one left a permanent upgrade in how I debug.
If I had to compress the whole project into one rule, it is this: localizing a product is not adding a language to a finished app; it is letting the language make the early decisions. The Arabic did not make this project harder. It made it honest — and it made it something I can actually hand to a restaurant in Cairo and watch someone's grandmother order koshari from it without being told how.