Skip to content

Instantly share code, notes, and snippets.

@bengry
Created March 12, 2026 19:37
Show Gist options
  • Select an option

  • Save bengry/a06b2bc3d36fe4f02c2f6d0187f82f3e to your computer and use it in GitHub Desktop.

Select an option

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.
// ==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