Mirroring a stylesheet is not right-to-left support, and machine translation is not localisation. Here is what genuine multilingual support looked like in a narrated 3D history app we built.
Nūr al-Tārīkh is a narrated 3D journey through thirteen centuries of history, in nine languages. It is our own, it is live, and it runs on React, React Three Fiber and Vite, with ElevenLabs narration. Most of what made it hard had nothing to do with 3D. It was the part most teams leave for last: making the same experience true in nine languages, including the ones that read right to left.
One dataset, three ways to see it
The app has three viewing modes over a single dataset: an interactive globe, a flowing timeline ribbon, and cinematic era scenes with synchronised narration and captions. Keeping one dataset under all three was the first localisation decision, not a technical convenience. An event, its date, its place and its description exist once, and every mode and every language reads the same record. Three modes built on three copies of the data would have meant three chances to translate something differently.
Right-to-left is a layout, not a flip
The shortcut for right-to-left languages is to mirror the stylesheet: flip everything horizontally and ship. It produces something that looks plausible in a screenshot and wrong in use. Genuine right-to-left means the reading order, alignment and navigation follow the script, while things that are not text — a play button, a timeline that runs in time — are decided on their own merits rather than flipped by default.
Nūr al-Tārīkh was built with genuine right-to-left layout rather than a mirrored stylesheet, and with correct typography per script. Different scripts need different type: line height, weight and spacing that suit one alphabet can crowd or clip another. Treating typography as a per-script decision is what stops a translated screen from looking like an accident.
Narration that survives a bad connection
Narration in nine languages is expensive to generate on demand and fragile to stream. So the narration is pre-generated in each language, with the browser's own speech synthesis as a fallback. The result is that audio works offline and off-budget: a visitor on a poor connection still hears the story, and a spike in visitors does not turn into a spike in voice-generation bills.
Every date checked
A history app in nine languages multiplies every mistake by nine. Before release, the content went through a multi-pass verification over dates, names, coordinates and neutrality of framing, with sources recorded for each event. That last check matters as much as the first three: the same event can be described in ways that quietly take sides, and a translation carries the framing along with the facts.
Access built in, not bolted on
The visual language holds to geometric and astronomical motifs, and the app ships keyboard navigation, captions, reduced-motion and high-contrast paths. Those were built alongside the features, not added at the end — the same rule we apply to every app: accessibility, reduced-motion and keyboard paths from the first commit.
What carries over to other products
Most businesses will never ship a 3D history app, but many will need a second language, and some a right-to-left one. The lessons carry over: keep one source of truth for content, decide layout per script rather than flipping it, give media a fallback that works offline, and verify translated content as carefully as the original. More on what an app build involves on the web and mobile apps page.