Skip to content
Learn Agentic AI
Learn Agentic AI10 min read16 views

Building RTL-Compatible Agent Interfaces: Arabic, Hebrew, and Persian Support

Implement right-to-left text support, bidirectional content handling, and UI mirroring for AI agent interfaces serving Arabic, Hebrew, and Persian-speaking users.

The RTL Challenge in AI Interfaces

Right-to-left (RTL) language support goes far beyond flipping text direction. When an AI agent serves Arabic, Hebrew, or Persian users, the entire interface layout must mirror: navigation moves to the right, progress indicators reverse, chat bubbles swap sides, and mixed-direction content (code snippets, URLs, numbers within Arabic text) must render correctly without garbling.

For AI agents specifically, the challenge intensifies because agent responses often mix RTL text with LTR elements — code blocks, technical terms, URLs, and mathematical expressions all flow left-to-right even within an Arabic response.

Detecting RTL Requirements

Determine directionality from the language code and apply it to the response context.

Hear it before you finish reading

Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.

Try Live Demo →
flowchart LR
    INPUT(["User intent"])
    PARSE["Parse plus<br/>classify"]
    PLAN["Plan and tool<br/>selection"]
    AGENT["Agent loop<br/>LLM plus tools"]
    GUARD{"Guardrails<br/>and policy"}
    EXEC["Execute and<br/>verify result"]
    OBS[("Trace and metrics")]
    OUT(["Outcome plus<br/>next action"])
    INPUT --> PARSE --> PLAN --> AGENT --> GUARD
    GUARD -->|Pass| EXEC --> OUT
    GUARD -->|Fail| AGENT
    AGENT --> OBS
    style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
    style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
    style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
    style OUT fill:#059669,stroke:#047857,color:#fff
from dataclasses import dataclass
from typing import Set

RTL_LANGUAGES: Set[str] = {"ar", "he", "fa", "ur", "ps", "sd", "yi", "dv"}

@dataclass
class DirectionalityContext:
    language: str
    is_rtl: bool
    base_direction: str  # "rtl" or "ltr"
    alignment: str       # "right" or "left"

    @classmethod
    def from_language(cls, lang_code: str) -> "DirectionalityContext":
        lang = lang_code.split("-")[0].split("_")[0].lower()
        is_rtl = lang in RTL_LANGUAGES
        return cls(
            language=lang,
            is_rtl=is_rtl,
            base_direction="rtl" if is_rtl else "ltr",
            alignment="right" if is_rtl else "left",
        )

# Usage
ctx = DirectionalityContext.from_language("ar_SA")
print(ctx.base_direction)  # "rtl"
print(ctx.alignment)       # "right"

Handling Bidirectional Text in Agent Responses

Agent responses often contain embedded LTR content within RTL text. Use Unicode bidirectional control characters to prevent display corruption.

import re

# Unicode Bidi control characters
LRI = "\u2066"  # Left-to-Right Isolate
RLI = "\u2067"  # Right-to-Left Isolate
PDI = "\u2069"  # Pop Directional Isolate
LRM = "\u200E"  # Left-to-Right Mark
RLM = "\u200F"  # Right-to-Left Mark

class BidiTextProcessor:
    """Process bidirectional text for correct display."""

    def wrap_ltr_in_rtl(self, text: str) -> str:
        """Wrap LTR segments (code, URLs, numbers) in isolation markers within RTL text."""
        # Isolate URLs
        text = re.sub(
            r"(https?://\S+)",
            lambda m: f"{LRI}{m.group(1)}{PDI}",
            text,
        )
        # Isolate code in single backticks
        text = re.sub(
            r"`([^`]+)`",
            lambda m: f"`{LRI}{m.group(1)}{PDI}`",
            text,
        )
        # Isolate standalone numbers with units
        text = re.sub(
            r"(\d+[\w%$]+)",
            lambda m: f"{LRI}{m.group(1)}{PDI}",
            text,
        )
        return text

    def prepare_code_block(self, code: str, surrounding_dir: str) -> str:
        """Ensure code blocks always render LTR regardless of surrounding direction."""
        if surrounding_dir == "rtl":
            return f"{LRI}{code}{PDI}"
        return code

    def fix_punctuation(self, text: str, direction: str) -> str:
        """Ensure punctuation appears on the correct side for the text direction."""
        if direction == "rtl":
            # Arabic/Hebrew punctuation should be at the logical end
            text = text.replace(f".{LRI}", f"{LRI}.")
        return text

Backend Response Formatting for RTL

When the agent generates responses, annotate them with directionality metadata so the frontend can render correctly.

from typing import List
from dataclasses import dataclass, field

@dataclass
class FormattedSegment:
    text: str
    direction: str  # "rtl", "ltr", or "auto"
    segment_type: str  # "text", "code", "url", "number"

@dataclass
class DirectionalResponse:
    base_direction: str
    segments: List[FormattedSegment] = field(default_factory=list)

