Как управлять плюсами и минусами при форматировании валюты

Используйте опцию signDisplay, чтобы показывать или скрывать плюсы и минусы при форматировании сумм в валюте на JavaScript

Введение

Когда вы показываете сумму транзакции, например $500, в банковском приложении, пользователи не могут понять, это пополнение или списание. Отсутствие плюса или минуса создает неясность. Если отображать +$500 или -$500, направление операции становится очевидным.

Финансовым приложениям важно точно контролировать, как отображаются знаки у сумм в валюте. В истории транзакций пополнения и списания показываются с явными знаками. В отчетах о прибыли и убытках прирост и потери отмечаются четкими плюсами и минусами. Изменения баланса счета должны сопровождаться видимыми знаками, чтобы было понятно, поступили деньги или ушли. В JavaScript Intl.NumberFormat предоставляет опцию signDisplay, чтобы точно управлять появлением плюсов и минусов при форматировании валюты.

Как по умолчанию форматируется валюта

По умолчанию Intl.NumberFormat показывает минус для отрицательных сумм и не показывает знак для положительных.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD"
});

console.log(formatter.format(250.50));
// Output: "$250.50"

console.log(formatter.format(-75.25));
// Output: "-$75.25"

console.log(formatter.format(0));
// Output: "$0.00"

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

Управление знаками валюты с помощью signDisplay

Опция signDisplay определяет, когда плюсы и минусы будут показаны при форматировании валюты. Передайте эту опцию при создании форматтера чисел для валюты.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "always"
});

console.log(formatter.format(250.50));
// Output: "+$250.50"

console.log(formatter.format(-75.25));
// Output: "-$75.25"

Теперь положительные суммы отображаются с плюсом, и пополнения или доходы становятся явно видны, а не подразумеваются.

Понимание значений signDisplay для валюты

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

Значение auto для стандартного форматирования валюты

Значение "auto" используется по умолчанию. Оно показывает минус для отрицательных сумм, но не отображает знак для положительных.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "auto"
});

console.log(formatter.format(1000));
// Output: "$1,000.00"

console.log(formatter.format(-500));
// Output: "-$500.00"

console.log(formatter.format(0));
// Output: "$0.00"

Используйте "auto" для отображения цен, балансов счетов и других абсолютных валютных значений, где важно выделять отрицательные суммы, а положительные считаются стандартными.

Значение always для отображения всех направлений операций

Значение "always" показывает знаки для всех сумм: положительных, отрицательных и нуля.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "always"
});

console.log(formatter.format(1000));
// Output: "+$1,000.00"

console.log(formatter.format(-500));
// Output: "-$500.00"

console.log(formatter.format(0));
// Output: "+$0.00"

Используйте "always" для истории транзакций, отчётов о прибылях и убытках, а также лент активности по счету, где важно направление движения средств для каждой записи. Явный плюс подчёркивает, что положительные суммы — это депозиты, прибыль или поступления.

Значение exceptZero для выделения реальных изменений

Значение "exceptZero" показывает знаки для положительных и отрицательных сумм, но не отображает знак для нуля.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "exceptZero"
});

console.log(formatter.format(1000));
// Output: "+$1,000.00"

console.log(formatter.format(-500));
// Output: "-$500.00"

console.log(formatter.format(0));
// Output: "$0.00"

Используйте "exceptZero" для отображения изменений баланса, где ноль означает отсутствие изменений. Это делает ноль визуально отличимым от реальных прибылей или убытков. Торговые платформы и инвестиционные приложения используют этот формат для показа изменений цен и стоимости портфеля.

Значение negative для акцента на долгах

Значение "negative" показывает минус только для отрицательных сумм, исключая отрицательный ноль. Положительные суммы и ноль отображаются без знаков.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "negative"
});

console.log(formatter.format(1000));
// Output: "$1,000.00"

console.log(formatter.format(-500));
// Output: "-$500.00"

console.log(formatter.format(0));
// Output: "$0.00"

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

never — значение для отображения абсолютных сумм

Значение "never" показывает суммы в валюте без каких-либо знаков, даже для отрицательных значений.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "never"
});

console.log(formatter.format(1000));
// Output: "$1,000.00"

