Skip to content

i18n — RTL & bidi

i18n specs/i18n/rtl-bidi.kmd

The contract for right-to-left + bidirectional text: authors write LOGICAL (start/end) layout — never physical left/right — so a surface mirrors under `dir="rtl"` with no per-component RTL code; directional icons mirror while neutral ones don't; mixed-direction text is isolated per the Unicode bidi algorithm. gov.br has no RTL runtime — KDS surpasses it by making RTL a property of the layout system, not a per-locale rewrite. ar/he are the validation locales.

When this pattern applies

Primary triggers

All triggers

Specification body

i18n — RTL & bidi

R1 — Logical layout, never physical

Layout is authored in logical (writing-relative) propertiesinline-start / inline-end, margin-inline, padding-inline, inset-inline, border-inline, text-align: start/end, and flex/grid start/endnever left/right, margin-left, text-align: right, etc. A surface built this way mirrors automatically under RTL with zero per-component code. Physical left/right is reserved only for things that are genuinely physical and direction-independent (a drop-shadow offset, a fixed hardware affordance) — never for reading-order layout.

R2 — Activating RTL

Direction is set on the document/root (<html dir="rtl">) or a subtree container, driven by the active locale (i18n/contract.kmd). Every component reads its direction from the cascade — it does not detect or hard-code a direction. A surface MUST render correctly at dir="ltr" and dir="rtl" from the same source.

R3 — Directional icons mirror; neutral icons don't

An icon that encodes reading direction — back/forward, next/prev chevrons, indent, list-nesting, a right-pointing "proceed" arrow — mirrors under RTL. An icon whose meaning is direction-independent — search, settings, a checkmark, a logo, a clock, media play (play always points to the timeline's forward, which is culturally LTR) — does not mirror. Icons carry a mirrorable flag; the renderer flips only those under dir="rtl". Guessing per icon at call sites is forbidden — the flag is the SSOT.

R4 — Bidirectional text (the Unicode bidi algorithm)

Mixed-direction runs (an English brand name, a URL, a phone number, or code inside Arabic prose) follow the Unicode Bidirectional Algorithm:

  • User-supplied / unknown-direction text is rendered with dir="auto" (or a first-strong isolate) so its base direction follows its content, not the container.
  • Embedded opposite-direction runs are isolated (unicode-bidi: isolate, or the isolate control chars) so a trailing punctuation/number does not visually jump to the wrong edge.
  • Never concatenate a bidi-sensitive value into a translated string without isolation (a classic "the ) landed on the wrong side" bug).

R5 — Start/end tokens & utilities

The spacing/grid tokens are direction-neutral scalars (spacing-scale.kmd, column-grid.kmd); RTL support is applying them through logical properties, not new values. The logical-property utility classes (.ms-*/.me-* = margin-inline start/end, .text-start, .float-start, …) are the authoring shorthand — they live in the vendored SoT koder_web_kit.css (drift-gated), NOT invented in a design-gen copy (same rule as column-grid.kmd's utility class). Kroma surfaces express the same start/end intent through the widget layout API.

R6 — Component contract

Every component in the corpus:

  • uses only logical properties for reading-order layout (R1) — a physical left/right in layout is a defect;
  • flags its directional icons mirrorable (R3);
  • isolates any bidi-sensitive interpolated value (R4).

New/changed components are checked against this at review; a component that bakes in LTR is not RTL-ready and is not conformant.

R7 — Validation

RTL/bidi is validated with ar (Arabic) and he (Hebrew) as the target locales, via k-test-gen-i18n + i18n/test-template.kmd: render each surface at dir="rtl" and assert (a) no physical-left/right layout leaked, (b) directional icons mirrored and neutral ones did not, (c) a mixed-direction fixture string renders with correct isolation.

Não-escopo / follow-up

  • Adoption: migrating the existing components/landings off physical left/right onto logical properties, adding the .ms-*/.me-* utility classes to koder_web_kit.css, tagging icons mirrorable, and the k-test-gen-i18n RTL suite — an incremental sweep (stack#450, opened).
  • Translation / string extractioni18n/contract.kmd; leak detectioni18n/leak-detection.kmd. This spec is layout+bidi, not the message catalogue.

References