Skip to content

Commit c07b2ad

Browse files
committed
Add a MessageFormatter Phrase renderer
This gives us the ability to use ICU MessageFormatter formatting strings for better support of internationalization.
1 parent 19e9ada commit c07b2ad

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

app/code/Magento/Translation/etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<argument name="renderers" xsi:type="array">
4545
<item name="translation" xsi:type="object">Magento\Framework\Phrase\Renderer\Translate</item>
4646
<item name="placeholder" xsi:type="object">Magento\Framework\Phrase\Renderer\Placeholder</item>
47+
<item name="messageFormatter" xsi:type="object">Magento\Framework\Phrase\Renderer\MessageFormatter</item>
4748
<item name="inline" xsi:type="object">Magento\Framework\Phrase\Renderer\Inline</item>
4849
</argument>
4950
</arguments>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Magento\Framework\Phrase\Renderer;
4+
5+
use Magento\Framework\Phrase\RendererInterface;
6+
use Magento\Framework\TranslateInterface;
7+
8+
/**
9+
* Process texts to resolve ICU MessageFormat
10+
*/
11+
class MessageFormatter implements RendererInterface
12+
{
13+
/** @var TranslateInterface */
14+
private $translate;
15+
16+
/**
17+
* @param TranslateInterface $translate
18+
*/
19+
public function __construct(TranslateInterface $translate)
20+
{
21+
$this->translate = $translate;
22+
}
23+
24+
/**
25+
* @inheritDoc
26+
*/
27+
public function render(array $source, array $arguments)
28+
{
29+
$text = end($source);
30+
31+
if (strpos($text, '{') === false) {
32+
// Definitely nothing to process with MessageFormatter
33+
return $text;
34+
}
35+
36+
$result = \MessageFormatter::formatMessage($this->translate->getLocale(), $text, $arguments);
37+
38+
// Return $text if MessageFormatter fails (for backwards-compatibility)
39+
return $result !== false ? $result : $text;
40+
}
41+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace Magento\Framework\Phrase\Test\Unit\Renderer;
4+
5+
use Magento\Framework\Phrase\Renderer\MessageFormatter;
6+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
7+
use Magento\Framework\Translate;
8+
9+
class MessageFormatterTest extends \PHPUnit\Framework\TestCase
10+
{
11+
/** @var ObjectManager */
12+
private $objectManager;
13+
14+
protected function setUp()
15+
{
16+
$this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
17+
}
18+
19+
private function getMessageFormatter($locale)
20+
{
21+
$translateMock = $this->getMockBuilder(Translate::class)
22+
->disableOriginalConstructor()
23+
->setMethods(['getLocale'])
24+
->getMock();
25+
$translateMock->method('getLocale')
26+
->willReturn($locale);
27+
28+
return $this->objectManager->getObject(MessageFormatter::class, ['translate' => $translateMock]);
29+
}
30+
31+
/**
32+
* @param string $text The text with MessageFormat markers
33+
* @param string $locale
34+
* @param array $arguments The arguments supplying values for the variables
35+
* @param string $result The result of Phrase rendering
36+
*
37+
* @dataProvider renderMessageFormatterDataProvider
38+
*/
39+
public function testRenderMessageFormatter($text, $locale, array $arguments, $result)
40+
{
41+
$renderer = $this->getMessageFormatter($locale);
42+
43+
$this->assertEquals($result, $renderer->render([$text], $arguments));
44+
}
45+
46+
/**
47+
* @return array
48+
*/
49+
public function renderMessageFormatterDataProvider()
50+
{
51+
$twentynineteenJuneTwentyseven = new \DateTime('2019-06-27');
52+
53+
return [
54+
[
55+
'A table has {legs, plural, =0 {no legs} =1 {one leg} other {# legs}}.',
56+
'en_US',
57+
['legs' => 4],
58+
'A table has 4 legs.'
59+
],
60+
[
61+
'A table has {legs, plural, =0 {no legs} =1 {one leg} other {# legs}}.',
62+
'en_US',
63+
['legs' => 0],
64+
'A table has no legs.'
65+
],
66+
[
67+
'A table has {legs, plural, =0 {no legs} =1 {one leg} other {# legs}}.',
68+
'en_US',
69+
['legs' => 1],
70+
'A table has one leg.'
71+
],
72+
['The table costs {price, number, currency}.', 'en_US', ['price' => 23.4], 'The table costs $23.40.'],
73+
[
74+
'Today is {date, date, long}.',
75+
'en_US',
76+
['date' => $twentynineteenJuneTwentyseven],
77+
'Today is June 27, 2019.'
78+
],
79+
[
80+
'Today is {date, date, long}.',
81+
'ja_JP',
82+
['date' => $twentynineteenJuneTwentyseven],
83+
'Today is 2019年6月27日.'
84+
],
85+
];
86+
}
87+
}

lib/internal/Magento/Framework/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"ext-spl": "*",
2222
"ext-xsl": "*",
2323
"ext-bcmath": "*",
24+
"ext-intl": "*",
2425
"lib-libxml": "*",
2526
"colinmollenhour/php-redis-session-abstract": "~1.4.0",
2627
"composer/composer": "^1.6",

0 commit comments

Comments
 (0)