В экосистеме FormatJS работа с процентными значениями основана на
стандарте Intl.NumberFormat, который предоставляет нативные
возможности локализованного форматирования чисел в JavaScript. Основной
механизм заключается в использовании опции
style: 'percent', при которой входное число
интерпретируется как доля единицы и автоматически масштабируется.
Ключевая особенность: значение 1 соответствует
100%, а не 1%.
Это фундаментальное правило влияет на всю логику обработки данных:
0.15 → 15%1 → 100%1.2 → 120%0.003 → 0.3%const formatter = new Intl.NumberFormat('ru-RU', {
style: 'percent'
});
formatter.format(0.15); // "15 %"
В различных локалях формат может отличаться: пробел перед символом процента, позиция символа и правила округления определяются стандартами CLDR, которые использует FormatJS.
В библиотеке FormatJS чаще всего процентные значения используются
через компонент FormattedNumber.
import { FormattedNumber } from 'react-intl';
<FormattedNumber
value={0.42}
style="percent"
/>
Результат будет локализован автоматически:
en-US → 42%fr-FR → 42 %de-DE → 42 %При этом не требуется ручное управление символами или форматированием — вся логика делегируется ICU и Intl API.
Наиболее частая ошибка при работе с процентами — двойное масштабирование значения.
Если данные уже представлены в процентах (например, 15
означает 15%), а затем применяется style: 'percent',
результат будет некорректным:
// Ошибка интерпретации
formatter.format(15); // 1500%
Правильный подход зависит от источника данных:
const normalizePercent = (value) => value / 100;
formatter.format(normalizePercent(15)); // 15%
FormatJS опирается на настройки minimumFractionDigits и
maximumFractionDigits, которые позволяют контролировать
отображение дробных процентов.
const formatter = new Intl.NumberFormat('ru-RU', {
style: 'percent',
maximumFractionDigits: 1
});
formatter.format(0.1234); // "12,3 %"
Особенности округления:
В FormatJS процентные значения могут быть встроены в ICU-сообщения, что особенно важно для интернационализации интерфейсов.
const messages = {
completion: 'Прогресс: {value, number, percent}'
};
Использование:
<FormattedMessage
id="completion"
values={{ value: 0.78 }}
/>
Здесь 0.78 автоматически преобразуется в 78% согласно
локали пользователя.
Разные локали не только меняют формат, но и влияют на визуальное представление:
, или .)%Примеры:
en-US: 75%fr-FR: 75 %ar-EG: ٧٥٪FormatJS не требует ручной обработки этих различий, так как использует данные CLDR.
При частом обновлении значений (например, прогресс-бар, загрузка, аналитика) важно учитывать производительность форматирования.
Рекомендации:
Intl.NumberFormat при каждом
рендереconst percentFormatter = new Intl.NumberFormat('ru-RU', {
style: 'percent'
});
FormatJS хорошо интегрируется с TypeScript, особенно при
использовании react-intl.
import { FormattedNumber } from 'react-intl';
type Props = {
value: number;
};
function Progress({ value }: Props) {
return <FormattedNumber value={value} style="percent" />;
}
Типизация помогает избежать передачи строк вместо чисел, что критично для корректного форматирования.
Процентные значения часто используются в:
Важно разделять:
FormatJS отвечает только за последний слой — визуализацию, не вмешиваясь в бизнес-логику.
Отрицательные значения также корректно форматируются:
formatter.format(-0.12); // "-12 %"
Такие значения часто используются для:
Локализация сохраняется и для отрицательных чисел, включая позицию минуса и пробелы.
FormatJS учитывает пользовательскую локаль, которая может динамически
меняться. При изменении locale формат процентов
пересоздаётся автоматически в контексте IntlProvider.
<IntlProvider locale="ru">
<App />
</IntlProvider>
Смена локали приводит к:
Процентный стиль тесно связан с другими режимами форматирования:
decimal — обычные числаcurrency — денежные значенияunit — физические единицыnew Intl.NumberFormat('ru-RU', {
style: 'decimal'
});
new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB'
});
new Intl.NumberFormat('ru-RU', {
style: 'percent'
});
Каждый стиль использует общую инфраструктуру, но различается правилами масштабирования и символикой.