Перенос слов

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

В JavaScript задачи сегментации текста и подготовки его к переносу частично решаются через Intl API, в первую очередь через механизм Intl.Segmenter, основанный на Unicode Text Segmentation Standard (UAX #29).


Сегментация текста как основа переноса

Любая логика переноса строк опирается на определение единиц текста:

  • графемные кластеры (grapheme clusters)
  • слова (words)
  • предложения (sentences)

Простейший подход:

const words = text.split(" ");

Такой метод не учитывает:

  • языки без пробелов (китайский, японский, тайский)
  • сложные составные символы (эмодзи, комбинированные диакритики)
  • знаки пунктуации, влияющие на границы слов
  • правила локали

Intl.Segmenter как инструмент корректного разбиения

Intl.Segmenter предоставляет стандартизированную сегментацию текста с учетом локали и типа разбиения.

Базовая структура

const segmenter = new Intl.Segmenter("en", { granularity: "word" });
const segments = segmenter.segment("Hello world!");

for (const { segment, isWordLike } of segments) {
  console.log(segment, isWordLike);
}

Результат содержит не просто строки, а структурированные сегменты:

  • segment — фрагмент текста
  • index — позиция в исходной строке
  • isWordLike — признак словоподобного сегмента

Гранулярность сегментации и перенос строк

Графемы

const segmenter = new Intl.Segmenter("ja", { granularity: "grapheme" });

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

  • emoji-комбинации
  • акцентированные буквы
  • сложные письменности

Графемная сегментация важна, когда перенос не должен разрывать визуально неделимый символ.


Слова

const segmenter = new Intl.Segmenter("ru", { granularity: "word" });

Позволяет определить границы слов для:

  • вставки мягких переносов
  • добавления <wbr>
  • построения кастомного переноса строк

Предложения

const segmenter = new Intl.Segmenter("en", { granularity: "sentence" });

Используется в случаях:

  • адаптивной верстки текста
  • разбиения длинных блоков
  • генерации подсказок и превью

Перенос слов в браузерной модели

Перенос текста в веб-интерфейсах определяется несколькими уровнями:

  1. Unicode Line Breaking Algorithm (UAX #14)
  2. CSS свойства (overflow-wrap, word-break, hyphens)
  3. JavaScript-сегментация (Intl API)

Intl.Segmenter находится выше CSS по уровню абстракции, поскольку позволяет формировать текст до рендеринга.


Построение мягких точек переноса

Одно из практических применений сегментации — вставка мягких точек переноса.

Использование <wbr>

const segmenter = new Intl.Segmenter("en", { granularity: "word" });

function insertBreaks(text) {
  return [...segmenter.segment(text)]
    .map(s => s.segment)
    .join("<wbr>");
}

Такой подход позволяет браузеру переносить строки в корректных местах без нарушения целостности слов.


Языковые особенности переноса

Языки без пробелов

В языках вроде китайского и японского границы слов не совпадают с пробелами:

const segmenter = new Intl.Segmenter("zh", { granularity: "word" });

const text = "今天的天气很好";

Без сегментации разбиение строки невозможно выполнить корректно.


Сложные письменности

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

  • тайский язык
  • кхмерский
  • лаосский

Intl.Segmenter учитывает правила Unicode, а не упрощенные эвристики.


Графемные кластеры и неделимость символов

Один видимый символ может состоять из нескольких Unicode-кодов:

  • = e + U+0301
  • флаги = пара региональных индикаторов
  • эмодзи с модификаторами кожи

Графемная сегментация предотвращает разрыв таких конструкций при переносе.

const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });

const text = "?‍?‍?‍? family";

console.log([...segmenter.segment(text)]);

Интеграция с CSS-переносом

JavaScript-сегментация используется совместно с CSS:

.text {
  overflow-wrap: break-word;
  word-break: normal;
  hyphens: auto;
}

Сценарии:

  • CSS отвечает за рендеринг
  • Intl API определяет корректные границы

Практическая модель гибридного переноса

Этап 1: сегментация

const segmenter = new Intl.Segmenter(locale, { granularity: "word" });
const segments = [...segmenter.segment(text)];

Этап 2: разметка

const html = segments
  .map(s => `<span>${s.segment}</span>`)
  .join("<wbr>");

Этап 3: визуализация

HTML получает управляемые точки переноса без потери семантики слов.


Производительность сегментации

Intl.Segmenter оптимизирован на уровне движков:

  • реализация в ICU
  • отсутствие регулярных выражений
  • потоковая обработка сегментов

Однако частое пересоздание сегментера нежелательно:

// неэффективно
function bad(text) {
  const s = new Intl.Segmenter("en", { granularity: "word" });
  return [...s.segment(text)];
}

Оптимальная модель:

const segmenter = new Intl.Segmenter("en", { granularity: "word" });

function good(text) {
  return [...segmenter.segment(text)];
}

Контекст локали и влияние на разбиение

Локаль влияет на:

  • правила определения слов
  • поведение пунктуации
  • обработку сокращений
  • границы предложений
new Intl.Segmenter("en-US", { granularity: "word" });
new Intl.Segmenter("de", { granularity: "word" });

Различия особенно заметны в составных словах немецкого языка и сокращениях английского.


Мягкий перенос через Unicode символы

Дополнительный механизм — символ мягкого переноса:

  • \u00AD (soft hyphen)
const text = "international\u00ADization";

Он отображается только при переносе строки.


Ограничения подхода

Несмотря на возможности Intl API:

  • отсутствует прямой API line breaking (уровня UAX #14)
  • не учитываются стилистические предпочтения типографики
  • нет встроенного хифенационного словаря
  • сложные правила переносятся на CSS и браузер

Комбинированные стратегии

На практике применяется сочетание:

  • Intl.Segmenter — логическая сегментация
  • CSS hyphens — типографика
  • <wbr> — управляемые точки переноса
  • Unicode soft hyphen — ручная корректировка

Такая модель позволяет обеспечить корректное поведение текста в многоязычных интерфейсах без потери семантики и визуальной целостности.