console.log(formatter.format(-500));
// Output: "$500.00"

console.log(formatter.format(0));
// Output: "$0.00"

Используйте "never" для отображения абсолютных сумм, когда направление указывается другими способами. Например, если в списке транзакций используются отдельные столбцы для дебета и кредита или цветовое кодирование для положительных и отрицательных значений, отсутствие знака избавляет от избыточной информации.

Комбинирование signDisplay с бухгалтерским стилем

Форматирование валюты поддерживает бухгалтерское обозначение, при котором отрицательные суммы отображаются в скобках. Установите currencySign в "accounting", чтобы включить этот формат.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencySign: "accounting"
});

console.log(formatter.format(1000));
// Output: "$1,000.00"

console.log(formatter.format(-500));
// Output: "($500.00)"

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

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

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencySign: "accounting",
  signDisplay: "always"
});

console.log(formatter.format(1000));
// Output: "+$1,000.00"

console.log(formatter.format(-500));
// Output: "($500.00)"

console.log(formatter.format(0));
// Output: "+$0.00"

С signDisplay: "always" положительные суммы отображаются со знаком плюс, а отрицательные по-прежнему заключаются в скобки. Такой формат отлично подходит для отчетов о прибылях и убытках, где важно четко различать доходы и потери.

С signDisplay: "exceptZero" ноль отображается без знака, а положительные и отрицательные суммы используют свои индикаторы.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencySign: "accounting",
  signDisplay: "exceptZero"
});

console.log(formatter.format(1000));
// Output: "+$1,000.00"

console.log(formatter.format(-500));
// Output: "($500.00)"

console.log(formatter.format(0));
// Output: "$0.00"

Такое сочетание выделяет реальные изменения, делая ноль визуально нейтральным.

Как signDisplay работает с режимами отображения валюты

Форматирование валюты поддерживает три режима отображения самой валюты. Опция currencyDisplay определяет, показывать ли валюту как символ, код или название.

Опция signDisplay работает одинаково во всех режимах отображения валюты.

const symbol = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "symbol",
  signDisplay: "always"
});

console.log(symbol.format(100));
// Output: "+$100.00"

const code = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "code",
  signDisplay: "always"
});

console.log(code.format(100));
// Output: "+USD 100.00"

const name = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "name",
  signDisplay: "always"
});

console.log(name.format(100));
// Output: "+100.00 US dollars"

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

Положение знака зависит от локали

В разных локалях знак размещается по-разному относительно символа валюты. JavaScript автоматически учитывает эти особенности для каждой локали.

const enUS = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "always"
});

console.log(enUS.format(100));
// Output: "+$100.00"

console.log(enUS.format(-100));
// Output: "-$100.00"

const frFR = new Intl.NumberFormat("fr-FR", {
  style: "currency",
  currency: "EUR",
  signDisplay: "always"
});

console.log(frFR.format(100));
// Output: "+100,00 €"

console.log(frFR.format(-100));
// Output: "-100,00 €"

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

В некоторых локалях отрицательные знаки размещаются иначе, чем положительные, даже при использовании signDisplay: "always".

const nlNL = new Intl.NumberFormat("nl-NL", {
  style: "currency",
  currency: "EUR",
  signDisplay: "always"
});

console.log(nlNL.format(100));
// Output: "+€ 100,00"

console.log(nlNL.format(-100));
// Output: "-€ 100,00"

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

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

В разных финансовых ситуациях нужны разные стратегии отображения знака.

Истории транзакций

Банковские приложения и платёжные платформы показывают списки транзакций, где каждая запись отражает движение денег. Используйте signDisplay: "always", чтобы явно указывать направление каждой транзакции.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "always"
});

const transactions = [
  { description: "Salary deposit", amount: 3500 },
  { description: "Rent payment", amount: -1200 },
  { description: "Grocery store", amount: -85.50 },
  { description: "Refund", amount: 25 }
];

transactions.forEach(transaction => {
  console.log(`${transaction.description}: ${formatter.format(transaction.amount)}`);
});
// Output:
// Salary deposit: +$3,500.00
// Rent payment: -$1,200.00
// Grocery store: -$85.50
// Refund: +$25.00

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

Отчёты о прибылях и убытках

