Skip to content

Commit

Permalink
Update Number::forHumans helper to support pluralized localization
Browse files Browse the repository at this point in the history
I just want to preface this with saying that language is complex. Like really complex. It's doubtful that a relatively short and simple method can contain all the edge cases needed for full support of something as complex as this. I totally understand if this is not something that's worth merging, but I wanted to try it out so here it is. We can always revert the commit.
  • Loading branch information
caendesilva committed Nov 23, 2023
1 parent c3b7ba1 commit 97b1b0a
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 9 deletions.
18 changes: 9 additions & 9 deletions src/Illuminate/Support/Number.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,27 +143,27 @@ public static function fileSize(int|float $bytes, int $precision = 0, ?int $maxP
*/
public static function forHumans(int|float $number, int $precision = 0, ?int $maxPrecision = null, ?string $locale = null)
{
$units = [
3 => __('thousand', locale: $locale ?? static::$locale),
6 => __('million', locale: $locale ?? static::$locale),
9 => __('billion', locale: $locale ?? static::$locale),
12 => __('trillion', locale: $locale ?? static::$locale),
15 => __('quadrillion', locale: $locale ?? static::$locale),
];

switch (true) {
case $number === 0:
return '0';
case $number < 0:
return sprintf('-%s', static::forHumans(abs($number), $precision, $maxPrecision, $locale));
case $number >= 1e15:
return sprintf('%s %s', static::forHumans($number / 1e15, $precision, $maxPrecision, $locale), __('quadrillion', locale: $locale ?? static::$locale));
return sprintf('%s %s', static::forHumans($number = $number / 1e15, $precision, $maxPrecision, $locale), trans_choice('quadrillion', $number, locale: $locale ?? static::$locale));
}

$numberExponent = floor(log10($number));
$displayExponent = $numberExponent - ($numberExponent % 3);
$number /= pow(10, $displayExponent);

$units = [
3 => trans_choice('thousand', $number, locale: $locale ?? static::$locale),
6 => trans_choice('million', $number, locale: $locale ?? static::$locale),
9 => trans_choice('billion', $number, locale: $locale ?? static::$locale),
12 => trans_choice('trillion', $number, locale: $locale ?? static::$locale),
15 => trans_choice('quadrillion', $number, locale: $locale ?? static::$locale),
];

return trim(sprintf('%s %s', static::format($number, $precision, $maxPrecision, $locale), $units[$displayExponent] ?? ''));
}

Expand Down
33 changes: 33 additions & 0 deletions tests/Support/SupportNumberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,39 @@ public function testToHumansWithLocalization()
$this->assertSame('1,23 miljon', Number::forHumans(1234567, locale: 'sv', precision: 2));
}

public function testToHumansWithPluralizedLocalization()
{
$this->mockTranslator();

app('translator')->setLoaded([
'*' => [
'*' => [
'sv' => [
'thousand' => 'tusen',
'million' => 'miljon|miljoner',
'billion' => 'miljard|miljarder',
'trillion' => 'biljon|biljoner',
'quadrillion' => 'biljard|biljarder',
],
],
],
]);

$this->assertSame('1 tusen', Number::forHumans(1000, locale: 'sv'));
$this->assertSame('10 tusen', Number::forHumans(10000, locale: 'sv'));
$this->assertSame('1 miljon', Number::forHumans(1000000, locale: 'sv'));
$this->assertSame('1 miljard', Number::forHumans(1000000000, locale: 'sv'));
$this->assertSame('1 biljon', Number::forHumans(1000000000000, locale: 'sv'));
$this->assertSame('1 biljard', Number::forHumans(1000000000000000, locale: 'sv'));

$this->assertSame('1,23 miljoner', Number::forHumans(1234567, locale: 'sv', precision: 2));
$this->assertSame('10 miljoner', Number::forHumans(10000000, locale: 'sv'));
$this->assertSame('10 miljarder', Number::forHumans(10000000000, locale: 'sv'));
$this->assertSame('10 biljoner', Number::forHumans(10000000000000, locale: 'sv'));
$this->assertSame('1 tusen biljarder', Number::forHumans(1000000000000000000, locale: 'sv')); $this->assertSame('10 tusen biljarder', Number::forHumans(10000000000000000000, locale: 'sv'));
$this->assertSame('10 tusen biljarder', Number::forHumans(10000000000000000000, locale: 'sv')); $this->assertSame('10 tusen biljarder', Number::forHumans(10000000000000000000, locale: 'sv'));
}

protected function mockTranslator(): void
{
app()->singleton('translator', fn () => new Translator(new ArrayLoader(), 'en'));
Expand Down

0 comments on commit 97b1b0a

Please sign in to comment.