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

Форматирование чисел и пользовательского ввода в Cleave.js строится вокруг идеи явной конфигурации: библиотека не определяет локаль автоматически, а предоставляет набор параметров, позволяющих имитировать поведение различных региональных стандартов через настройки разделителей, десятичного знака, группировки и структуры ввода. Такой подход делает поведение предсказуемым в разных браузерах и окружениях, но требует точного понимания того, какие параметры отвечают за конкретные элементы локализации.


Основой локализации числового ввода в Cleave.js выступает режим numeral. Он активирует специализированную обработку чисел, включая форматирование тысячных разрядов, управление десятичной частью и контроль допустимого ввода.

new Cleave(input, {
  numeral: true
});

Сам по себе этот режим не задаёт локаль — он лишь включает механизм числового форматирования. Все региональные особенности добавляются через дополнительные параметры.


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

  • 1,000,000 (англоязычный формат)
  • 1.000.000 (европейский формат)
  • 10,00,000 (индийская система)

Cleave.js предоставляет параметр numeralThousandsGroupStyle, который позволяет выбрать стратегию группировки:

new Cleave(input, {
  numeral: true,
  numeralThousandsGroupStyle: 'thousand'
});

Доступные значения:

1. thousand Классическая западная система группировки по три цифры:

1000000 → 1,000,000

2. lakh Индийская система:

1000000 → 10,00,000

3. wan Китайская система:

100000000 → 1,0000,0000

Важно понимать, что выбор этого параметра полностью заменяет “локаль”, поскольку именно он определяет визуальную структуру числа.


Десятичный разделитель и региональные различия

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

  • точка: 12.34
  • запятая: 12,34

В Cleave.js это управляется параметром numeralDecimalMark:

new Cleave(input, {
  numeral: true,
  numeralDecimalMark: ','
});

или

new Cleave(input, {
  numeral: true,
  numeralDecimalMark: '.'
});

Важный нюанс

Cleave.js не преобразует значения в “настоящую локаль” JavaScript. Он лишь визуально заменяет символ ввода. Это означает, что:

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

Управление разделителем тысяч

Хотя numeralThousandsGroupStyle задаёт структуру группировки, символ разделителя управляется отдельно через delimiter:

new Cleave(input, {
  numeral: true,
  delimiter: ' '
});

Примеры локальных стилей:

Европейский вариант

{
  numeral: true,
  delimiter: ' ',
  numeralDecimalMark: ','
}

Результат:

1000000 → 1 000 000
12.5 → 12,5

Американский вариант

{
  numeral: true,
  delimiter: ',',
  numeralDecimalMark: '.'
}

Результат:

1000000 → 1,000,000
12.5 → 12.5

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

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

Cleave.js не имеет встроенного механизма смены локали, поэтому используется пересоздание экземпляра:

let cleave = new Cleave(input, configEnUS);

// переключение
cleave.destroy();

cleave = new Cleave(input, configDeDE);

Где конфигурации могут выглядеть так:

const configEnUS = {
  numeral: true,
  delimiter: ',',
  numeralDecimalMark: '.',
  numeralThousandsGroupStyle: 'thousand'
};

const configDeDE = {
  numeral: true,
  delimiter: '.',
  numeralDecimalMark: ',',
  numeralThousandsGroupStyle: 'thousand'
};

Такой подход отражает архитектурную особенность библиотеки: состояние форматирования не абстрагировано в “локаль”, а хранится в наборе параметров.


Работа с валютными форматами

Хотя Cleave.js не является полноценной библиотекой интернационализации, она часто используется для подготовки валютных полей ввода.

Типичная конфигурация включает:

  • фиксированное число десятичных знаков
  • разделители тысяч
  • символ валюты через prefix
new Cleave(input, {
  numeral: true,
  numeralDecimalScale: 2,
  numeralDecimalMark: '.',
  delimiter: ',',
  prefix: '$'
});

Для европейских валют:

new Cleave(input, {
  numeral: true,
  numeralDecimalScale: 2,
  numeralDecimalMark: ',',
  delimiter: ' ',
  prefix: '€ '
});

Особенность prefix

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


Ограничения локализации в Cleave.js

Несмотря на гибкость, модель локализации имеет ряд ограничений:

1. Отсутствие автоматического определения локали

Библиотека не использует navigator.language и не подстраивается под регион автоматически.

2. Нет полноценной поддержки ICU форматов

В отличие от Intl.NumberFormat, Cleave.js не поддерживает сложные правила:

  • склонение валют
  • форматирование дат по локали
  • контекстные символы

3. Только визуальный уровень

Форматирование применяется к строке ввода, а не к числовому типу данных.


Сопоставление с Intl.NumberFormat

В экосистеме JavaScript существует стандартный инструмент локализации — Intl.NumberFormat. Он работает иначе, чем Cleave.js.

new Intl.NumberFormat('de-DE').format(1000000);

Результат:

1.000.000

Различия:

  • Intl.NumberFormat — форматирует вывод
  • Cleave.js — форматирует ввод
  • Intl работает с локалями напрямую
  • Cleave.js требует ручной настройки параметров

Таким образом, Cleave.js применяется на уровне UI-инпута, а не на уровне представления данных.


Комбинирование локалей и пользовательского опыта

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

Типичный сценарий:

  1. Приложение определяет язык интерфейса
  2. Загружается соответствующая конфигурация Cleave.js
  3. При смене языка экземпляр пересоздаётся

Пример централизованной фабрики:

function createNumeralConfig(locale) {
  switch (locale) {
    case 'de-DE':
      return {
        numeral: true,
        delimiter: '.',
        numeralDecimalMark: ',',
        numeralThousandsGroupStyle: 'thousand'
      };

    case 'en-US':
    default:
      return {
        numeral: true,
        delimiter: ',',
        numeralDecimalMark: '.',
        numeralThousandsGroupStyle: 'thousand'
      };
  }
}

Обработка пользовательского ввода в разных локалях

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

Например:

  • 1,5 (европейский ввод)
  • 1.5 (американский ввод)

Cleave.js не приводит значение к числу автоматически. Поэтому применяется нормализация:

function parseValue(value) {
  return Number(
    value
      .replace(/\s/g, '')
      .replace(',', '.')
  );
}

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


Особенности работы с нулевыми значениями и ведущими нулями

Локализация также затрагивает поведение при вводе:

new Cleave(input, {
  numeral: true,
  stripLeadingZeroes: true
});

Этот параметр предотвращает ввод значений вроде:

000123 → 123

В некоторых локалях это критично, поскольку восприятие чисел с ведущими нулями может различаться в зависимости от контекста (например, финансовые коды, идентификаторы).


Дробная точность и локальные ограничения

Параметр numeralDecimalScale определяет количество знаков после запятой:

new Cleave(input, {
  numeral: true,
  numeralDecimalScale: 3
});

При локализации важно учитывать, что:

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

Практическая модель локализации через Cleave.js

Полноценная локализация чисел в Cleave.js обычно строится как комбинация четырёх элементов:

  1. delimiter — разделитель тысяч
  2. numeralDecimalMark — десятичный символ
  3. numeralThousandsGroupStyle — стратегия группировки
  4. prefix — символ валюты или единицы измерения

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


Поведение при некорректных символах локали

При вводе символов, не соответствующих текущей конфигурации:

  • Cleave.js автоматически очищает недопустимые символы
  • попытки вставки “чужих” разделителей приводят к нормализации
  • форматирование применяется мгновенно при событии input

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