В финансовых отчётах прибыль и убытки показываются с чёткими положительными и отрицательными индикаторами. Используйте signDisplay: "always" с бухгалтерским форматом для профессиональных финансовых документов.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  currencySign: "accounting",
  signDisplay: "always"
});

const financials = {
  revenue: 150000,
  expenses: -95000,
  netIncome: 55000
};

console.log(`Revenue: ${formatter.format(financials.revenue)}`);
// Output: Revenue: +$150,000.00

console.log(`Expenses: ${formatter.format(financials.expenses)}`);
// Output: Expenses: ($95,000.00)

console.log(`Net Income: ${formatter.format(financials.netIncome)}`);
// Output: Net Income: +$55,000.00

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

Индикаторы изменения баланса

Инвестиционные платформы и трейдинговые приложения показывают, как менялась стоимость счёта со временем. Используйте signDisplay: "exceptZero", чтобы выделить реальные изменения, а отсутствие изменений сделать визуально нейтральным.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "exceptZero"
});

const changes = [
  { period: "Today", change: 125.50 },
  { period: "This week", change: -45.75 },
  { period: "This month", change: 0 },
  { period: "This year", change: 1850 }
];

changes.forEach(item => {
  console.log(`${item.period}: ${formatter.format(item.change)}`);
});
// Output:
// Today: +$125.50
// This week: -$45.75
// This month: $0.00
// This year: +$1,850.00

Ноль отображается без знака, что выделяет этот период как время без изменений.

Остатки на счетах

Банковские приложения показывают текущие остатки на счетах: отрицательные значения означают перерасход. Используйте signDisplay: "negative", чтобы выделить долги, а положительные остатки отображайте как обычные.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "negative"
});

const accounts = [
  { name: "Checking", balance: 2500 },
  { name: "Savings", balance: 15000 },
  { name: "Credit Card", balance: -850 }
];

accounts.forEach(account => {
  console.log(`${account.name}: ${formatter.format(account.balance)}`);
});
// Output:
// Checking: $2,500.00
// Savings: $15,000.00
// Credit Card: -$850.00

Минус привлекает внимание к отрицательному балансу, а положительные остатки отображаются без знака.

Абсолютные разницы цен

В шопинг-приложениях и сервисах сравнения цен показывается, насколько отличаются цены между вариантами. Используйте signDisplay: "never", чтобы отображать абсолютные разницы цен, когда направление не важно.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "never"
});

const comparisons = [
  { item: "Laptop A vs B", difference: -150 },
  { item: "Phone X vs Y", difference: 75 },
  { item: "Tablet M vs N", difference: -25 }
];

comparisons.forEach(comp => {
  console.log(`${comp.item}: ${formatter.format(comp.difference)} difference`);
});
// Output:
// Laptop A vs B: $150.00 difference
// Phone X vs Y: $75.00 difference
// Tablet M vs N: $25.00 difference

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

Комбинирование signDisplay с точностью десятичных знаков

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

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "always",
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

console.log(formatter.format(1234.5));
// Output: "+$1,234.50"

console.log(formatter.format(-89.1));
// Output: "-$89.10"

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

Можно также комбинировать signDisplay с минимальным и максимальным количеством значимых цифр для научных или финансовых расчетов.

const formatter = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "always",
  minimumSignificantDigits: 3,
  maximumSignificantDigits: 3
});

console.log(formatter.format(1234.567));
// Output: "+$1,230"

console.log(formatter.format(-0.0456));
// Output: "-$0.0456"

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

Что важно помнить

Опция signDisplay в Intl.NumberFormat управляет тем, когда плюсы и минусы появляются в отформатированных суммах. Используйте "always", чтобы явно показывать знаки для всех сумм, "exceptZero" чтобы скрывать знак у нуля, "auto" для стандартного поведения, "negative" чтобы показывать только минусы, и "never" чтобы скрывать все знаки.

Выбирайте подходящее значение signDisplay в зависимости от вашего финансового контекста. В истории транзакций для всех сумм нужны явные знаки. Для индикаторов изменения баланса полезно делать ноль визуально нейтральным. Для баланса счета удобно выделять только отрицательные значения. При сравнении цен часто нужны абсолютные значения без знаков.

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