Тот же товар - техническая книга - открывается на арабском. Каталог, карточка, цена, кнопка покупки должны выглядеть привычно тому, кто ведёт взгляд справа налево. Наивное решение напрашивается: отразить вёрстку целиком - transform: scaleX(-1) на странице или замена left и right. Кажется, RTL - это зеркало, и отражения хватит.
На деле направление - свойство текста, а не косметика поверх макета. Порядком символов управляет bidi-алгоритм (Unicode Bidirectional Algorithm): браузер сам решает, куда течёт фрагмент строки, по категории символов. Арабские буквы идут справа налево, латиница и цифры - слева направо, и в одной строке уживаются разом. Зеркальный фильтр этого не знает: переворачивает пиксели, а не смысл, ломает то, что переворачивать нельзя.
Начинать нужно с корня. Атрибут lang сообщает язык содержимого, dir - основное направление: dir=rtl разворачивает поток интерфейса, выравнивание текста, порядок колонок и логику начала строки. Это не стилевой хак, а сигнал платформе: браузер, экранный диктор и bidi-алгоритм отталкиваются от него. Один правильный dir на html делает больше сотни правок в CSS.
Дальше вступают logical properties - логические свойства CSS: они описывают отступы и границы не через физические стороны (left, right, top, bottom), а через поток текста. Ось inline идёт вдоль строки, block - поперёк. margin-inline задаёт отступы по краям строки, padding-inline - внутренние поля, border-inline-start - границу со стороны начала, text-align: start - выравнивание к началу. В LTR начало слева, в RTL - справа, и один стиль работает в обе стороны без дубликатов и отдельной арабской таблицы стилей.
Отдельная забота - смешанные строки. Номер заказа ABC-123 или цена латинскими цифрами внутри арабского предложения - те самые встречные потоки, которые bidi-алгоритм порой собирает неожиданно: скобки, дефисы и знаки прилипают не к тому фрагменту. Элемент bdi (bidirectional isolate) изолирует кусок, чтобы направление не перетекало наружу и не тянуло соседний текст. Артикул читаем, а предложение вокруг - целым.
Иконки требуют суждения, а не сплошного отражения. Направленные символы - стрелки назад и вперёд, значок ответа, индикатор прогресса - в RTL должны смотреть в другую сторону, и зеркалирование через transform: scaleX() тут уместно. Но универсальные знаки зеркалить нельзя: треугольник play означает ход времени, а не сторону, а check, логотип бренда и циферблат часов одинаковы во всех культурах. Отразив их с макетом, получаете перевёрнутый логотип и галочку не туда.
Локализуемым должен быть и объём текста. Перевод меняет длину надписи: немецкая строка легко на треть длиннее исходной, арабская - короче, но выше из-за диакритики. Кнопка с жёсткой шириной обрезает перевод, а надпись, впечатанная в картинку, не переводится и не читается диктором. Поэтому размеры задают по содержимому, строку держат в комфортных пределах, а текст оставляют текстом, не пикселями.
Показательный провал. Карточку книги оформили с border-left: 4px и margin-left: auto, а арабскую версию получили фильтром scaleX(-1) на всём контейнере. Граница осталась слева, хотя по потоку должна быть справа; логотип и галочка Купить отразились и читаются как ошибка; номер заказа развалился без bdi. Замена физических свойств логическими, dir на корне и зеркалирование только направленных иконок убирают все четыре дефекта разом - интерфейс описан на языке потока, а не сторон.
.card {
margin-inline: auto;
padding-inline: 1rem;
border-inline-start: 4px solid currentColor;
text-align: start;
}
.icon-next {
transform: scaleX(var(--direction, 1));
}<html lang="ar" dir="rtl">
<p>رقم الطلب: <bdi>ABC-123</bdi></p>