All case studies
Sidera · Design System Owner · UX Designer · 2026

Bilingual Design System (LTR / RTL)

How I consolidated a bilingual English/LTR + Persian/RTL Figma design system into single, mode-switchable components that flip like light and dark — instead of maintaining a Persian twin for every component.

Explore the Sidera docs
Snapshot

Problem — bilingual parity built the obvious way (a Persian “twin” for every component) means each one is built twice: 2× maintenance and guaranteed drift.

Insight — a Figma variable mode can swap a color or a number, but it cannot reorder layout, change alignment, or switch a font. A row can't just “flip” to RTL by mode.

Solution — pre-build both directions inside one component and toggle visibility with an isRTL variable mode. The whole file flips EN↔FA at once, like a theme.

Outcome — one component instead of two per family (−50%), a single source of truth, and an 8-archetype taxonomy that turns each new component into a lookup, not a research task.

Context

Sidera is a bilingual system: English set in Latin, left-to-right; Persian set in Vazirmatn, right-to-left. Persian/RTL is a first-class requirement, not a retrofit — full parity is non-negotiable across every button, field and container: right direction, right font, right alignment, right icon side, right reading order.

The problem — the twin trap

The obvious way to ship bilingual parity is a Persian twin — Card and Card (FA), Select and Select (FA). It works on day one and rots by day thirty: two components per family means twice the surface to build, twice the variants to review, and two sources of truth that drift the moment one is edited and the other isn't.

DimensionTwin model → consolidated
Components2 (twin model) → 1 (consolidated)
Variant sets2× → 1×
Sources of truth2 → 1
Drift riskHigh → none
The constraint that shapes everything

A Figma variable mode can change a color or a number. It cannot reorder auto-layout children, change text alignment, or switch a font family. That fact rules out the tempting shortcut of “just bind direction to a mode” — if the platform can't flip a single layout, the component has to contain both directions.

The idea — flip by visibility, like light and dark

Both layouts live inside the component; a boolean isRTL property drives the RTL layer's visibility, while a hidden isLTR variable drives the LTR layer as its logical inverse. Switch the file's localization mode from EN to FA and every consolidated component flips together, in the same instant.

Foundations — tokens first, including the text

Layout flips by visibility; strings flip by being bound to variables. Before building a single layer, every user-visible string became a localization variable with an English and a Persian value, bound in both layers — “Step 0.” Fonts can't switch by mode either, so each Latin text style has a Persian twin carrying Vazirmatn and Persian line-heights.

  • A Localization collection with two modes — EN (default) and FA — one switch drives the whole file.
  • isRTL / isLTR booleans — the hidden inverse drives the LTR layer.
  • Localization string variables for every visible string, EN + FA.
  • Parallel FA/* text styles — a Vazirmatn twin for every Latin style.
Archetypes — a system of recipes

Rather than solving each component from scratch, I classified the whole library into eight structural shapes, each with one repeatable RTL transform — Inline control + label (Checkbox, Radio, Toggle, Badge, Chip ×2, Alert — 7 families), Field stack (Text Field, Textarea, Search, Select, Stepper — 5), Sequence/trail container (Breadcrumb, Pagination, Tabs — 3), Absolute graphical (Slider/Range, Slider/Vertical — 2), List option (Menu option — 1), Composed container that inherits (Select menu — 1), Nested inline + separator (Breadcrumb item — 1), and Composed bar + reveal panel (Navigation Menu — 1). Once the taxonomy existed, a new component stopped being a research problem and became a lookup — and known shapes consolidate with no bespoke work.

Proof — the flip, and the rule that proves it's correct

The LTR layer is the original; the RTL layer is its mirror — children reversed, text right-aligned in Vazirmatn, icon and control sides swapped, directional glyphs flipped. The “+1 invariant”: a correct consolidation changes the variant count by +0 and adds exactly one property — isRTL. That became the automated QA check.

The hard problems

Five silent failure modes I had to diagnose — each invisible until you flip to FA — then encoded into the process so they're solved once, not rediscovered per component:

  • clone() drops property references — cloning the LTR layer silently kills icon/label wiring; fixed by re-applying references by node name after every clone.
  • Shared text property collapse — one shared property wired across variants showed the same string on all of them, in both locales; fixed with one localization variable per variant × field.
  • The visible-ref wrapper trick — a visibility toggle on a cloned icon doesn't propagate to instances; wrapping the icon in a fresh, lineage-free frame does.
  • Rebind isRTL last — wiring the RTL visibility ref silently drops the variable-bound default if done too early.
  • Collapse-safety — flipping the container axis can collapse the frame to padding width; fixed by restoring fixed width, hug height.
Impact
MetricResult
Components per bilingual family−50% (2 → 1)
Sources of truth per family1 — the twin can't drift from itself
Reusable archetypes covering the library8
Modes to flip the entire system EN↔FA1
Reflections
  • Constraints first. The entire solution came from taking one platform limitation seriously instead of working around it — the constraint was the brief.
  • Systems over instances. Classifying the library into archetypes turned an open-ended chore into a finite, teachable, scriptable process.
  • RTL as first-class. Designing both directions into the same component is what actually guarantees parity you can no longer forget to maintain.
← SivanLand — Customer & Sale Panel
Explore the Sidera docs →