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.
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.
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 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.
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.
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.
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.
isRTL / isLTR booleans — the hidden inverse drives the LTR layer.FA/* text styles — a Vazirmatn twin for every Latin style.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.
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.
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.isRTL last — wiring the RTL visibility ref silently drops the variable-bound default if done too early.