Skip to Content
Living documentation — last reviewed 2026-05-28
DecisionsADR-0006: Hebrew/RTL as a first-class language

ADR-0006: Hebrew/RTL as a first-class language

Status: Accepted Date: ~2026-01 (estimate) Context owner: Owner

Context

FitKit’s target market is Israeli boutique fitness studios. Hebrew is the primary user-facing language; the platform also serves English and Russian users. Hebrew is right-to-left (RTL), which affects layout, scrollbars, icons, animations, and prepositions in copy.

Treating Hebrew as a translation-after-the-fact is a known anti-pattern: bidi bugs accumulate, RTL layout gets bolted on awkwardly, and copy gets translated word-for-word rather than rewritten idiomatically.

Decision

Hebrew is a first-class language. Every user-facing string flows through the i18n dictionary in all three locales before it lands in code.

  • Locales: en, he, ru (apps/web/src/i18n/config.ts lists i18n.locales).
  • Server-side dictionaries (no client-side translation library) keep bundle size in check.
  • Routes are locale-prefixed: /en/..., /he/..., /ru/.... Middleware detects the locale from cookie → Accept-Language → default.
  • The dir attribute is set per locale. CSS uses logical properties (margin-inline-start, padding-block-end) so styles flip automatically.
  • The API does not translate. It returns data; the web localizes labels at render time. This keeps the API agnostic to the client language.

Hard rule (also in CLAUDE.md): every user-facing string lives in en.json, he.json, and ru.json. Hardcoded English in JSX, toasts, or alerts is a regression.

Consequences

Positive

  • Hebrew users get a native experience. RTL bugs surface during development, not after launch.
  • New copy lands in all three languages at once (or it doesn’t land — code review catches missing keys).
  • Search-engine indexing and analytics events both work per-locale.

Negative

  • Every new feature requires writing copy three times. Slows shipping slightly.
  • Some libraries (especially older shadcn components) need RTL fixes — we vendor and patch where necessary.
  • Russian translation quality is uneven (smaller user base; sometimes machine-translated).

Discipline

  • Add a key to en.json first, then translate to he.json and ru.json before opening a PR.
  • Use logical CSS properties, not directional ones. (text-start not text-left.)
  • For numbers, dates, and currencies: use Intl.* with the active locale. Don’t hardcode formats.
  • For tests: integration tests cover at least one RTL layout assertion per feature; E2E spot-checks Hebrew for golden paths.
  • When in doubt, render in Hebrew while developing — it surfaces directional bugs immediately.