Пользовательские правила форматирования

Библиотека Globalize строится на данных CLDR (Unicode Common Locale Data Repository), где все правила форматирования чисел, дат, валют и сообщений задаются локалями. Однако стандартные наборы форматов не всегда покрывают требования конкретного приложения, поэтому используется механизм пользовательских правил форматирования, позволяющий изменять поведение без вмешательства в исходные данные CLDR.

Ключевой принцип: форматирование не ограничивается предустановленными шаблонами, а может быть расширено или заменено на уровне приложения.


Пользовательские числовые форматы

Переопределение шаблонов чисел

Globalize использует внутренние шаблоны для отображения чисел:

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

Пользовательские правила позволяют создавать альтернативные маски отображения.

Пример расширенного подхода:

  • стандартное значение: 1,234.56
  • пользовательское правило: 1 234,560

Изменение достигается через кастомную конфигурацию формата:

Globalize.load({
  numbers: {
    "latn": {
      "patterns": {
        "custom-accounting": "#,##0.000"
      }
    }
  }
});

Использование:

const formatNumber = Globalize("ru").numberFormatter({
  raw: "custom-accounting"
});

formatNumber(1234.5);

Фиксация точности отображения

Пользовательские правила позволяют фиксировать:

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

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


Кастомизация валютных представлений

Альтернативные валютные шаблоны

Globalize позволяет переопределять отображение валюты без изменения базовой локали.

Globalize.load({
  numbers: {
    currencies: {
      USD: {
        displayName: "US Dollar Custom",
        symbol: "US$",
        patterns: {
          custom: "¤ #,##0.00;(¤ #,##0.00)"
        }
      }
    }
  }
});

Форматтер с пользовательским правилом:

const formatCurrency = Globalize("en").currencyFormatter("USD", {
  raw: "custom"
});

Изменение позиции символа валюты

В некоторых локалях символ валюты располагается относительно числа автоматически. Пользовательские правила позволяют:

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

Пользовательские правила форматирования дат

Переопределение шаблонов CLDR

Globalize использует CLDR Date Fields (y, M, d, H, m, s). Пользовательские правила позволяют создавать собственные композиции.

Globalize.load({
  main: {
    "ru": {
      dates: {
        calendars: {
          gregorian: {
            dateFormats: {
              custom: "dd/MM/yyyy HH:mm"
            }
          }
        }
      }
    }
  }
});

Использование:

const formatDate = Globalize("ru").dateFormatter({
  raw: "custom"
});

formatDate(new Date());

Альтернативные временные схемы

В ряде приложений требуется нестандартное отображение времени:

  • 24-часовой формат без секунд
  • сокращённые названия месяцев
  • порядок год-день-месяц

Пользовательские правила позволяют формировать такие представления независимо от локали.


Расширение правил множественного числа

Переопределение plural rules

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

Globalize.loadMessages({
  ru: {
    itemCount: {
      one: "{count} элемент",
      few: "{count} элемента",
      many: "{count} элементов",
      other: "{count} элемента"
    }
  }
});

Форматирование:

const message = Globalize("ru").messageFormatter("itemCount");

message({ count: 5 });

Пользовательские категории чисел

Вместо стандартных категорий one, few, many, other могут применяться дополнительные логические группы через предварительную обработку значений перед передачей в message formatter.


Регистрация пользовательских форматтеров

Расширение API через форматтеры

Globalize допускает создание пользовательских форматтеров поверх стандартных механизмов.

function customPercentageFormatter(value) {
  return (value * 100).toFixed(1) + " %";
}

Globalize.load({
  numbers: {
    patterns: {
      percentageCustom: customPercentageFormatter
    }
  }
});

Использование:

const format = Globalize("ru").numberFormatter({
  raw: "percentageCustom"
});

format(0.256);

Композиция форматтеров

Форматтеры могут комбинироваться:

  • числовой формат → строковая трансформация
  • дата → локализованная постобработка
  • валюта → визуальное форматирование интерфейса

Пользовательские правила в цепочках форматирования

Постобработка результатов

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

const baseFormatter = Globalize("ru").numberFormatter();
const customFormatter = value =>
  "≈ " + baseFormatter(value) + " (оценка)";

Такая схема используется для:

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

Форматирование сообщений с пользовательскими шаблонами

Шаблоны сообщений с логикой

Globalize поддерживает ICU MessageFormat, но пользовательские правила расширяют его за счёт предварительной подготовки данных.

Globalize.loadMessages({
  ru: {
    balance: "Баланс: {amount} {currency} ({status})"
  }
});

Передача вычисленных значений:

const formatMessage = Globalize("ru").messageFormatter("balance");

formatMessage({
  amount: Globalize("ru").numberFormatter()(1234.56),
  currency: "₽",
  status: "активен"
});

Иерархия приоритетов форматирования

При использовании пользовательских правил важно учитывать порядок применения:

  1. данные CLDR локали
  2. пользовательские расширения форматов
  3. параметры вызова форматтера
  4. постобработка результата

Любое нарушение порядка приводит к непредсказуемому отображению, особенно в сложных локализациях.


Ограничения пользовательских правил

Несмотря на гибкость, существуют архитектурные ограничения:

  • CLDR остаётся базовым источником для большинства локалей
  • пользовательские правила не заменяют локализацию полностью
  • некоторые типы данных (например, plural rules) требуют согласованности с ICU
  • переопределение может привести к конфликтам при обновлении CLDR данных

Особое внимание требуется при:

  • изменении валютных символов
  • кастомизации календарных систем
  • переопределении форм множественного числа

Организация слоя пользовательских форматов в приложении

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

  • модуль formatters/number
  • модуль formatters/date
  • модуль formatters/currency
  • слой бизнес-форматирования

Такой подход позволяет:

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

Структура конфигурации часто принимает форму декларативного объекта, описывающего все нестандартные форматы системы.


Интеграция с динамическими локалями

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

Globalize.load(cldrData);

const g = Globalize("fr");

const customDate = g.dateFormatter({
  raw: "custom"
});

В этом случае:

  • CLDR обеспечивает базовую локализацию
  • пользовательские правила добавляют прикладной слой форматирования
  • итоговый вывод остаётся локализованным, но адаптированным под бизнес-логику