-
-
Notifications
You must be signed in to change notification settings - Fork 150
[Intl] Add PHP 8.5 IntlListFormatter
to ICU polyfill
#532
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 1.x
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Polyfill\Intl\Icu; | ||
|
||
/** | ||
* A polyfill implementation of the IntlListFormatter class provided by the intl extension. | ||
* | ||
* @author Ayesh Karunaratne <[email protected]> | ||
* | ||
* @internal | ||
*/ | ||
class IntlListFormatter | ||
{ | ||
public const TYPE_AND = 0; | ||
public const TYPE_OR = 1; | ||
public const TYPE_UNITS = 2; | ||
|
||
public const WIDTH_WIDE = 0; | ||
public const WIDTH_SHORT = 1; | ||
public const WIDTH_NARROW = 2; | ||
|
||
/** | ||
* @var int | ||
*/ | ||
private $type; | ||
/** | ||
* @var int | ||
*/ | ||
private $width; | ||
|
||
private const EN_LIST_PATTERNS = [ | ||
'listPattern-type-standard' => [ | ||
'start' => '{0}, {1}', | ||
'middle' => '{0}, {1}', | ||
'end' => '{0}, and {1}', | ||
2 => '{0} and {1}', | ||
], | ||
'listPattern-type-or' => [ | ||
'start' => '{0}, {1}', | ||
'middle' => '{0}, {1}', | ||
'end' => '{0}, or {1}', | ||
2 => '{0} or {1}', | ||
], | ||
'listPattern-type-or-narrow' => [ | ||
'start' => '{0}, {1}', | ||
'middle' => '{0}, {1}', | ||
'end' => '{0}, or {1}', | ||
2 => '{0} or {1}', | ||
], | ||
'listPattern-type-or-short' => [ | ||
'start' => '{0}, {1}', | ||
'middle' => '{0}, {1}', | ||
'end' => '{0}, or {1}', | ||
2 => '{0} or {1}', | ||
], | ||
'listPattern-type-standard-narrow' => [ | ||
'start' => '{0}, {1}', | ||
'middle' => '{0}, {1}', | ||
'end' => '{0}, {1}', | ||
2 => '{0}, {1}', | ||
], | ||
'listPattern-type-standard-short' => [ | ||
'start' => '{0}, {1}', | ||
'middle' => '{0}, {1}', | ||
'end' => '{0}, & {1}', | ||
2 => '{0} & {1}', | ||
], | ||
'listPattern-type-unit' => [ | ||
'start' => '{0}, {1}', | ||
'middle' => '{0}, {1}', | ||
'end' => '{0}, {1}', | ||
2 => '{0}, {1}', | ||
], | ||
'listPattern-type-unit-narrow' => [ | ||
'start' => '{0} {1}', | ||
'middle' => '{0} {1}', | ||
'end' => '{0} {1}', | ||
2 => '{0} {1}', | ||
], | ||
'listPattern-type-unit-short' => [ | ||
'start' => '{0}, {1}', | ||
'middle' => '{0}, {1}', | ||
'end' => '{0}, {1}', | ||
2 => '{0}, {1}', | ||
], | ||
]; | ||
|
||
public function __construct( | ||
string $locale, | ||
int $type = self::TYPE_AND, | ||
int $width = self::WIDTH_WIDE | ||
) { | ||
$exceptionClass = PHP_VERSION_ID >= 80000 ? \ValueError::class : \InvalidArgumentException::class; | ||
if ($locale !== 'en' && strpos($locale, 'en') !== 0) { | ||
throw new $exceptionClass('Invalid locale, only "en" and "en-*" locales are supported'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have some mixed feelings about this. Since it's using the en-US set, for en-gb it would return a different result than the real class. |
||
} | ||
|
||
if ($type !== self::TYPE_AND && $type !== self::TYPE_OR && $type !== self::TYPE_UNITS) { | ||
throw new $exceptionClass('Argument #2 ($type) must be one of IntlListFormatter::TYPE_AND, IntlListFormatter::TYPE_OR, or IntlListFormatter::TYPE_UNITS.'); | ||
} | ||
|
||
if ($width !== self::WIDTH_WIDE && $width !== self::WIDTH_SHORT && $width !== self::WIDTH_NARROW) { | ||
throw new $exceptionClass('Argument #3 ($width) must be one of IntlListFormatter::WIDTH_WIDE, IntlListFormatter::WIDTH_SHORT, or IntlListFormatter::WIDTH_NARROW.'); | ||
} | ||
|
||
$this->type = $type; | ||
$this->width = $width; | ||
} | ||
|
||
public function format(array $strings): string | ||
{ | ||
$itemCount = count($strings); | ||
|
||
if ($itemCount === 0) { | ||
return ''; | ||
} | ||
|
||
$strings = array_values($strings); | ||
|
||
if ($itemCount === 1) { | ||
return (string) $strings[0]; | ||
} | ||
|
||
$pattern = $this->getListPattern(); | ||
|
||
switch ($this->type) { | ||
case self::TYPE_AND: | ||
$lookupKeyType = 'standard'; | ||
break; | ||
case self::TYPE_OR: | ||
$lookupKeyType = 'or'; | ||
break; | ||
case self::TYPE_UNITS: | ||
$lookupKeyType = 'unit'; | ||
break; | ||
} | ||
|
||
switch ($this->width) { | ||
case self::WIDTH_WIDE: | ||
$lookupKeyWidth = ''; | ||
break; | ||
case self::WIDTH_SHORT: | ||
$lookupKeyWidth = '-short'; | ||
break; | ||
case self::WIDTH_NARROW: | ||
$lookupKeyWidth = '-narrow'; | ||
break; | ||
} | ||
|
||
$pattern = $pattern['listPattern-type-' . $lookupKeyType . $lookupKeyWidth]; | ||
|
||
if ($itemCount === 2) { | ||
return strtr($pattern[2], ['{0}' => (string) $strings[0], '{1}' => (string) $strings[1]]); | ||
} | ||
|
||
if ($itemCount === 3) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could remove this case. It can be covered by the same code that for 4 items or more (the |
||
$start = strtr($pattern['start'], ['{0}' => (string) $strings[0], '{1}' => (string) $strings[1]]); | ||
return strtr($pattern['end'], ['{0}' => $start, '{1}' => (string) $strings[2]]); | ||
} | ||
|
||
$result = strtr($pattern['start'], ['{0}' => (string) $strings[0], '{1}' => (string) $strings[1]]); | ||
|
||
for ($i = 2; $i < $itemCount - 1; $i++) { | ||
$result = strtr($pattern["middle"], [ | ||
"{0}" => $result, | ||
"{1}" => $strings[$i], | ||
]); | ||
} | ||
|
||
return strtr($pattern["end"], [ | ||
"{0}" => $result, | ||
"{1}" => $strings[$itemCount - 1], | ||
]); | ||
} | ||
|
||
private function getListPattern(): array { | ||
return self::EN_LIST_PATTERNS; | ||
} | ||
|
||
public function getErrorCode(): int | ||
{ | ||
return 0; | ||
} | ||
|
||
public function getErrorMessage(): string | ||
{ | ||
return ''; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
final class IntlListFormatter extends Symfony\Polyfill\Intl\Icu\IntlListFormatter | ||
{ | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Polyfill\Tests\Intl\ListFormatter; | ||
|
||
use IntlListFormatter; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* @author Ayesh Karunaratne <[email protected]> | ||
* | ||
* @group class-polyfill | ||
*/ | ||
class IntlListFormatterTest extends TestCase | ||
{ | ||
public function testSupportedLocales() | ||
{ | ||
$this->expectNotToPerformAssertions(); | ||
new IntlListFormatter('en'); | ||
new IntlListFormatter('en-US'); | ||
new IntlListFormatter('en_US'); | ||
new IntlListFormatter('en-LK'); | ||
} | ||
|
||
public function testUnsupportedLocales() | ||
{ | ||
if (PHP_VERSION_ID >= 80000) { | ||
$this->expectException(\ValueError::class); | ||
} | ||
else { | ||
$this->expectException(\InvalidArgumentException::class); | ||
} | ||
|
||
new IntlListFormatter('ja'); | ||
} | ||
|
||
public function testUnsupportedType() | ||
{ | ||
if (PHP_VERSION_ID >= 80000) { | ||
$this->expectException(\ValueError::class); | ||
} | ||
else { | ||
$this->expectException(\InvalidArgumentException::class); | ||
} | ||
$this->expectExceptionMessage('must be one of IntlListFormatter::TYPE_AND, IntlListFormatter::TYPE_OR, or IntlListFormatter::TYPE_UNITS'); | ||
new IntlListFormatter('en', 42); | ||
} | ||
|
||
public function testUnsupportedWidth() | ||
{ | ||
if (PHP_VERSION_ID >= 80000) { | ||
$this->expectException(\ValueError::class); | ||
} | ||
else { | ||
$this->expectException(\InvalidArgumentException::class); | ||
} | ||
$this->expectExceptionMessage('must be one of IntlListFormatter::WIDTH_WIDE, IntlListFormatter::WIDTH_SHORT, or IntlListFormatter::WIDTH_NARROW'); | ||
new IntlListFormatter('en', IntlListFormatter::TYPE_AND, 42); | ||
} | ||
|
||
/** | ||
* @dataProvider formattingLists | ||
*/ | ||
public function testFormatting(int $type, int $wide, array $strings, string $expected) | ||
{ | ||
$formatter = new IntlListFormatter('en', $type, $wide); | ||
self::assertSame($expected, $formatter->format($strings)); | ||
} | ||
|
||
public function formattingLists() { | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE, [], '']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE, [1], '1']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry'], 'apple, banana, and strawberry']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry', 'orange'], 'apple, banana, strawberry, and orange']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple, banana, strawberry, orange, and 16']; | ||
|
||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT, [], '']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT, [1], '1']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry'], 'apple, banana, & strawberry']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry', 'orange'], 'apple, banana, strawberry, & orange']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple, banana, strawberry, orange, & 16']; | ||
|
||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW, [], '']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW, [1], '1']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW, ['apple', 'banana', 'strawberry'], 'apple, banana, strawberry']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW, ['apple', 'banana', 'strawberry', 'orange'], 'apple, banana, strawberry, orange']; | ||
yield [IntlListFormatter::TYPE_AND, IntlListFormatter::WIDTH_NARROW, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple, banana, strawberry, orange, 16']; | ||
|
||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE, [], '']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE, [1], '1']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry'], 'apple, banana, or strawberry']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry', 'orange'], 'apple, banana, strawberry, or orange']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple, banana, strawberry, orange, or 16']; | ||
|
||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT, [], '']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT, [1], '1']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry'], 'apple, banana, or strawberry']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry', 'orange'], 'apple, banana, strawberry, or orange']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple, banana, strawberry, orange, or 16']; | ||
|
||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW, [], '']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW, [1], '1']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW, ['apple', 'banana', 'strawberry', 'orange'], 'apple, banana, strawberry, or orange']; | ||
yield [IntlListFormatter::TYPE_OR, IntlListFormatter::WIDTH_NARROW, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple, banana, strawberry, orange, or 16']; | ||
|
||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE, [], '']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE, [1], '1']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry'], 'apple, banana, strawberry']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry', 'orange'], 'apple, banana, strawberry, orange']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_WIDE, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple, banana, strawberry, orange, 16']; | ||
|
||
|
||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT, [], '']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT, [1], '1']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry'], 'apple, banana, strawberry']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry', 'orange'], 'apple, banana, strawberry, orange']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_SHORT, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple, banana, strawberry, orange, 16']; | ||
|
||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW, [], '']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW, [1], '1']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW, ['1'], '1']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW, ['apple'], 'apple']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW, ['apple', 'banana', 'strawberry'], 'apple banana strawberry']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW, ['apple', 'banana', 'strawberry', 'orange'], 'apple banana strawberry orange']; | ||
yield [IntlListFormatter::TYPE_UNITS, IntlListFormatter::WIDTH_NARROW, ['apple', 'banana', 'strawberry', 'orange', 16], 'apple banana strawberry orange 16']; | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.