Работа с несколькими валютами в JavaScript опирается на
Intl.NumberFormat, который стандартизирует отображение
денежных значений в зависимости от локали, валютного кода и правил
округления. Базовый принцип заключается в том, что валюта не является
просто строковым суффиксом, а формирует часть числового формата,
зависящего от региона и финансовых стандартов.
Ключевая конструкция:
new Intl.NumberFormat(locale, {
style: "currency",
currency: "USD"
})
В этом режиме форматтер автоматически применяет:
В мультивалютных интерфейсах каждая сумма ассоциируется с конкретным
ISO-кодом валюты. Intl.NumberFormat требует явного указания
валюты через параметр currency, поэтому при работе с
несколькими валютами создаются отдельные форматтеры.
const usdFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
});
const eurFormatter = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR"
});
Такой подход устраняет неоднозначность отображения: форматирование всегда соответствует комбинации локали и валюты, а не только числовому значению.
Локаль влияет не только на разделители, но и на порядок элементов. Например:
en-US: $1,234.56de-DE: 1.234,56 €ja-JP: ¥1,234Даже при одинаковой валюте представление может существенно отличаться. Это особенно критично в системах, где одна валюта отображается для пользователей разных регионов.
Параметр currencyDisplay определяет форму отображения
валюты:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
currencyDisplay: "symbol"
});
Основные режимы:
symbol — $, €, £code — USD, EURname — US dollars, euros, Japanese yennarrowSymbol — компактные символы без региональной
неоднозначностиИспользование code критично в мультивалютных
интерфейсах, где символы могут пересекаться (например, $
используется в нескольких странах).
Мультивалютные системы часто требуют различного отображения отрицательных значений.
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
signDisplay: "always"
});
signDisplay поддерживает режимы:
auto — стандартное поведениеalways — всегда показывать знакnever — скрывать знакexceptZero — скрывать знак для нуляДля бухгалтерских интерфейсов используется дополнительная логика скобок, но базовая поддержка знаков формируется именно через этот параметр.
Разные валюты имеют разные правила дробной части. Например:
Intl.NumberFormat автоматически учитывает minor units
валюты:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "JPY"
}).format(1234.56);
Результат: ¥1,235
С появлением roundingMode появилась возможность более
тонкой настройки:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
roundingMode: "halfExpand"
});
Это важно в финансовых системах, где поведение округления должно быть строго детерминированным.
В системах учета часто требуется отображение списков транзакций с разными валютами. В таких случаях форматтеры создаются на основе кода валюты динамически.
const formatters = new Map();
function getFormatter(currency, locale) {
const key = `${locale}-${currency}`;
if (!formatters.has(key)) {
formatters.set(
key,
new Intl.NumberFormat(locale, {
style: "currency",
currency
})
);
}
return formatters.get(key);
}
Такой подход снижает накладные расходы при рендеринге больших списков.
При смешивании валют в одном UI возникает проблема визуальной консистентности. Даже при одинаковых числах:
различия могут влиять на восприятие плотности данных.
Для унифицированных таблиц часто применяется стратегия:
en-US);currencyDisplay: "code";new Intl.NumberFormat("en-US", {
style: "currency",
currency: "EUR",
currencyDisplay: "code"
});
Результат: EUR 1,234.56
Для отображения названий валют используется
Intl.DisplayNames:
const currencyNames = new Intl.DisplayNames("en", {
type: "currency"
});
currencyNames.of("USD"); // "US Dollar"
currencyNames.of("EUR"); // "Euro"
Это позволяет строить интерфейсы, где код валюты сопровождается текстовым описанием без ручных словарей.
Intl не выполняет конвертацию, но тесно интегрируется с
результатом конвертированных значений.
Типичный поток:
Intl.NumberFormat.const rate = 0.92;
const usd = 100;
const eur = usd * rate;
new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR"
}).format(eur);
Форматирование отделено от бизнес-логики, что упрощает поддержку мультивалютных систем.
При работе с крупными значениями используется
notation: "compact":
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
notation: "compact"
}).format(2500000);
Результат: $2.5M
В мультивалютных дашбордах это снижает визуальную нагрузку при сохранении смысловой точности.
Некоторые символы пересекаются между валютами или регионами.
Например, $ может обозначать:
Использование currency: "code" устраняет
неоднозначность, особенно в международных интерфейсах.
Intl.NumberFormat является относительно тяжелым
объектом. В мультивалютных системах с большим количеством строк важно
избегать повторного создания экземпляров.
Оптимизация строится на:
locale + currency;Это особенно важно в таблицах транзакций, где форматирование выполняется тысячи раз за рендер.
В отчетах часто встречаются суммы в разных валютах. Intl
не агрегирует значения, но обеспечивает корректное отображение каждой
позиции:
Такой подход предотвращает смешивание несопоставимых значений и сохраняет финансовую точность отображения.
Разные регионы используют разные визуальные шаблоны:
Intl.NumberFormat инкапсулирует эти правила, обеспечивая
единообразие без ручной настройки форматирования.
В мультивалютных приложениях Intl выполняет строго
ограниченную, но критически важную функцию: визуализацию денежных
значений. Все операции конвертации, хранения и расчётов выносятся в
бизнес-слой, а форматирование становится завершающим этапом отображения
данных.
Такое разделение снижает количество ошибок, связанных с локализацией, и обеспечивает предсказуемость представления финансовой информации в разных регионах и валютных контекстах.