class RTLResponseFormatter:
    def __init__(self, bidi: BidiTextProcessor):
        self.bidi = bidi

    def format_response(self, text: str, lang: str) -> DirectionalResponse:
        ctx = DirectionalityContext.from_language(lang)
        response = DirectionalResponse(base_direction=ctx.base_direction)

        # Split response into segments by code fence delimiters
        fence = "~" * 3
        parts = re.split(rf"({fence}\w*\n[\s\S]*?{fence})", text)
        for part in parts:
            if part.startswith(fence):
                response.segments.append(
                    FormattedSegment(text=part, direction="ltr", segment_type="code")
                )
            elif ctx.is_rtl:
                processed = self.bidi.wrap_ltr_in_rtl(part)
                response.segments.append(
                    FormattedSegment(text=processed, direction="rtl", segment_type="text")
                )
            else:
                response.segments.append(
                    FormattedSegment(text=part, direction="ltr", segment_type="text")
                )
        return response

UI Mirroring Metadata

Send layout hints to the frontend so the chat interface mirrors correctly for RTL users.

def generate_layout_hints(direction: str) -> dict:
    """Generate CSS/layout hints for the frontend."""
    if direction == "rtl":
        return {
            "dir": "rtl",
            "text_align": "right",
            "user_bubble_side": "left",   # Mirrored from LTR default
            "agent_bubble_side": "right",
            "input_icon_position": "left",
            "scrollbar_side": "left",
            "nav_direction": "row-reverse",
            "font_family": "'Noto Sans Arabic', 'Segoe UI', sans-serif",
        }
    return {
        "dir": "ltr",
        "text_align": "left",
        "user_bubble_side": "right",
        "agent_bubble_side": "left",
        "input_icon_position": "right",
        "scrollbar_side": "right",
        "nav_direction": "row",
        "font_family": "'Inter', 'Segoe UI', sans-serif",
    }

Input Handling for RTL

Agent input fields must handle mixed-direction typing. When a user types Arabic text and then inserts an English technical term, the cursor behavior and text flow must remain predictable.

Still reading? Stop comparing — try CallSphere live.

CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.

class RTLInputValidator:
    """Validate and normalize RTL input before processing."""

    def normalize_input(self, text: str, expected_dir: str) -> str:
        """Normalize Unicode and strip problematic bidi overrides from user input."""
        import unicodedata
        # Normalize to NFC form
        text = unicodedata.normalize("NFC", text)
        # Remove potentially malicious bidi override characters
        dangerous = {"\u202A", "\u202B", "\u202C", "\u202D", "\u202E"}
        for char in dangerous:
            text = text.replace(char, "")
        return text.strip()

    def detect_mixed_direction(self, text: str) -> bool:
        """Check if text contains both RTL and LTR scripts."""
        has_rtl = bool(re.search(r"[\u0600-\u06FF\u0590-\u05FF\u0750-\u077F]", text))
        has_ltr = bool(re.search(r"[a-zA-Z]", text))
        return has_rtl and has_ltr

FAQ

Do I need separate UI builds for RTL and LTR?

No. Modern CSS with logical properties (margin-inline-start instead of margin-left) and the dir HTML attribute handle mirroring automatically. Build one responsive interface that adapts based on the direction attribute. This is significantly easier to maintain than separate builds.

How do I handle RTL text in agent logs and debugging?

Logs should store raw Unicode text without bidi formatting characters. Add the language code and direction as structured metadata fields alongside the log entry. This keeps logs machine-readable while preserving full content. Bidi rendering should only happen at the display layer.

What fonts should I use for RTL languages?

Use the Noto font family (Google Noto Sans Arabic, Noto Sans Hebrew) as a reliable cross-platform choice. Specify RTL fonts first in your CSS font stack with LTR fonts as fallback. Ensure the font supports all diacritical marks — Arabic text without proper tashkeel rendering looks broken to native speakers.


#RTLSupport #BidirectionalText #ArabicUI #AIInterfaces #Accessibility #AgenticAI #LearnAI #AIEngineering

Share

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

AI Voice Agents

Voice Agent for Elderly & Accessibility: Designing for Everyone (2026)

Voice interfaces lift task completion 40%+ for users with motor impairments — but only if speech rate, pause budgets, and feedback patterns adapt. We map ADA-aligned UX and CallSphere's senior-friendly mode.

AI Strategy

Retail AI Voice & ADA Effective Communication in 2026

Title III lawsuits against retail digital channels hit a record in 2025. Here is the effective-communication, multi-modal, and consent stack a retail AI voice agent needs to ship in 2026.

AI Strategy

ADA Title III & AI Receptionists in Hospitality (2026)

ADA Title III requires automated-attendant systems to be accessible. Here is what hotels, restaurants, and resorts need to know about deploying AI voice receptionists without inviting a Title III lawsuit in 2026.

AI Strategy

WCAG 2.2 and ADA Title II for AI Voice Accessibility in 2026

DOJ's ADA Title II Web and Mobile Accessibility Rule reaches its first compliance deadline April 24, 2026. AI voice and chat platforms supporting public entities and healthcare must meet WCAG 2.1 AA — and WCAG 2.2 is the working baseline.

AI Voice Agents

WebRTC + AI Captioning for Live Church and Faith Services in 2026

Live faith services in 2026 ship multilingual AI captions over WebRTC to congregations spanning 100+ languages. Here is the production stack with on-prem ASR, accessible overlays, and donation flows.

Learn Agentic AI

Accessibility Auditing with GPT Vision: Automated WCAG Compliance Checking

Use GPT Vision to perform automated accessibility audits that detect visual WCAG violations including contrast issues, missing labels, touch target sizes, and reading order problems — generating actionable compliance reports.