DEV Community

Idan Levi
Idan Levi

Posted on

AI Coding Agents Are Great, but They Suck at RTL. Here's How I Fixed It

RTLify CLI demo showing the init and check commands in a terminal

I build products for Hebrew-speaking users. Every time I ask an AI to generate a component, I get the same broken output — margin-left instead of margin-inline-start, ml-4 instead of ms-4, arrows pointing the wrong way, and order numbers jumping around inside RTL sentences.

I fix it. I ask for the next component. Same bugs. The AI doesn't learn — it's trained on LTR codebases and has zero awareness that RTL exists.

After months of manually fixing the same 5-6 patterns in every single component, I built RTLify — a CLI that teaches your AI editor the rules once, so you never fix them again.

npx rtlify-ai init
Enter fullscreen mode Exit fullscreen mode

One command. Works with Claude Code, Cursor, Windsurf, Cline, GitHub Copilot, Gemini CLI, and Codex CLI.


The Bugs AI Keeps Making

Let me show you exactly what goes wrong. If you've built anything in Hebrew, Arabic, Persian, or Urdu — you'll recognize every single one.

1. Physical CSS Instead of Logical

AI writes:

.sidebar {
  margin-left: 16px;
  padding-right: 8px;
  border-left: 1px solid #ccc;
  left: 0;
}
Enter fullscreen mode Exit fullscreen mode

In RTL, "left" is "right". The layout mirrors, but these properties don't. The correct version:

.sidebar {
  margin-inline-start: 16px;
  padding-inline-end: 8px;
  border-inline-start: 1px solid #ccc;
  inset-inline-start: 0;
}
Enter fullscreen mode Exit fullscreen mode

Logical properties work in both LTR and RTL. AI never uses them unless you tell it to.

2. Wrong Tailwind Classes

This is the most common one. AI writes:

<div className="ml-4 pr-6 text-left border-l-2 rounded-tl-lg">
Enter fullscreen mode Exit fullscreen mode

Every single class here is wrong for RTL. The correct version:

<div className="ms-4 pe-6 text-start border-s-2 rounded-ss-lg">
Enter fullscreen mode Exit fullscreen mode

RTLify includes a full mapping table with 20+ conversions — mlms, prpe, text-lefttext-start, float-rightfloat-end, rounded-tlrounded-ss, and more.

3. Numbers Jumping Around (Bidi Text)

This is the sneaky one. Look at this Hebrew sentence:

<p>ההזמנה שלך #12345 אושרה בהצלחה</p>
Enter fullscreen mode Exit fullscreen mode

Looks fine in your code editor. Open it in a browser with dir="rtl" — the number #12345 visually jumps to a completely wrong position. The sentence becomes unreadable.

The fix is a <bdi> tag:

<p>ההזמנה שלך <bdi>#12345</bdi> אושרה בהצלחה</p>
Enter fullscreen mode Exit fullscreen mode

Same applies to phone numbers, dates, English brand names — any LTR content inside an RTL sentence needs <bdi> wrapping. AI never does this.

4. Icons Pointing the Wrong Way

In an RTL interface, a "next" arrow should point left, not right. But AI always generates:

<ChevronRight className="w-5 h-5" />
Enter fullscreen mode Exit fullscreen mode

The fix:

<ChevronRight className="w-5 h-5 rtl:-scale-x-100" />
Enter fullscreen mode Exit fullscreen mode

Non-directional icons (home, settings, search) should NOT be flipped. AI doesn't know the difference — RTLify teaches it which ones to flip.

5. Currency and Dates

AI formats prices like this:

const price = `₪${amount}`;  // Wrong — symbol on wrong side
Enter fullscreen mode Exit fullscreen mode

The correct way:

const price = new Intl.NumberFormat('he-IL', {
  style: 'currency',
  currency: 'ILS',
}).format(amount);
// → "42.90 ₪" — symbol on correct side, RTL mark included
Enter fullscreen mode Exit fullscreen mode

Same for dates — AI defaults to MM/DD/YYYY instead of DD/MM/YYYY with Intl.DateTimeFormat.

6. React Native Gets It Even Worse

On mobile, the same problems exist but with different APIs:

// AI writes:
paddingLeft: 16
left: 0
textAlign: 'left'

// Should be:
paddingStart: 16
start: 0
writingDirection: 'rtl'
Enter fullscreen mode Exit fullscreen mode

Plus you need I18nManager.isRTL for conditional checks and transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }] for icon flipping.


How RTLify Works

There's no magic and no runtime dependency. Here's what happens when you run npx rtlify-ai init:

  1. It writes .rtlify-rules.md — a markdown file containing 8 RTL architecture rules with concrete "do this / not that" code examples. This is the full ruleset the AI will follow.

  2. It adds a 3-line pointer to your editor's config file (CLAUDE.md, .cursorrules, .windsurfrules, etc.) that tells the AI: "read .rtlify-rules.md before generating any UI code."

  3. For Claude Code users — it installs a global /rtlify command. Just type /rtlify in Claude Code and it scans, fixes, and verifies your entire project.

That's it. The AI reads the rules on every conversation. No extra prompting needed.

You can open .rtlify-rules.md and read exactly what the AI sees. Full transparency — it's just a markdown file.

The Linter

RTLify also ships with a scanner that catches violations in existing code:

npx rtlify-ai check
Enter fullscreen mode Exit fullscreen mode
  src/components/Sidebar.tsx
       3 Tailwind Physical
         Use logical classes (ms-*, me-*, ps-*, pe-*)
         <div className="ml-4 pl-6 text-left">

  src/components/OrderCard.tsx
       8 Tailwind Physical
         Use text-start / text-end
         <h2 className="text-left text-xl">פרטי הזמנה</h2>

  2 violations across 2 files
Enter fullscreen mode Exit fullscreen mode

Exits with code 1 — plug it into your CI pipeline to catch RTL violations on every PR.

The Fix Command (Cursor, Windsurf, Cline, Copilot)

Claude Code users get the /rtlify slash command. For every other editor:

npx rtlify-ai fix
Enter fullscreen mode Exit fullscreen mode

It generates a ready-to-paste prompt and copies it to your clipboard. Paste it into Cursor, Windsurf, Cline, or any AI editor — it tells the AI to scan, fix, and verify all RTL violations.


The 8 Rules

# Rule What the AI Learns
1 Logical CSS margin-inline-start not margin-left
2 Tailwind Mapping 20+ class conversions (ml-*ms-*)
3 Icon Flipping rtl:-scale-x-100 on directional icons only
4 BDI Safety <bdi> tags for numbers/English in RTL text
5 Localized Formats Intl.NumberFormat('he-IL') for currency & dates
6 Safe i18n Respects your i18n setup or lack of it
7 Complex Components Carousels, charts, sliders with dir="rtl"
8 React Native I18nManager.isRTL, paddingStart, writingDirection

Try It

npx rtlify-ai init
Enter fullscreen mode Exit fullscreen mode

Then ask your AI to "build a checkout form in Hebrew" or "create a settings screen in Arabic". You'll see the difference immediately.

GitHub: github.com/idanlevi1/rtlify
NPM: npmjs.com/package/rtlify-ai

If you're building for RTL markets — what's the most annoying RTL bug an AI has generated for you? I'd love to hear in the comments.

Top comments (0)