From 6c00077d3838c1996e361e577b0064214fc07027 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Thu, 11 Jun 2026 21:04:38 -0500 Subject: [PATCH] feat(desktop): auto-detect RTL/bidi text direction in chat Arabic/Hebrew/Persian/Urdu chat text rendered left-to-right and left-aligned, and mixed RTL/English technical messages (the common case) read backwards. Resolve each chat block's base direction from its own first strong character (UAX#9) with pure CSS, scoped to the chat surfaces only: - `unicode-bidi: plaintext` + `text-align: start` on assistant prose blocks (p, h1-h6, li, blockquote), the user bubble's text lines, and both composers (main + edit share the composer-rich-input slot). RTL blocks read and right-align RTL; English stays LTR; mixed conversations resolve per block. `text-align: start` is required because the user bubble hardcodes `text-left`. - Inline `code` and KaTeX are pinned `direction: ltr; unicode-bidi: isolate`, so the bidi first-strong heuristic skips them: a sentence that *starts* with a command (`./run.sh ...`) followed by Arabic still resolves RTL, and the command's own neutrals keep their order. - Fenced code surfaces (code-card, user fences) are pinned LTR so they never mirror or right-align inside an RTL list item or blockquote. `direction` is never forced, so app chrome, layout, and list indent stay LTR per the issue's request not to flip the whole UI. English-only content is byte-for-byte unchanged. Salvaged and unified from #44065 and #44169; verified in Chromium that isolate removes inline code from the paragraph direction vote (the code-first case), making the JS dir-resolution in #44065 unnecessary. Fixes #44150 Co-authored-by: Adolanium Co-authored-by: Adalsteinn Helgason --- .../assistant-ui/user-message-text.tsx | 4 ++- apps/desktop/src/styles.css | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/components/assistant-ui/user-message-text.tsx b/apps/desktop/src/components/assistant-ui/user-message-text.tsx index 9e0da646f29..4235f94bf69 100644 --- a/apps/desktop/src/components/assistant-ui/user-message-text.tsx +++ b/apps/desktop/src/components/assistant-ui/user-message-text.tsx @@ -127,7 +127,9 @@ const InlineSegmentView: FC<{ text: string }> = ({ text }) => { const nodes = useMemo(() => splitInlineCode(text), [text]) return ( - + // styles.css bidi hook (#44150); whitespace-pre-line makes each line its own + // UAX#9 paragraph so it resolves direction independently. + {nodes.map((node, nodeIndex) => node.kind === 'inline-code' ? ( code), +[data-slot='aui_user-inline-code'], +[data-slot='aui_assistant-message-content'] .aui-md .katex { + direction: ltr; + unicode-bidi: isolate; +} + +/* Fenced code stays LTR even inside an RTL list item/blockquote — never mirrors. */ +[data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'], +[data-slot='aui_user-fence'] { + direction: ltr; + text-align: left; +} + [data-slot='aui_user-message-root'] { top: var(--sticky-human-top); }