← All posts
Engineering6 min read

[ENGINEERING] · May 5, 2026 · 09:00

Multilingual live chat: serving 12 languages from one inbox

How muro's widget detects the visitor's language, falls back gracefully, and lets a single agent answer Spanish, Japanese, and Arabic without switching tools.

LM

Léa Marchand

Engineering

#i18n#engineering#languages#rtl

Live chat is one of the few products where i18n really matters at the edge. A French visitor on a Spanish e-commerce site will not type in English. A Japanese visitor will close the tab if the placeholder text is in English. We chose 12 languages for muro — covering ~80% of the public internet by visitor count — and built the widget i18n in a way that adds about 2 KB to the bundle.

The 12 supported languages

EN · FR · ES · DE · IT · PT · NL · JA · KO · ZH · AR (RTL) · RU. Eleven UI strings each — welcome, online status, reply ETA, typing indicator, type-message placeholder, send, attach, new message, conversation closed, reopen, powered-by line.

Resolution order

  1. 01Explicit muro('init', { lang: 'fr' }) from the install snippet
  2. 02Per-website default in the muro dashboard (config.language)
  3. 03navigator.language (browser preference)
  4. 04<html lang="…"> of the host page
  5. 05English fallback

In practice, most websites set the per-site default to match the site's primary language and let navigator.language override for visitors browsing in another tongue. That covers the long tail.

RTL: Arabic

Arabic flips everything — text direction, the side the launcher sits on, the bubble corners. We detect RTL via a simple isRtl(lang) check and add dir="rtl" on the widget root. Tailwind's logical properties (ms-3 instead of ml-3) handle the rest:

tsx<div dir={isRtl(lang) ? 'rtl' : 'ltr'} className="muro-widget">
  <header className="ps-3 pe-2">…</header>
</div>

Where the strings live

Plain TypeScript module — src/lib/i18n.ts — keyed by language code. No fancy ICU MessageFormat, no plural rules library; the strings we need are 11 short labels with at most one variable. JSON would have worked too; TS gives us autocomplete on the keys for free.

Agent side: the inbox stays English

The dashboard UI is in English regardless of the visitor's language — agents work in one tongue, see incoming messages in whatever language the visitor wrote. We deliberately don't translate the message body even when we detect a mismatch; agents prefer raw text + their own translation tool (DeepL, Apple's built-in) over an automatic translation that might subtly change meaning.

Adding a 13th language

It's a single file edit + a one-line type union update. Languages have come up: Polish, Turkish, Greek, Hebrew (RTL). We'll add them when we see real demand — typically when one customer's biggest market is in that language.

✦ ✦ ✦

Multilingual chat is a quiet detail that earns trust the moment a visitor sees their language reflected back. It's also a feature we get asked about more than we'd expect, so this article exists mainly so the next person who asks gets a link instead of a paragraph.

LM

✎ Written by

Léa Marchand

Engineering