Skip to content

Commit eb3635f

Browse files
committed
feature #18314 [Translation] added support for adding custom message formatter (aitboudad)
This PR was merged into the 3.4 branch. Discussion ---------- [Translation] added support for adding custom message formatter | Q | A | | --- | --- | | Branch? | master | | Bug fix? | no | | New feature? | yes | | BC breaks? | no | | Deprecations? | yes | | Tests pass? | yes | | Fixed tickets | #6009, #10152, one item in #11742, #11948 | | License | MIT | | Doc PR | ~ | Commits ------- 42183b0 [Translation] Support adding custom message formatter
2 parents e8b3797 + 449525b commit eb3635f

File tree

7 files changed

+230
-28
lines changed

7 files changed

+230
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ CHANGELOG
1212
* Improved Xliff 2.0 loader to load `<notes>` section.
1313
* Added `TranslationWriterInterface`
1414
* Deprecated `TranslationWriter::writeTranslations` in favor of `TranslationWriter::write`
15+
* added support for adding custom message formatter and decoupling the default one.
1516

1617
3.2.0
1718
-----
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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\Formatter;
13+
14+
/**
15+
* @author Abdellatif Ait boudad <[email protected]>
16+
*/
17+
interface ChoiceMessageFormatterInterface
18+
{
19+
/**
20+
* Formats a localized message pattern with given arguments.
21+
*
22+
* @param string $message The message (may also be an object that can be cast to string)
23+
* @param int $number The number to use to find the indice of the message
24+
* @param string $locale The message locale
25+
* @param array $parameters An array of parameters for the message
26+
*
27+
* @return string
28+
*/
29+
public function choiceFormat($message, $number, $locale, array $parameters = array());
30+
}

Formatter/MessageFormatter.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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\Formatter;
13+
14+
use Symfony\Component\Translation\MessageSelector;
15+
16+
/**
17+
* @author Abdellatif Ait boudad <[email protected]>
18+
*/
19+
class MessageFormatter implements MessageFormatterInterface, ChoiceMessageFormatterInterface
20+
{
21+
private $selector;
22+
23+
/**
24+
* @param MessageSelector|null $selector The message selector for pluralization
25+
*/
26+
public function __construct(MessageSelector $selector = null)
27+
{
28+
$this->selector = $selector ?: new MessageSelector();
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function format($message, $locale, array $parameters = array())
35+
{
36+
return strtr($message, $parameters);
37+
}
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
public function choiceFormat($message, $number, $locale, array $parameters = array())
43+
{
44+
$parameters = array_merge(array('%count%' => $number), $parameters);
45+
46+
return $this->format($this->selector->choose($message, (int) $number, $locale), $locale, $parameters);
47+
}
48+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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\Formatter;
13+
14+
/**
15+
* @author Guilherme Blanco <[email protected]>
16+
* @author Abdellatif Ait boudad <[email protected]>
17+
*/
18+
interface MessageFormatterInterface
19+
{
20+
/**
21+
* Formats a localized message pattern with given arguments.
22+
*
23+
* @param string $message The message (may also be an object that can be cast to string)
24+
* @param string $locale The message locale
25+
* @param array $parameters An array of parameters for the message
26+
*
27+
* @return string
28+
*/
29+
public function format($message, $locale, array $parameters = array());
30+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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 PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Translation\Formatter\MessageFormatter;
16+
17+
class MessageFormatterTest extends TestCase
18+
{
19+
/**
20+
* @dataProvider getTransMessages
21+
*/
22+
public function testFormat($expected, $message, $parameters = array())
23+
{
24+
$this->assertEquals($expected, $this->getMessageFormatter()->format($message, 'en', $parameters));
25+
}
26+
27+
/**
28+
* @dataProvider getTransChoiceMessages
29+
*/
30+
public function testFormatPlural($expected, $message, $number, $parameters)
31+
{
32+
$this->assertEquals($expected, $this->getMessageFormatter()->choiceFormat($message, $number, 'fr', $parameters));
33+
}
34+
35+
public function getTransMessages()
36+
{
37+
return array(
38+
array(
39+
'There is one apple',
40+
'There is one apple',
41+
),
42+
array(
43+
'There are 5 apples',
44+
'There are %count% apples',
45+
array('%count%' => 5),
46+
),
47+
array(
48+
'There are 5 apples',
49+
'There are {{count}} apples',
50+
array('{{count}}' => 5),
51+
),
52+
);
53+
}
54+
55+
public function getTransChoiceMessages()
56+
{
57+
return array(
58+
array('Il y a 0 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0)),
59+
array('Il y a 1 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, array('%count%' => 1)),
60+
array('Il y a 10 pommes', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, array('%count%' => 10)),
61+
62+
array('Il y a 0 pomme', 'Il y a %count% pomme|Il y a %count% pommes', 0, array('%count%' => 0)),
63+
array('Il y a 1 pomme', 'Il y a %count% pomme|Il y a %count% pommes', 1, array('%count%' => 1)),
64+
array('Il y a 10 pommes', 'Il y a %count% pomme|Il y a %count% pommes', 10, array('%count%' => 10)),
65+
66+
array('Il y a 0 pomme', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0)),
67+
array('Il y a 1 pomme', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1)),
68+
array('Il y a 10 pommes', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10)),
69+
70+
array('Il n\'y a aucune pomme', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0)),
71+
array('Il y a 1 pomme', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1)),
72+
array('Il y a 10 pommes', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10)),
73+
74+
array('Il y a 0 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0)),
75+
);
76+
}
77+
78+
private function getMessageFormatter()
79+
{
80+
return new MessageFormatter();
81+
}
82+
}

