Localisation
Prism is authored to be robust to language and direction from the first line of CSS. Localisation is not a retrofit — it's a property of the layout primitives.
Direction (RTL)
The same component and the same code, left-to-right and right-to-left. Because Prism uses logical properties everywhere, order, icon placement, progress direction and focus all mirror automatically.
Left-to-right (dir="ltr")
Right-to-left (dir="rtl")
A form row mirrors the same way — labels, inputs and required markers all flip:
The brand lockup also mirrors correctly — order flips, the mark itself does not:
Logical properties
The whole UI mirrors under dir="rtl" for free, because Prism uses CSS logical properties everywhere — never physical ones:
| Use | Not |
|---|---|
margin-inline-start | margin-left |
padding-inline | padding-left/right |
inset-inline-start | left |
border-inline-start | border-left |
text-align: start | text-align: left |
Set dir="rtl" on <html> (or any subtree) and layout, icons-with-text order, progress direction and focus order all mirror. Directional glyphs (chevrons, breadcrumb separators, back arrows) flip; non-directional icons don't. Test in QA with the RTL gate.
Long strings
German, Finnish and many others run far longer than English. Prism tolerates this by design:
- Body line-height is a roomy 1.55; type sizes are
remso text-zoom composes. - Layout subtrees use the overflow/overlap guards in
base.css: media caps atmax-inline-size:100%; text wraps viaoverflow-wrap; adddata-guard="layout"so flex/grid children may shrink below content size (the usual cause of a row overflowing); use.prism-truncate/.prism-clamp(with--lines) to clip deliberately rather than overflow. - Never size a control or container to fit one language's string. Let it grow or wrap.
- Avoid text baked into images; keep labels in the DOM.
Locale-aware formatting
Numbers, dates, currency and lists are locale-aware, and right-aligned in tables with monospace (--font-mono) so digits line up across rows. Use the platform Intl APIs (React Aria's i18n hooks wrap these):
Intl.NumberFormatfor numbers, percentages, currency (currency symbol, grouping and decimal separators vary by locale).Intl.DateTimeFormatfor dates/times — never hand-format. Prism'sCalendar/DatePicker/DateRangePicker/TimePickerare built on React Aria's calendar system, which is locale- and calendar-system-aware (Gregorian and non-Gregorian) and respects first-day-of-week.Intl.ListFormat/Intl.RelativeTimeFormatfor conjunctions and "3 days ago".
Pseudo-localisation
Before a real translation exists, test with pseudo-localisation — accented, expanded, bracketed strings (e.g. [!!! Ŝéñð rémîñðér !!!]) — to surface truncation, concatenation and hard-coded-string bugs early. It's a QA gate (QA); keep fixtures in tests/pseudo-localisation/.
Authoring rules
- Logical properties only. A physical
left/right/margin-leftin a component is a bug. - Never concatenate translated fragments into a sentence — word order varies. Use whole strings with named placeholders.
- Don't hard-code formats, separators, or currency symbols — go through
Intl. - Mirror-test every new component under
dir="rtl"and expansion-test under pseudo-localisation. - Keep the measure readable (
--measure, ~68ch) in every language for longform.