-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Translation] Added intl message formatter. #27399
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
Changes from 1 commit
940d440
19e8e69
c2b3dc0
b43fe21
a325a44
2aa7181
597a15d
f88153f
b1aa004
fb30c77
2a90931
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
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. AFAIK, we are not using this anywhere else, this should be removed. |
||
|
||
namespace Symfony\Component\Translation\Formatter; | ||
|
||
use Symfony\Component\Translation\Exception\LogicException; | ||
|
||
class FallbackFormatter implements MessageFormatterInterface, ChoiceMessageFormatterInterface | ||
{ | ||
/** | ||
* @var MessageFormatterInterface|ChoiceMessageFormatterInterface | ||
*/ | ||
private $firstFormatter; | ||
|
||
/** | ||
* @var MessageFormatterInterface|ChoiceMessageFormatterInterface | ||
*/ | ||
private $secondFormatter; | ||
|
||
public function __construct(MessageFormatterInterface $firstFormatter, MessageFormatterInterface $secondFormatter) | ||
{ | ||
$this->firstFormatter = $firstFormatter; | ||
$this->secondFormatter = $secondFormatter; | ||
} | ||
|
||
public function format($message, $locale, array $parameters = array()) | ||
{ | ||
try { | ||
$result = $this->firstFormatter->format($message, $locale, $parameters); | ||
} catch (\Throwable $e) { | ||
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. Can we be more specific here? We should be as much as possible IMHO (same below.) 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. Do we want to be more specific? 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 agree with @nicolas-grekas |
||
return $this->secondFormatter->format($message, $locale, $parameters); | ||
} | ||
|
||
if ($result === $message) { | ||
$result = $this->secondFormatter->format($message, $locale, $parameters); | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
public function choiceFormat($message, $number, $locale, array $parameters = array()) | ||
{ | ||
// If both support ChoiceMessageFormatterInterface | ||
if ($this->firstFormatter instanceof ChoiceMessageFormatterInterface && $this->secondFormatter instanceof ChoiceMessageFormatterInterface) { | ||
try { | ||
$result = $this->firstFormatter->choiceFormat($message, $number, $locale, $parameters); | ||
} catch (\Throwable $e) { | ||
return $this->secondFormatter->choiceFormat($message, $number, $locale, $parameters); | ||
} | ||
|
||
if ($result === $message) { | ||
$result = $this->secondFormatter->choiceFormat($message, $number, $locale, $parameters); | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
if ($this->firstFormatter instanceof ChoiceMessageFormatterInterface) { | ||
return $this->firstFormatter->choiceFormat($message, $number, $locale, $parameters); | ||
} | ||
|
||
if ($this->secondFormatter instanceof ChoiceMessageFormatterInterface) { | ||
return $this->secondFormatter->choiceFormat($message, $number, $locale, $parameters); | ||
} | ||
|
||
throw new LogicException(sprintf('The no formatter support plural translations.')); | ||
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. The message is not so clear to me :) I suppose you meant |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,8 @@ | |
|
||
namespace Symfony\Component\Translation\Formatter; | ||
|
||
use Symfony\Component\Translation\Exception\InvalidArgumentException; | ||
|
||
/** | ||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com> | ||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com> | ||
|
@@ -25,15 +27,12 @@ public function format($message, $locale, array $parameters = array()) | |
try { | ||
$formatter = new \MessageFormatter($locale, $message); | ||
} catch (\Throwable $e) { | ||
throw new \InvalidArgumentException('Invalid message format.', $e); | ||
} | ||
if (null === $formatter) { | ||
throw new \InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code())); | ||
throw new InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code()), 0, $e); | ||
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. As an exception should end with a dot, I suggest to use |
||
} | ||
|
||
$message = $formatter->format($parameters); | ||
if (U_ZERO_ERROR !== $formatter->getErrorCode()) { | ||
throw new \InvalidArgumentException(sprintf('Unable to format message. Reason: %s (error #%s)', $formatter->getErrorMessage(), $formatter->getErrorCode())); | ||
throw new InvalidArgumentException(sprintf('Unable to format message. Reason: %s (error #%s)', $formatter->getErrorMessage(), $formatter->getErrorCode())); | ||
} | ||
|
||
return $message; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Translation\Tests\Formatter; | ||
|
||
use Symfony\Component\Translation\Exception\InvalidArgumentException; | ||
use Symfony\Component\Translation\Exception\LogicException; | ||
use Symfony\Component\Translation\Formatter\ChoiceMessageFormatterInterface; | ||
use Symfony\Component\Translation\Formatter\FallbackFormatter; | ||
use Symfony\Component\Translation\Formatter\MessageFormatterInterface; | ||
|
||
class FallbackFormatterTest extends \PHPUnit\Framework\TestCase | ||
{ | ||
public function testFormatSame() | ||
{ | ||
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$first | ||
->expects($this->once()) | ||
->method('format') | ||
->with('foo', 'en', array(2)) | ||
->willReturn('foo'); | ||
|
||
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$second | ||
->expects($this->once()) | ||
->method('format') | ||
->with('foo', 'en', array(2)) | ||
->willReturn('bar'); | ||
|
||
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->format('foo', 'en', array(2))); | ||
} | ||
|
||
public function testFormatDifferent() | ||
{ | ||
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$first | ||
->expects($this->once()) | ||
->method('format') | ||
->with('foo', 'en', array(2)) | ||
->willReturn('new value'); | ||
|
||
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$second | ||
->expects($this->exactly(0)) | ||
->method('format') | ||
->withAnyParameters(); | ||
|
||
$this->assertEquals('new value', (new FallbackFormatter($first, $second))->format('foo', 'en', array(2))); | ||
} | ||
|
||
public function testFormatException() | ||
{ | ||
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$first | ||
->expects($this->once()) | ||
->method('format') | ||
->willThrowException(new InvalidArgumentException()); | ||
|
||
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$second | ||
->expects($this->once()) | ||
->method('format') | ||
->with('foo', 'en', array(2)) | ||
->willReturn('bar'); | ||
|
||
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->format('foo', 'en', array(2))); | ||
} | ||
|
||
public function testChoiceFormatSame() | ||
{ | ||
$first = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock(); | ||
$first | ||
->expects($this->once()) | ||
->method('choiceFormat') | ||
->with('foo', 1, 'en', array(2)) | ||
->willReturn('foo'); | ||
|
||
$second = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock(); | ||
$second | ||
->expects($this->once()) | ||
->method('choiceFormat') | ||
->with('foo', 1, 'en', array(2)) | ||
->willReturn('bar'); | ||
|
||
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2))); | ||
} | ||
|
||
public function testChoiceFormatDifferent() | ||
{ | ||
$first = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock(); | ||
$first | ||
->expects($this->once()) | ||
->method('choiceFormat') | ||
->with('foo', 1, 'en', array(2)) | ||
->willReturn('new value'); | ||
|
||
$second = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock(); | ||
$second | ||
->expects($this->exactly(0)) | ||
->method('choiceFormat') | ||
->withAnyParameters() | ||
->willReturn('bar'); | ||
|
||
$this->assertEquals('new value', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2))); | ||
} | ||
|
||
public function testChoiceFormatException() | ||
{ | ||
$first = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock(); | ||
$first | ||
->expects($this->once()) | ||
->method('choiceFormat') | ||
->willThrowException(new InvalidArgumentException()); | ||
|
||
$second = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock(); | ||
$second | ||
->expects($this->once()) | ||
->method('choiceFormat') | ||
->with('foo', 1, 'en', array(2)) | ||
->willReturn('bar'); | ||
|
||
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2))); | ||
} | ||
|
||
public function testChoiceFormatOnlyFirst() | ||
{ | ||
// Implements both interfaces | ||
$first = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock(); | ||
$first | ||
->expects($this->once()) | ||
->method('choiceFormat') | ||
->with('foo', 1, 'en', array(2)) | ||
->willReturn('bar'); | ||
|
||
// Implements only one interface | ||
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$second | ||
->expects($this->exactly(0)) | ||
->method('format') | ||
->withAnyParameters() | ||
->willReturn('error'); | ||
|
||
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2))); | ||
} | ||
|
||
public function testChoiceFormatOnlySecond() | ||
{ | ||
// Implements only one interface | ||
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$first | ||
->expects($this->exactly(0)) | ||
->method('format') | ||
->withAnyParameters() | ||
->willReturn('error'); | ||
|
||
// Implements both interfaces | ||
$second = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock(); | ||
$second | ||
->expects($this->once()) | ||
->method('choiceFormat') | ||
->with('foo', 1, 'en', array(2)) | ||
->willReturn('bar'); | ||
|
||
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2))); | ||
} | ||
|
||
public function testChoiceFormatNoChoiceFormat() | ||
{ | ||
// Implements only one interface | ||
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$first | ||
->expects($this->exactly(0)) | ||
->method('format'); | ||
|
||
// Implements both interfaces | ||
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock(); | ||
$second | ||
->expects($this->exactly(0)) | ||
->method('format'); | ||
|
||
$this->expectException(LogicException::class); | ||
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2))); | ||
} | ||
} | ||
|
||
interface SuperFormatterInterface extends MessageFormatterInterface, ChoiceMessageFormatterInterface | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing space after
and
.