Как форматировать проценты с символом процента

Используйте стиль percent в Intl.NumberFormat, чтобы отображать числа в виде процентов с форматированием, соответствующим локали

Введение

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

API Intl.NumberFormat в JavaScript автоматически обрабатывает эти различия в форматировании. Установив параметр style в значение "percent", вы получите правильно отформатированные проценты для любого региона без необходимости писать код для конкретного языка.

Почему форматирование процентов зависит от региона

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

Различия в форматировании касаются не только расположения знака. В некоторых регионах используются разные символы для обозначения процента. В арабском языке используется ٪ (U+066A) вместо стандартного знака процента ASCII. Разделители десятичных и тысячных также различаются в зависимости от региона, как и при обычном форматировании чисел.

Когда вы жестко задаете форматирование процентов с помощью объединения строк, вы заставляете всех пользователей видеть формат одного региона. Французский пользователь, видящий 50% вместо 50 %, сталкивается с неестественным форматом. Турецкий пользователь, видящий 50%, когда он ожидает %50, сталкивается с той же проблемой. API Intl решает эту проблему, применяя правильные правила форматирования для каждого региона.

Форматирование чисел в проценты

Опция style в Intl.NumberFormat определяет, будет ли число форматироваться как обычное число, валюта, процент или единица измерения. Установите style в значение "percent", чтобы форматировать числа как проценты.

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

console.log(formatter.format(0.75));
// Вывод: "75%"

console.log(formatter.format(0.05));
// Вывод: "5%"

console.log(formatter.format(1.5));
// Вывод: "150%"

Форматировщик автоматически умножает входное значение на 100 и добавляет знак процента. Это означает, что вы передаете дробные значения в форматировщик. Значение 0.75 становится 75%. Значение 1.5 становится 150%.

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

Понимание дробных входных значений

Форматировщик процентов ожидает дробные входные данные, где 1.0 представляет 100%. Этот выбор дизайна соответствует тому, как проценты рассчитываются в коде.

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

// Расчет процента завершения
const completed = 75;
const total = 100;
const ratio = completed / total;

console.log(formatter.format(ratio));
// Вывод: "75%"

// Расчет темпа роста
const oldValue = 1000;
const newValue = 1250;
const growth = (newValue - oldValue) / oldValue;

console.log(formatter.format(growth));
// Вывод: "25%"

Когда вы делите completed на total, вы получаете 0.75. Передайте это напрямую в форматировщик, и он отобразит 75%. Когда вы рассчитываете рост как отношение изменения к исходному значению, вы получаете 0.25. Форматировщик отображает это как 25%.

Этот подход предотвращает распространенную ошибку, когда разработчики умножают на 100 перед форматированием, что приводит к значениям вроде 7500% вместо 75%. Форматировщик выполняет умножение, поэтому вы работаете с естественным десятичным представлением в вашем коде.

Обработка значений вне диапазона 0-1

Проценты не ограничиваются значениями между 0% и 100%. Значения ниже нуля представляют отрицательные проценты. Значения выше 1.0 представляют проценты, превышающие 100%.

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

console.log(formatter.format(-0.15));
// Вывод: "-15%"

console.log(formatter.format(2.5));
// Вывод: "250%"

console.log(formatter.format(0.0025));
// Вывод: "0%"

Отрицательные значения форматируются с минусом. Это полезно для отображения уменьшений, убытков или отрицательных темпов роста. Значения больше 1.0 форматируются как проценты выше 100%, что часто используется для отображения роста по сравнению с предыдущим годом или сравнений, где новое значение превышает базовое.

Очень маленькие значения могут округляться до 0% из-за настроек точности по умолчанию. Значение 0.0025, которое представляет 0.25%, отображается как 0%, потому что максимальное количество дробных цифр для процентов по умолчанию равно 0. В следующем уроке рассматривается управление десятичными знаками для точного отображения таких меньших процентов.

Форматирование процентов в разных локалях

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

const enFormatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

console.log(enFormatter.format(0.5));
// Вывод: "50%"

const frFormatter = new Intl.NumberFormat("fr-FR", {
  style: "percent"
});

console.log(frFormatter.format(0.5));
// Вывод: "50 %"

const trFormatter = new Intl.NumberFormat("tr-TR", {
  style: "percent"
});

console.log(trFormatter.format(0.5));
// Вывод: "%50"

const arFormatter = new Intl.NumberFormat("ar-SA", {
  style: "percent"
});

console.log(arFormatter.format(0.5));
// Вывод: "٪50"

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

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

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

По умолчанию форматирование процентов не отображает десятичные знаки. Значение, например, 0.755, округляется и отображается как 76%. Вы можете управлять количеством десятичных знаков с помощью параметров minimumFractionDigits и maximumFractionDigits.

const defaultFormatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

console.log(defaultFormatter.format(0.755));
// Вывод: "76%"

const oneDecimalFormatter = new Intl.NumberFormat("en-US", {
  style: "percent",
  minimumFractionDigits: 1,
  maximumFractionDigits: 1
});

console.log(oneDecimalFormatter.format(0.755));
// Вывод: "75.5%"

const twoDecimalFormatter = new Intl.NumberFormat("en-US", {
  style: "percent",
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

console.log(twoDecimalFormatter.format(0.755));
// Вывод: "75.50%"

Параметр minimumFractionDigits гарантирует, что форматер отображает как минимум указанное количество десятичных знаков, добавляя нули, если это необходимо. Параметр maximumFractionDigits ограничивает количество десятичных знаков, округляя значение при необходимости.

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

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

Комбинирование процентов с отображением знаков

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

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

console.log(formatter.format(0.0523));
// Вывод: "+5.2%"

console.log(formatter.format(-0.0341));
// Вывод: "-3.4%"

console.log(formatter.format(0));
// Вывод: "+0.0%"

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

Форматирование нуля в виде процента

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

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

console.log(formatter.format(0));
// Вывод: "0%"

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

console.log(withSignFormatter.format(0.05));
// Вывод: "+5%"

console.log(withSignFormatter.format(0));
// Вывод: "0%"

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

Когда использовать форматирование в виде процентов

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

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

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

Понимание точности форматирования процентов

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

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

console.log(formatter.format(0.755));
// Вывод: "76%"

console.log(formatter.format(0.754));
// Вывод: "75%"

console.log(formatter.format(0.001));
// Вывод: "0%"

Значения округляются до ближайшего целого процента. Значение 0.755 округляется до 76%. Значение 0.754 округляется до 75%. Очень маленькие значения, такие как 0.001, округляются до 0%.

Если вам нужно отображать малые проценты или дробные проценты, увеличьте максимальное количество дробных знаков. Следующий урок подробно рассматривает управление точностью.