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.tslistsi18n.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
dirattribute 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.jsonfirst, then translate tohe.jsonandru.jsonbefore opening a PR. - Use logical CSS properties, not directional ones. (
text-startnottext-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.
Related
- architecture/i18n.md
- CLAUDE.md “Localization” section