setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $maxPrecision); } elseif (! is_null($precision)) { $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); } return $formatter->format($number); } /** * Spell out the given number in the given locale. * * @param int|float $number * @param string|null $locale * @param int|null $after * @param int|null $until * @return string */ public static function spell(int|float $number, ?string $locale = null, ?int $after = null, ?int $until = null) { static::ensureIntlExtensionIsInstalled(); if (! is_null($after) && $number <= $after) { return static::format($number, locale: $locale); } if (! is_null($until) && $number >= $until) { return static::format($number, locale: $locale); } $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::SPELLOUT); return $formatter->format($number); } /** * Convert the given number to ordinal form. * * @param int|float $number * @param string|null $locale * @return string */ public static function ordinal(int|float $number, ?string $locale = null) { static::ensureIntlExtensionIsInstalled(); $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::ORDINAL); return $formatter->format($number); } /** * Convert the given number to its percentage equivalent. * * @param int|float $number * @param int $precision * @param int|null $maxPrecision * @param string|null $locale * @return string|false */ public static function percentage(int|float $number, int $precision = 0, ?int $maxPrecision = null, ?string $locale = null) { static::ensureIntlExtensionIsInstalled(); $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::PERCENT); if (! is_null($maxPrecision)) { $formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $maxPrecision); } else { $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $precision); } return $formatter->format($number / 100); } /** * Convert the given number to its currency equivalent. * * @param int|float $number * @param string $in * @param string|null $locale * @return string|false */ public static function currency(int|float $number, string $in = 'USD', ?string $locale = null) { static::ensureIntlExtensionIsInstalled(); $formatter = new NumberFormatter($locale ?? static::$locale, NumberFormatter::CURRENCY); return $formatter->formatCurrency($number, $in); } /** * Convert the given number to its file size equivalent. * * @param int|float $bytes * @param int $precision * @param int|null $maxPrecision * @return string */ public static function fileSize(int|float $bytes, int $precision = 0, ?int $maxPrecision = null) { $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; for ($i = 0; ($bytes / 1024) > 0.9 && ($i < count($units) - 1); $i++) { $bytes /= 1024; } return sprintf('%s %s', static::format($bytes, $precision, $maxPrecision), $units[$i]); } /** * Convert the number to its human-readable equivalent. * * @param int|float $number * @param int $precision * @param int|null $maxPrecision * @return bool|string */ public static function abbreviate(int|float $number, int $precision = 0, ?int $maxPrecision = null) { return static::forHumans($number, $precision, $maxPrecision, abbreviate: true); } /** * Convert the number to its human-readable equivalent. * * @param int|float $number * @param int $precision * @param int|null $maxPrecision * @param bool $abbreviate * @return bool|string */ public static function forHumans(int|float $number, int $precision = 0, ?int $maxPrecision = null, bool $abbreviate = false) { return static::summarize($number, $precision, $maxPrecision, $abbreviate ? [ 3 => 'K', 6 => 'M', 9 => 'B', 12 => 'T', 15 => 'Q', ] : [ 3 => ' thousand', 6 => ' million', 9 => ' billion', 12 => ' trillion', 15 => ' quadrillion', ]); } /** * Convert the number to its human-readable equivalent. * * @param int|float $number * @param int $precision * @param int|null $maxPrecision * @param array $units * @return string|false */ protected static function summarize(int|float $number, int $precision = 0, ?int $maxPrecision = null, array $units = []) { if (empty($units)) { $units = [ 3 => 'K', 6 => 'M', 9 => 'B', 12 => 'T', 15 => 'Q', ]; } switch (true) { case floatval($number) === 0.0: return $precision > 0 ? static::format(0, $precision, $maxPrecision) : '0'; case $number < 0: return sprintf('-%s', static::summarize(abs($number), $precision, $maxPrecision, $units)); case $number >= 1e15: return sprintf('%s'.end($units), static::summarize($number / 1e15, $precision, $maxPrecision, $units)); } $numberExponent = floor(log10($number)); $displayExponent = $numberExponent - ($numberExponent % 3); $number /= pow(10, $displayExponent); return trim(sprintf('%s%s', static::format($number, $precision, $maxPrecision), $units[$displayExponent] ?? '')); } /** * Clamp the given number between the given minimum and maximum. * * @param int|float $number * @param int|float $min * @param int|float $max * @return int|float */ public static function clamp(int|float $number, int|float $min, int|float $max) { return min(max($number, $min), $max); } /** * Execute the given callback using the given locale. * * @param string $locale * @param callable $callback * @return mixed */ public static function withLocale(string $locale, callable $callback) { $previousLocale = static::$locale; static::useLocale($locale); return tap($callback(), fn () => static::useLocale($previousLocale)); } /** * Set the default locale. * * @param string $locale * @return void */ public static function useLocale(string $locale) { static::$locale = $locale; } /** * Ensure the "intl" PHP extension is installed. * * @return void */ protected static function ensureIntlExtensionIsInstalled() { if (! extension_loaded('intl')) { $method = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function']; throw new RuntimeException('The "intl" PHP extension is required to use the ['.$method.'] method.'); } } }