Направление письма (RTL/LTR)

Preact — это легковесный JavaScript-фреймворк, который поддерживает концепцию виртуального DOM и предоставляет API, совместимое с React. Одним из важных аспектов веб-разработки является корректная работа с направлениями письма: LTR (Left-to-Right) для большинства европейских языков и RTL (Right-to-Left) для арабского, иврита и некоторых других языков. Preact не накладывает строгих ограничений на работу с направлениями письма, однако правильная организация компонентов и стилизации крайне важна для поддержки многоязычных интерфейсов.

Атрибут dir и его применение

Направление письма определяется атрибутом HTML dir, который может принимать значения:

  • ltr — текст отображается слева направо;
  • rtl — текст отображается справа налево;
  • auto — направление выбирается автоматически на основе первых значимых символов текста.

В Preact атрибут dir можно назначать напрямую на JSX-элемент:

import { h } from 'preact';

const Header = () => (
  <header dir="rtl">
    <h1>مرحبا بالعالم</h1>
  </header>
);

В данном примере текст заголовка будет отображаться справа налево. Атрибут можно использовать как на отдельных элементах, так и на контейнерах, охватывающих весь интерфейс.

Динамическое переключение направления

Для многоязычных приложений часто требуется динамическое управление направлением письма в зависимости от выбранного языка. Это можно реализовать через пропсы компонентов:

const App = ({ language }) => {
  const direction = language === 'ar' || language === 'he' ? 'rtl' : 'ltr';

  return (
    <div dir={direction}>
      <p>
        {language === 'ar' ? 'مرحبا بالعالم' : 'Hello World'}
      </p>
    </div>
  );
};

Использование переменной direction позволяет централизованно контролировать направление письма, обеспечивая корректное отображение интерфейса при смене языка.

Стилизация и поддержка RTL

CSS играет ключевую роль при работе с направлением письма. Основные моменты:

  • Свойства margin, padding, float и text-align часто требуют инверсии при переходе с LTR на RTL. Например, margin-left в LTR может соответствовать margin-right в RTL.
  • Использование CSS-переменных или утилитных классов позволяет легко адаптировать стили под оба направления:
:root {
  --main-padding-ltr: 16px;
  --main-padding-rtl: 16px;
}

.container {
  padding-left: var(--main-padding-ltr);
  padding-right: var(--main-padding-rtl);
}

[dir="rtl"] .container {
  padding-left: var(--main-padding-rtl);
  padding-right: var(--main-padding-ltr);
}
  • Для сложных интерфейсов можно применять CSS Logical Properties, такие как margin-inline-start, margin-inline-end, padding-inline-start, которые автоматически учитывают направление письма.

Работа с компонентами и библиотеками

Preact совместим с большинством React-компонентов и библиотек, но при использовании сторонних UI-фреймворков важно проверять поддержку RTL. Некоторые библиотеки предоставляют отдельные темы или настройки для RTL:

import { Button } from 'some-ui-library';

const MyComponent = () => (
  <div dir="rtl">
    <Button>حفظ</Button>
  </div>
);

При отсутствии встроенной поддержки потребуется вручную адаптировать CSS для корректного отображения.

Международные форматы и текстовые направления

Помимо визуального отображения, направление письма влияет на:

  • Выравнивание чисел и дат: арабские цифры обычно отображаются слева направо, даже в RTL-контексте, что важно учитывать при форматировании;
  • Сочетание LTR и RTL текста: для смешанных блоков текста применяются специальные символы Unicode (LRM, RLM) или CSS-свойство unicode-bidi: embed для корректного визуального представления;
  • Навигацию и компоненты интерфейса: стрелки, кнопки и иконки могут требовать зеркального отображения для RTL, чтобы сохранялось логическое направление действий.

Оптимизация производительности

При динамическом переключении направления письма важно избегать лишних перерисовок компонентов. Использование Preact Hooks, таких как useMemo и useEffect, позволяет обновлять только нужные элементы при смене языка:

import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';

const LanguageProvider = ({ language }) => {
  const [direction, setDirection] = useState('ltr');

  useEffect(() => {
    setDirection(language === 'ar' ? 'rtl' : 'ltr');
  }, [language]);

  return <div dir={direction}>Контент приложения</div>;
};

Такой подход минимизирует количество изменений в DOM и поддерживает высокую производительность интерфейса.

Интеграция с Preact Router

Для многоязычных приложений с маршрутизацией важно синхронизировать направление письма с маршрутами. Например, можно хранить направление в контексте и использовать его для всех страниц:

import { h } from 'preact';
import { Router, Route } from 'preact-router';
import { createContext } from 'preact';

const DirectionContext = createContext('ltr');

const App = ({ language }) => {
  const direction = language === 'ar' ? 'rtl' : 'ltr';

  return (
    <DirectionContext.Provider value={direction}>
      <div dir={direction}>
        <Router>
          <Route path="/" component={Home} />
          <Route path="/about" component={About} />
        </Router>
      </div>
    </DirectionContext.Provider>
  );
};

Использование контекста позволяет компонентам на разных маршрутах автоматически подстраиваться под нужное направление письма без повторного расчета.

Итоговые рекомендации

  • Атрибут dir должен быть назначен на корневые контейнеры или отдельные компоненты с текстом, требующим специфического направления письма.
  • Использование CSS Logical Properties облегчает поддержку LTR и RTL без дублирования стилей.
  • Динамическое управление направлением через пропсы и контекст позволяет создавать адаптивные многоязычные интерфейсы.
  • Особое внимание следует уделять смешанному тексту, форматам чисел и дат, а также навигационным элементам, которые могут требовать зеркального отображения.

Поддержка RTL в Preact — это сочетание корректной установки атрибута dir, грамотной стилизации и использования возможностей фреймворка для минимизации лишних перерисовок компонентов.