Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit daaceb0

Browse files
committed
Use FallbackFormatter instead of support for multiple formatters
1 parent c5a4f86 commit daaceb0

File tree

12 files changed

+303
-82
lines changed

12 files changed

+303
-82
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ CHANGELOG
1111
* Deprecated the `Symfony\Bundle\FrameworkBundle\Controller\Controller` class in favor of `Symfony\Bundle\FrameworkBundle\Controller\AbstractController`.
1212
* Enabled autoconfiguration for `Psr\Log\LoggerAwareInterface`
1313
* Added new "auto" mode for `framework.session.cookie_secure` to turn it on when HTTPS is used
14-
* Added support for configuring the `Translator` with multiple formatters.
1514

1615
4.1.0
1716
-----

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -690,27 +690,14 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode)
690690
->{!class_exists(FullStack::class) && class_exists(Translator::class) ? 'canBeDisabled' : 'canBeEnabled'}()
691691
->fixXmlConfig('fallback')
692692
->fixXmlConfig('path')
693-
->fixXmlConfig('domain_formatter')
694693
->children()
695694
->arrayNode('fallbacks')
696695
->beforeNormalization()->ifString()->then(function ($v) { return array($v); })->end()
697696
->prototype('scalar')->end()
698697
->defaultValue(array('en'))
699698
->end()
700699
->booleanNode('logging')->defaultValue(false)->end()
701-
->scalarNode('formatter')
702-
->info('The default formatter to use if none is specified.')
703-
->defaultValue('translator.formatter.default')
704-
->end()
705-
->arrayNode('domain_formatters')
706-
->info('Configure different formatters per domain.')
707-
->useAttributeAsKey('domain')
708-
->prototype('array')
709-
->children()
710-
->scalarNode('service')->cannotBeEmpty()->end()
711-
->end()
712-
->end()
713-
->end()
700+
->scalarNode('formatter')->defaultValue('translator.formatter.default')->end()
714701
->scalarNode('default_path')
715702
->info('The default path used to load translations')
716703
->defaultValue('%kernel.project_dir%/translations')

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -981,9 +981,6 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
981981
$container->setAlias('translator.formatter', new Alias($config['formatter'], false));
982982
$translator = $container->findDefinition('translator.default');
983983
$translator->addMethodCall('setFallbackLocales', array($config['fallbacks']));
984-
foreach ($config['domain_formatters'] as $formatter) {
985-
$translator->addMethodCall('addFormatter', array($formatter['domain'], new Reference($formatter['service'])));
986-
}
987984

988985
$container->setParameter('translator.logging', $config['logging']);
989986
$container->setParameter('translator.default_path', $config['default_path']);

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,19 +185,13 @@
185185
<xsd:sequence>
186186
<xsd:element name="fallback" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
187187
<xsd:element name="path" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
188-
<xsd:element name="domain-formatter" type="translator_formatter" minOccurs="0" maxOccurs="unbounded" />
189188
</xsd:sequence>
190189
<xsd:attribute name="enabled" type="xsd:boolean" />
191190
<xsd:attribute name="fallback" type="xsd:string" />
192191
<xsd:attribute name="logging" type="xsd:boolean" />
193192
<xsd:attribute name="formatter" type="xsd:string" />
194193
</xsd:complexType>
195194

196-
<xsd:complexType name="translator_formatter">
197-
<xsd:attribute name="domain" type="xsd:string" use="required" />
198-
<xsd:attribute name="service" type="xsd:string" />
199-
</xsd:complexType>
200-
201195
<xsd:complexType name="validation">
202196
<xsd:choice minOccurs="0" maxOccurs="unbounded">
203197
<xsd:element name="static-method" type="xsd:string" />

src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@
2929
<tag name="monolog.logger" channel="translation" />
3030
</service>
3131

32-
<service id="translator.formatter.default" class="Symfony\Component\Translation\Formatter\MessageFormatter">
32+
<service id="translator.formatter.symfony" class="Symfony\Component\Translation\Formatter\MessageFormatter">
3333
<argument type="service" id="identity_translator" />
3434
</service>
35-
3635
<service id="translator.formatter.intl" class="Symfony\Component\Translation\Formatter\IntlMessageFormatter" public="false" />
37-
38-
<service id="translator.selector" class="Symfony\Component\Translation\MessageSelector" public="false" />
36+
<service id="translator.formatter.fallback" class="Symfony\Component\Translation\Formatter\FallbackFormatter" public="false">
37+
<argument type="service" id="translator.formatter.intl" />
38+
<argument type="service" id="translator.formatter.symfony" />
39+
</service>
40+
<service id="translator.formatter.default" alias="translator.formatter.fallback" />
3941

4042
<service id="translation.loader.php" class="Symfony\Component\Translation\Loader\PhpFileLoader">
4143
<tag name="translation.loader" alias="php" />

src/Symfony/Component/Translation/CHANGELOG.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ CHANGELOG
77
* Started using ICU parent locales as fallback locales.
88
* deprecated `TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`
99
* deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead
10-
* Added intl message formatter.
11-
* Added support for one formatter per domain
10+
* Added `IntlMessageFormatter` and`FallbackMessageFormatter`
1211

1312
4.1.0
1413
-----
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Symfony\Component\Translation\Formatter;
15+
16+
use Symfony\Component\Translation\Exception\LogicException;
17+
18+
class FallbackFormatter implements MessageFormatterInterface, ChoiceMessageFormatterInterface
19+
{
20+
/**
21+
* @var MessageFormatterInterface|ChoiceMessageFormatterInterface
22+
*/
23+
private $firstFormatter;
24+
25+
/**
26+
* @var MessageFormatterInterface|ChoiceMessageFormatterInterface
27+
*/
28+
private $secondFormatter;
29+
30+
public function __construct(MessageFormatterInterface $firstFormatter, MessageFormatterInterface $secondFormatter)
31+
{
32+
$this->firstFormatter = $firstFormatter;
33+
$this->secondFormatter = $secondFormatter;
34+
}
35+
36+
public function format($message, $locale, array $parameters = array())
37+
{
38+
try {
39+
$result = $this->firstFormatter->format($message, $locale, $parameters);
40+
} catch (\Throwable $e) {
41+
return $this->secondFormatter->format($message, $locale, $parameters);
42+
}
43+
44+
if ($result === $message) {
45+
$result = $this->secondFormatter->format($message, $locale, $parameters);
46+
}
47+
48+
return $result;
49+
}
50+
51+
public function choiceFormat($message, $number, $locale, array $parameters = array())
52+
{
53+
// If both support ChoiceMessageFormatterInterface
54+
if ($this->firstFormatter instanceof ChoiceMessageFormatterInterface && $this->secondFormatter instanceof ChoiceMessageFormatterInterface) {
55+
try {
56+
$result = $this->firstFormatter->choiceFormat($message, $number, $locale, $parameters);
57+
} catch (\Throwable $e) {
58+
return $this->secondFormatter->choiceFormat($message, $number, $locale, $parameters);
59+
}
60+
61+
if ($result === $message) {
62+
$result = $this->secondFormatter->choiceFormat($message, $number, $locale, $parameters);
63+
}
64+
65+
return $result;
66+
}
67+
68+
if ($this->firstFormatter instanceof ChoiceMessageFormatterInterface) {
69+
return $this->firstFormatter->choiceFormat($message, $number, $locale, $parameters);
70+
}
71+
72+
if ($this->secondFormatter instanceof ChoiceMessageFormatterInterface) {
73+
return $this->secondFormatter->choiceFormat($message, $number, $locale, $parameters);
74+
}
75+
76+
throw new LogicException(sprintf('The no formatter support plural translations.'));
77+
}
78+
}

src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Translation\Formatter;
1313

14+
use Symfony\Component\Translation\Exception\InvalidArgumentException;
15+
1416
/**
1517
* @author Guilherme Blanco <[email protected]>
1618
* @author Abdellatif Ait boudad <[email protected]>
@@ -25,15 +27,12 @@ public function format($message, $locale, array $parameters = array())
2527
try {
2628
$formatter = new \MessageFormatter($locale, $message);
2729
} catch (\Throwable $e) {
28-
throw new \InvalidArgumentException('Invalid message format.', $e);
29-
}
30-
if (null === $formatter) {
31-
throw new \InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code()));
30+
throw new InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code()), 0, $e);
3231
}
3332

3433
$message = $formatter->format($parameters);
3534
if (U_ZERO_ERROR !== $formatter->getErrorCode()) {
36-
throw new \InvalidArgumentException(sprintf('Unable to format message. Reason: %s (error #%s)', $formatter->getErrorMessage(), $formatter->getErrorCode()));
35+
throw new InvalidArgumentException(sprintf('Unable to format message. Reason: %s (error #%s)', $formatter->getErrorMessage(), $formatter->getErrorCode()));
3736
}
3837

3938
return $message;
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Translation\Tests\Formatter;
13+
14+
use Symfony\Component\Translation\Exception\InvalidArgumentException;
15+
use Symfony\Component\Translation\Exception\LogicException;
16+
use Symfony\Component\Translation\Formatter\ChoiceMessageFormatterInterface;
17+
use Symfony\Component\Translation\Formatter\FallbackFormatter;
18+
use Symfony\Component\Translation\Formatter\MessageFormatterInterface;
19+
20+
class FallbackFormatterTest extends \PHPUnit\Framework\TestCase
21+
{
22+
public function testFormatSame()
23+
{
24+
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
25+
$first
26+
->expects($this->once())
27+
->method('format')
28+
->with('foo', 'en', array(2))
29+
->willReturn('foo');
30+
31+
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
32+
$second
33+
->expects($this->once())
34+
->method('format')
35+
->with('foo', 'en', array(2))
36+
->willReturn('bar');
37+
38+
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->format('foo', 'en', array(2)));
39+
}
40+
41+
public function testFormatDifferent()
42+
{
43+
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
44+
$first
45+
->expects($this->once())
46+
->method('format')
47+
->with('foo', 'en', array(2))
48+
->willReturn('new value');
49+
50+
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
51+
$second
52+
->expects($this->exactly(0))
53+
->method('format')
54+
->withAnyParameters();
55+
56+
$this->assertEquals('new value', (new FallbackFormatter($first, $second))->format('foo', 'en', array(2)));
57+
}
58+
59+
public function testFormatException()
60+
{
61+
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
62+
$first
63+
->expects($this->once())
64+
->method('format')
65+
->willThrowException(new InvalidArgumentException());
66+
67+
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
68+
$second
69+
->expects($this->once())
70+
->method('format')
71+
->with('foo', 'en', array(2))
72+
->willReturn('bar');
73+
74+
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->format('foo', 'en', array(2)));
75+
}
76+
77+
public function testChoiceFormatSame()
78+
{
79+
$first = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock();
80+
$first
81+
->expects($this->once())
82+
->method('choiceFormat')
83+
->with('foo', 1, 'en', array(2))
84+
->willReturn('foo');
85+
86+
$second = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock();
87+
$second
88+
->expects($this->once())
89+
->method('choiceFormat')
90+
->with('foo', 1, 'en', array(2))
91+
->willReturn('bar');
92+
93+
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2)));
94+
}
95+
96+
public function testChoiceFormatDifferent()
97+
{
98+
$first = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock();
99+
$first
100+
->expects($this->once())
101+
->method('choiceFormat')
102+
->with('foo', 1, 'en', array(2))
103+
->willReturn('new value');
104+
105+
$second = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock();
106+
$second
107+
->expects($this->exactly(0))
108+
->method('choiceFormat')
109+
->withAnyParameters()
110+
->willReturn('bar');
111+
112+
$this->assertEquals('new value', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2)));
113+
}
114+
115+
public function testChoiceFormatException()
116+
{
117+
$first = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock();
118+
$first
119+
->expects($this->once())
120+
->method('choiceFormat')
121+
->willThrowException(new InvalidArgumentException());
122+
123+
$second = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock();
124+
$second
125+
->expects($this->once())
126+
->method('choiceFormat')
127+
->with('foo', 1, 'en', array(2))
128+
->willReturn('bar');
129+
130+
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2)));
131+
}
132+
133+
public function testChoiceFormatOnlyFirst()
134+
{
135+
// Implements both interfaces
136+
$first = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock();
137+
$first
138+
->expects($this->once())
139+
->method('choiceFormat')
140+
->with('foo', 1, 'en', array(2))
141+
->willReturn('bar');
142+
143+
// Implements only one interface
144+
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
145+
$second
146+
->expects($this->exactly(0))
147+
->method('format')
148+
->withAnyParameters()
149+
->willReturn('error');
150+
151+
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2)));
152+
}
153+
154+
public function testChoiceFormatOnlySecond()
155+
{
156+
// Implements only one interface
157+
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
158+
$first
159+
->expects($this->exactly(0))
160+
->method('format')
161+
->withAnyParameters()
162+
->willReturn('error');
163+
164+
// Implements both interfaces
165+
$second = $this->getMockBuilder(SuperFormatterInterface::class)->setMethods(array('format', 'choiceFormat'))->getMock();
166+
$second
167+
->expects($this->once())
168+
->method('choiceFormat')
169+
->with('foo', 1, 'en', array(2))
170+
->willReturn('bar');
171+
172+
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2)));
173+
}
174+
175+
public function testChoiceFormatNoChoiceFormat()
176+
{
177+
// Implements only one interface
178+
$first = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
179+
$first
180+
->expects($this->exactly(0))
181+
->method('format');
182+
183+
// Implements both interfaces
184+
$second = $this->getMockBuilder(MessageFormatterInterface::class)->setMethods(array('format'))->getMock();
185+
$second
186+
->expects($this->exactly(0))
187+
->method('format');
188+
189+
$this->expectException(LogicException::class);
190+
$this->assertEquals('bar', (new FallbackFormatter($first, $second))->choiceFormat('foo', 1, 'en', array(2)));
191+
}
192+
}
193+
194+
interface SuperFormatterInterface extends MessageFormatterInterface, ChoiceMessageFormatterInterface
195+
{
196+
}

0 commit comments

Comments
 (0)