Локализация разделителей

Локализация разделителей — один из ключевых аспектов международной типографики, который напрямую влияет на читаемость чисел, списков и сложных структур данных в интерфейсе. В экосистеме FormatJS работа с разделителями строится поверх стандартов ECMA-402 (Intl API) и данных CLDR, что позволяет учитывать культурные различия без ручного управления форматированием.

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

Базовая локализация чисел через Intl.NumberFormat

const en = new Intl.NumberFormat('en-US');
const de = new Intl.NumberFormat('de-DE');

en.format(1234567.89); // "1,234,567.89"
de.format(1234567.89); // "1.234.567,89"

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

Форматирование в React-интеграции

import { FormattedNumber } from 'react-intl';

<FormattedNumber value={1234567.89} />

Вывод автоматически адаптируется под текущую локаль, включая:

  • десятичный разделитель
  • группировку разрядов
  • порядок и стиль отображения

Локализация разделителей списков

Помимо чисел, критически важна локализация разделителей в списках. В английском языке используется конструкция с союзом “and”, в других языках — запятые, точки с запятой или иные правила.

Intl.ListFormat как основа логики разделения

const en = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' });
const de = new Intl.ListFormat('de', { style: 'long', type: 'conjunction' });

en.format(['apples', 'bananas', 'oranges']);
// "apples, bananas, and oranges"

de.format(['Äpfel', 'Bananen', 'Orangen']);
// "Äpfel, Bananen und Orangen"

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

  • типа списка (conjunction, disjunction, unit)
  • стиля (long, short, narrow)
  • локали

Поведение типов списков

conjunction — перечисление с логическим «и» disjunction — альтернативы («или») unit — набор единиц измерения или технических значений

const orList = new Intl.ListFormat('en', { type: 'disjunction' });

orList.format(['red', 'green', 'blue']);
// "red, green, or blue"

React-форматирование списков в FormatJS

В экосистеме FormatJS логика списков интегрируется через react-intl.

import { FormattedList } from 'react-intl';

<FormattedList
  value={['HTML', 'CSS', 'JavaScript']}
  type="conjunction"
/>

Результат формируется в соответствии с локалью, включая правильные разделители и союзы.

Локализация разделителей в сложных строках

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

Неправильный подход

const text = "Items: " + items.join(", ");

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

Правильный подход через ListFormat

const formatter = new Intl.ListFormat(currentLocale, {
  style: 'long',
  type: 'conjunction'
});

const text = formatter.format(items);

Разделители в форматировании единиц

Числа, связанные с единицами измерения, требуют согласованного форматирования, где разделители играют роль визуального структурирования.

const speed = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer-per-hour'
});

speed.format(120);
// "120 km/h"

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

CLDR и источники правил разделителей

FormatJS опирается на CLDR (Common Locale Data Repository), где определяются:

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

Эти данные обеспечивают единообразие поведения во всех браузерах и средах выполнения.

Нестандартные разделители и кастомизация

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

Кастомизация через formatToParts

const formatter = new Intl.NumberFormat('en-US');
formatter.formatToParts(12345.67);

Результат позволяет извлечь структуру числа:

[
  { type: "integer", value: "12" },
  { type: "group", value: "," },
  { type: "integer", value: "345" },
  { type: "decimal", value: "." },
  { type: "fraction", value: "67" }
]

Это позволяет:

  • заменять разделители
  • стилизовать отдельные части
  • внедрять кастомные UI-компоненты

Разделители в датах как связанная область

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

const date = new Intl.DateTimeFormat('de-DE');
date.format(new Date());
// "29.05.2026"

Разделители точек, слешей и пробелов также зависят от локали и следуют тем же принципам CLDR.

Поведение разделителей в разных локалях

Различия между локалями часто касаются не только символов, но и логики:

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

Примеры:

new Intl.ListFormat('en-US').format(['A', 'B', 'C']);
// "A, B, and C"

new Intl.ListFormat('fr-FR').format(['A', 'B', 'C']);
// "A, B et C"

Согласованность между форматами

Одной из ключевых задач FormatJS является обеспечение единообразия разделителей во всех типах данных:

  • числа
  • списки
  • валюты
  • единицы измерения
  • даты

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