Tests/TranslatorTest.php

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Translation\Translator;
16-
use Symfony\Component\Translation\MessageSelector;
1716
use Symfony\Component\Translation\Loader\ArrayLoader;
1817
use Symfony\Component\Translation\MessageCatalogue;
1918

@@ -25,22 +24,22 @@ class TranslatorTest extends TestCase
2524
*/
2625
public function testConstructorInvalidLocale($locale)
2726
{
28-
$translator = new Translator($locale, new MessageSelector());
27+
$translator = new Translator($locale);
2928
}
3029

3130
/**
3231
* @dataProvider getValidLocalesTests
3332
*/
3433
public function testConstructorValidLocale($locale)
3534
{
36-
$translator = new Translator($locale, new MessageSelector());
35+
$translator = new Translator($locale);
3736

3837
$this->assertEquals($locale, $translator->getLocale());
3938
}
4039

4140
public function testConstructorWithoutLocale()
4241
{
43-
$translator = new Translator(null, new MessageSelector());
42+
$translator = new Translator(null);
4443

4544
$this->assertNull($translator->getLocale());
4645
}
@@ -61,7 +60,7 @@ public function testSetGetLocale()
6160
*/
6261
public function testSetInvalidLocale($locale)
6362
{
64-
$translator = new Translator('fr', new MessageSelector());
63+
$translator = new Translator('fr');
6564
$translator->setLocale($locale);
6665
}
6766

@@ -70,7 +69,7 @@ public function testSetInvalidLocale($locale)
7069
*/
7170
public function testSetValidLocale($locale)
7271
{
73-
$translator = new Translator($locale, new MessageSelector());
72+
$translator = new Translator($locale);
7473
$translator->setLocale($locale);
7574

7675
$this->assertEquals($locale, $translator->getLocale());
@@ -144,7 +143,7 @@ public function testSetFallbackLocalesMultiple()
144143
*/
145144
public function testSetFallbackInvalidLocales($locale)
146145
{
147-
$translator = new Translator('fr', new MessageSelector());
146+
$translator = new Translator('fr');
148147
$translator->setFallbackLocales(array('fr', $locale));
149148
}
150149

@@ -153,7 +152,7 @@ public function testSetFallbackInvalidLocales($locale)
153152
*/
154153
public function testSetFallbackValidLocales($locale)
155154
{
156-
$translator = new Translator($locale, new MessageSelector());
155+
$translator = new Translator($locale);
157156
$translator->setFallbackLocales(array('fr', $locale));
158157
// no assertion. this method just asserts that no exception is thrown
159158
$this->addToAssertionCount(1);
@@ -176,7 +175,7 @@ public function testTransWithFallbackLocale()
176175
*/
177176
public function testAddResourceInvalidLocales($locale)
178177
{
179-
$translator = new Translator('fr', new MessageSelector());
178+
$translator = new Translator('fr');
180179
$translator->addResource('array', array('foo' => 'foofoo'), $locale);
181180
}
182181

@@ -185,7 +184,7 @@ public function testAddResourceInvalidLocales($locale)
185184
*/
186185
public function testAddResourceValidLocales($locale)
187186
{
188-
$translator = new Translator('fr', new MessageSelector());
187+
$translator = new Translator('fr');
189188
$translator->addResource('array', array('foo' => 'foofoo'), $locale);
190189
// no assertion. this method just asserts that no exception is thrown
191190
$this->addToAssertionCount(1);
@@ -288,7 +287,7 @@ public function testNestedFallbackCatalogueWhenUsingMultipleLocales()
288287

289288
public function testFallbackCatalogueResources()
290289
{
291-
$translator = new Translator('en_GB', new MessageSelector());
290+
$translator = new Translator('en_GB');
292291
$translator->addLoader('yml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
293292
$translator->addResource('yml', __DIR__.'/fixtures/empty.yml', 'en_GB');
294293
$translator->addResource('yml', __DIR__.'/fixtures/resources.yml', 'en');
@@ -324,7 +323,7 @@ public function testTrans($expected, $id, $translation, $parameters, $locale, $d
324323
*/
325324
public function testTransInvalidLocale($locale)
326325
{
327-
$translator = new Translator('en', new MessageSelector());
326+
$translator = new Translator('en');
328327
$translator->addLoader('array', new ArrayLoader());
329328
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
330329

@@ -336,7 +335,7 @@ public function testTransInvalidLocale($locale)
336335
*/
337336
public function testTransValidLocale($locale)
338337
{
339-
$translator = new Translator($locale, new MessageSelector());
338+
$translator = new Translator($locale);
340339
$translator->addLoader('array', new ArrayLoader());
341340
$translator->addResource('array', array('test' => 'OK'), $locale);
342341

@@ -374,7 +373,7 @@ public function testTransChoice($expected, $id, $translation, $number, $paramete
374373
*/
375374
public function testTransChoiceInvalidLocale($locale)
376375
{
377-
$translator = new Translator('en', new MessageSelector());
376+
$translator = new Translator('en');
378377
$translator->addLoader('array', new ArrayLoader());
379378
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
380379

@@ -386,7 +385,7 @@ public function testTransChoiceInvalidLocale($locale)
386385
*/
387386
public function testTransChoiceValidLocale($locale)
388387
{
389-
$translator = new Translator('en', new MessageSelector());
388+
$translator = new Translator('en');
390389
$translator->addLoader('array', new ArrayLoader());
391390
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
392391

0 commit comments

Comments
 (0)