Internationalisation
RTL, locale formatting, and the hard part. That part is translating a status vocabulary without changing what it means clinically.
The short version
NOT IMPLEMENTED. This component does not exist in any released version of opsinjs. There is no package to install, no module to import and no props interface to generate code against. Everything on this page is a specification of intended behaviour and may change without notice. Do not write code against it.
This component is not built yet
PlannedRoadmapWhat “planned” means
Three separate problems travel under one word, and they have three different difficulties:
- Direction. Right-to-left is largely solved by CSS logical properties and
by not assuming that "next" is to the right. Logical properties mean
margin-inline-startrather thanmargin-left. - Formatting. Numbers, dates, times and units differ by locale.
Intldoes this correctly; hand-rolled formatting does not. - Status language. This is the hard one. The four clinical status levels are an ordinal vocabulary with fixed meanings, and a translation that shifts one level's intensity has changed what the product tells someone about their health.
opsinjs does not ship a [lang] route segment, and that is a recorded decision
rather than an oversight: see
ADR 0005. Unit systems are
treated as a correctness surface rather than a localisation one, and ship
now. See Unit systems.
How it works
Direction
Use logical properties throughout: padding-inline, margin-block,
inset-inline-start, text-align: start. Tailwind's ps-*, pe-*, ms-*,
me-* and start-*/end-* utilities map onto them. Set dir on the root and
the browser does the rest for text; what it does not do is flip your icons, your
progress direction or your chart axes.
A RangeBar is a directional component: in RTL the low end is on the right, and
the marker position, the labels and any leading edge all move with it.
Formatting
Intl.NumberFormat, Intl.DateTimeFormat and Intl.RelativeTimeFormat handle
grouping separators, decimal separators, ordinal forms and date order. They also
handle units, which is where most hand-rolled code goes wrong: 72 kg is not
formatted the same way in every locale, and the space is not always a space.
Formatting rules for health values are canonical in Numbers, units and precision and are locale-independent. Those rules cover precision, rounding and when to show a decimal. Locale decides presentation; the health page decides how many digits are honest.
Status language
The four levels are ordinal. A translation must preserve:
- The order. Each level is more urgent than the one before.
- The distance. If two adjacent levels translate to near-synonyms, the vocabulary has collapsed from four levels to three.
- The absence of a verdict. No level may translate to a word meaning "healthy", "safe", "normal" or "bad". This constraint is stated in Clinical status semantics and does not survive a generic translation workflow.
Status strings therefore need review by someone who speaks the language and understands the clinical intent. A translation memory match is not enough.
Do this
- Write CSS with logical properties from the start. Retrofitting is a large, boring change with a long tail of missed cases.
- Format with
Intl, and pass an explicit locale rather than relying on the runtime default, which differs between server and client and will produce a hydration mismatch. - Test in RTL early, with real content. Set
dir="rtl"on the root and read the page; problems are obvious and cheap to fix at that point. - Treat status strings as a special asset class with their own review.
- Keep units and locale separate. A reader in Germany may still want stones, and a reader in the UK may want kilograms.
Not this
- Do not concatenate translated fragments. "Your " + metric + " is " + status produces sentences that are ungrammatical in most languages. Use whole sentences with parameters.
- Do not use
left/rightin CSS wherestart/endwill do. - Do not flip everything in RTL. Clocks, media playback controls and logos do not mirror; arrows and progress do.
- Do not translate a unit symbol.
mmHgandmmol/Lare international; a translated abbreviation is a safety problem. - Do not assume text length. German and Finnish translations run substantially longer than English; a status pill sized to fit "watch" will clip.
- Do not localise a medication name. See Medications.
Gotchas
Intlon the server and the client can disagree if the locale is not passed explicitly, producing a hydration mismatch reported as a text-content error.- Numerals are not universal. Some locales use different digit glyphs;
Intlhandles it, string interpolation does not. text-align: rightin an RTL layout is notend. It is genuinely right, and it will look like a bug that only appears in one language.- Logical properties and
transformdo not interact. A translated element still moves in physical space; a slide-in sheet needs its direction chosen from the writing direction. - Screen readers announce direction changes. A Latin-script medication name
in an RTL sentence is mixed-direction content, and it needs explicit
diron the span to avoid the punctuation moving. - Date order is not the only difference. Some calendars are not Gregorian, and a date picker built on a fixed twelve-month year will be wrong.
Related
- Unit systems covers units as correctness, not localisation.
- Numbers, units and precision has the canonical formatting rules.
- ADR 0005: no lang segment yet has the decision and the recipe for retrofitting it.
- Clinical status semantics has the meanings a translation must preserve.
Server and client components
Where the client boundary falls, what is safe to render on the server, and why importing one interactive component can turn a whole page into client code.
TypeScript
The exported surface comprises named prop interfaces, the ClinicalStatus and HealthCategory unions, and the rule that makes generated API tables possible.