Работа с RTL-языками в контексте дат в JavaScript требует учета не только локализации форматов, но и особенностей направления письма, которое влияет на визуальное представление строки, содержащей дату, время и текст. В экосистеме date-fns локализация реализована через подключаемые локали и функции форматирования, которые опираются на стандарты CLDR, но при использовании арабского, иврита и других RTL-культур появляется дополнительный слой проблем: порядок символов, смешение направлений текста и корректное отображение числовых и словесных компонентов даты.
RTL-языки (Right-to-Left), такие как арабский и иврит, меняют не только направление текста, но и визуальную интерпретацию строк, содержащих числа, знаки пунктуации и латиницу. Дата, представленная как комбинация чисел и слов, часто становится смешанным направлением текста (bidirectional text).
Типичный пример:
При неправильной обработке возможно визуальное «перемешивание» компонентов, например:
В JavaScript это особенно заметно при использовании
format() без учета направления строки.
В date-fns локализация реализована через отдельные модули:
date-fns/locale/ar — арабскийdate-fns/locale/he — ивритdate-fns/locale/fa — персидский (в некоторых
сборках)Каждая локаль содержит:
Пример подключения локали:
import { format } from "date-fns";
import { ar } from "date-fns/locale";
format(new Date(2026, 2, 15), "d MMMM yyyy", { locale: ar });
Результат будет соответствовать арабской языковой модели, но не гарантирует корректного визуального RTL-выравнивания в DOM без дополнительных мер.
Основная проблема RTL — не формат даты, а алгоритм двунаправленного текста Unicode (BiDi algorithm). Он автоматически перераспределяет порядок символов в строке.
Если строка содержит:
то итоговый порядок может отличаться от ожидаемого.
Пример проблемной строки:
15 مارس 2026 (Monday)
В некоторых контекстах может отображаться как:
(2026 Monday) 15 مارس
или частично инвертированно.
Функция format() в date-fns не управляет направлением
текста, она лишь формирует строку:
format(date, "EEEE, d MMMM yyyy", { locale: ar });
Выход:
الأحد، 15 مارس 2026
Но при встраивании в UI важно учитывать контекст:
dir="rtl")Корректная работа с RTL часто решается не в JavaScript, а на уровне DOM:
<div dir="rtl">
الأحد، 15 مارس 2026
</div>
или смешанный вариант:
<div dir="rtl">
<span dir="ltr">15</span> مارس 2026
</div>
Это предотвращает перестановку чисел и символов.
При работе с датами часто требуется изолировать числовые компоненты. Это достигается с помощью Unicode-меток:
Пример ручной стабилизации строки:
const LRM = "\u200E";
const formatted = `15${LRM} March 2026`;
Однако при использовании date-fns предпочтительнее не вмешиваться вручную, а структурировать вывод через форматирование и DOM-изоляцию.
Функция formatDistance также зависит от локали:
import { formatDistance } from "date-fns";
import { ar } from "date-fns/locale";
formatDistance(new Date(2026, 2, 15), new Date(), {
locale: ar,
addSuffix: true
});
Результат будет грамматически адаптирован:
منذ 3 أيام
Особенность RTL здесь заключается в том, что числительное и слово могут менять порядок отображения в зависимости от окружения.
Функции:
formatRelativeformatDistanceToNowособенно чувствительны к локали, потому что возвращают текстовые конструкции.
Пример:
formatRelative(new Date(2026, 2, 15), new Date(), { locale: ar });
Результат:
الأحد الماضي عند الساعة 12:00
В этом случае важно учитывать:
При построении интерфейсов календарей возникает комбинация:
Пример компонента:
import { format } from "date-fns";
import { he } from "date-fns/locale";
const label = format(date, "EEEE, d MMMM", { locale: he });
Результат может быть визуально корректным, но при рендеринге в LTR-странице потребуется:
<div dir="rtl">
<!-- date string -->
</div>
Сложность возникает при сценариях:
В этом случае возможны:
date-fns использует токены форматирования:
d — деньMMMM — месяцyyyy — годEEEE — день неделиВ RTL-контексте важно не менять токены, а менять только локаль:
format(date, "EEEE d MMMM yyyy", { locale: ar });
Частая проблема — визуальная инверсия чисел:
2026 → 6202 (визуально в некоторых UI)
Причина — BiDi алгоритм и отсутствие изоляции.
Практики стабилизации:
dir="ltr" для числовых блоковПри кастомизации форматов важно учитывать, что локаль влияет только на текстовые элементы:
format(date, "d MMM yyyy", { locale: ar });
Если требуется строгий контроль структуры:
Даже при корректной работе date-fns результат зависит от:
Некоторые шрифты неправильно выравнивают цифры в арабском тексте, что усиливает визуальные ошибки.
Стабильный подход включает разделение уровней:
Логический слой (JavaScript)
Презентационный слой (DOM)
dirCSS слой
unicode-bidi.date {
direction: rtl;
unicode-bidi: isolate;
}
Это снижает влияние соседнего LTR-контента.
В реальных приложениях часто встречается:
В таких условиях date-fns используется только для генерации локализованных строк, а финальная визуальная стабилизация выполняется на уровне интерфейса.
При хранении и передаче дат не допускается использование локализованных строк. Даже в RTL-системах:
2026-03-15)Иначе возникают ошибки:
Работа с датами в RTL-средах требует разделения ответственности:
Нарушение любого уровня приводит к неконтролируемому BiDi-эффекту, который невозможно исправить только средствами форматирования даты.