Created
March 12, 2026 19:37
-
-
Save bengry/a06b2bc3d36fe4f02c2f6d0187f82f3e to your computer and use it in GitHub Desktop.
Claude RTL userscript — makes claude.ai RTL for Persian/Arabic speakers. Install via Tampermonkey/Greasemonkey.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Claude RTL | |
| // @namespace https://github.com/mh-daneshvar/claude-rtl | |
| // @version 1.2.0 | |
| // @description Makes claude.ai RTL for Persian and Arabic speakers. Code blocks stay LTR. | |
| // @author mh-daneshvar (userscript adaptation) | |
| // @match https://claude.ai/* | |
| // @run-at document-end | |
| // @grant none | |
| // @license MIT | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| const STYLE_ID = 'claude-rtl-style'; | |
| function applyRTL() { | |
| if (document.getElementById(STYLE_ID)) return; | |
| const style = document.createElement('style'); | |
| style.id = STYLE_ID; | |
| style.textContent = ` | |
| @import url('https://fonts.googleapis.com/css2?family=Vazirmatn&display=swap'); | |
| [data-testid="user-message"], | |
| [data-testid="assistant-message"], | |
| .font-claude-message, | |
| .font-claude-response-body, | |
| .standard-markdown, | |
| .whitespace-pre-wrap { | |
| direction: rtl !important; | |
| text-align: right !important; | |
| font-family: 'Vazirmatn', Tahoma, sans-serif !important; | |
| } | |
| div[contenteditable="true"], textarea { | |
| text-align: start !important; | |
| font-family: 'Vazirmatn', Tahoma, sans-serif !important; | |
| } | |
| .code-block__code, | |
| .code-block__code * { | |
| direction: ltr !important; | |
| text-align: left !important; | |
| font-family: monospace !important; | |
| } | |
| code.whitespace-pre-wrap { | |
| direction: ltr !important; | |
| text-align: left !important; | |
| unicode-bidi: embed !important; | |
| display: inline-block !important; | |
| font-family: monospace !important; | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| } | |
| function processContentEditable() { | |
| const el = document.querySelector('div[contenteditable="true"]'); | |
| if (el && !el.hasAttribute('dir')) { | |
| el.setAttribute('dir', 'auto'); | |
| } | |
| } | |
| applyRTL(); | |
| processContentEditable(); | |
| let debounceTimer = null; | |
| const observer = new MutationObserver(() => { | |
| processContentEditable(); | |
| clearTimeout(debounceTimer); | |
| debounceTimer = setTimeout(applyRTL, 150); | |
| }); | |
| observer.observe(document.documentElement, { | |
| childList: true, | |
| subtree: true, | |
| attributes: true, | |
| attributeFilter: ['contenteditable', 'dir'], | |
| }); | |
| let attempts = 0; | |
| const interval = setInterval(() => { | |
| if (++attempts > 5) { clearInterval(interval); return; } | |
| processContentEditable(); | |
| }, 2000); | |
| setTimeout(processContentEditable, 100); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment