Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 597a15d

Browse filesBrowse files
committed
Use FallbackFormatter instead of support for multiple formatters
1 parent 2aa7181 commit 597a15d
Copy full SHA for 597a15d

File tree

12 files changed

+303
-82
lines changed
Filter options

12 files changed

+303
-82
lines changed

‎src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
-1Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+1-14Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
-3Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
-6Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml
+6-4Lines 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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Translation/CHANGELOG.md
+1-2Lines 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
-----
+78Lines 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 <fabien@symfony.com>
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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php
+4-5Lines 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 <guilhermeblanco@hotmail.com>
1618
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
@@ -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;
+196Lines 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 <fabien@symfony.com>
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.