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 d870a85

Browse filesBrowse files
Nyholmnicolas-grekas
authored andcommitted
[Translator] Deprecated transChoice and moved it away from contracts
1 parent 3e7b029 commit d870a85
Copy full SHA for d870a85

22 files changed

+494
-566
lines changed

‎UPGRADE-4.2.md

Copy file name to clipboardExpand all lines: UPGRADE-4.2.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ Translation
219219
-----------
220220

221221
* The `TranslatorInterface` has been deprecated in favor of `Symfony\Contracts\Translation\TranslatorInterface`
222+
* The `Translator::transChoice()` has been deprecated in favor of using `Translator::trans()` with intl message format
222223
* The `MessageSelector`, `Interval` and `PluralizationRules` classes have been deprecated, use `IdentityTranslator` instead
223224
* The `Translator::getFallbackLocales()` and `TranslationDataCollector::getFallbackLocales()` method have been marked as internal
224225

‎src/Symfony/Bridge/Twig/Extension/TranslationExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Twig/Extension/TranslationExtension.php
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Symfony\Bridge\Twig\TokenParser\TransChoiceTokenParser;
1717
use Symfony\Bridge\Twig\TokenParser\TransDefaultDomainTokenParser;
1818
use Symfony\Bridge\Twig\TokenParser\TransTokenParser;
19+
use Symfony\Component\Translation\LegacyTranslatorTrait;
20+
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
1921
use Symfony\Contracts\Translation\TranslatorInterface;
2022
use Symfony\Contracts\Translation\TranslatorTrait;
2123
use Twig\Extension\AbstractExtension;
@@ -34,6 +36,9 @@ class TranslationExtension extends AbstractExtension
3436
getLocale as private;
3537
setLocale as private;
3638
trans as private doTrans;
39+
}
40+
41+
use LegacyTranslatorTrait {
3742
transChoice as private doTransChoice;
3843
}
3944

@@ -107,7 +112,7 @@ public function trans($message, array $arguments = array(), $domain = null, $loc
107112

108113
public function transchoice($message, $count, array $arguments = array(), $domain = null, $locale = null)
109114
{
110-
if (null === $this->translator) {
115+
if (null === $this->translator || !$this->translator instanceof LegacyTranslatorInterface) {
111116
return $this->doTransChoice($message, $count, array_merge(array('%count%' => $count), $arguments), $domain, $locale);
112117
}
113118

‎src/Symfony/Bundle/FrameworkBundle/Templating/Helper/TranslatorHelper.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Templating/Helper/TranslatorHelper.php
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Templating\Helper;
1313

1414
use Symfony\Component\Templating\Helper\Helper;
15+
use Symfony\Component\Translation\LegacyTranslatorTrait;
16+
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
1517
use Symfony\Contracts\Translation\TranslatorInterface;
1618
use Symfony\Contracts\Translation\TranslatorTrait;
1719

@@ -24,6 +26,9 @@ class TranslatorHelper extends Helper
2426
getLocale as private;
2527
setLocale as private;
2628
trans as private doTrans;
29+
}
30+
31+
use LegacyTranslatorTrait {
2732
transChoice as private doTransChoice;
2833
}
2934

@@ -51,7 +56,7 @@ public function trans($id, array $parameters = array(), $domain = 'messages', $l
5156
*/
5257
public function transChoice($id, $number, array $parameters = array(), $domain = 'messages', $locale = null)
5358
{
54-
if (null === $this->translator) {
59+
if (null === $this->translator || !$this->translator instanceof LegacyTranslatorInterface) {
5560
return $this->doTransChoice($id, $number, $parameters, $domain, $locale);
5661
}
5762

‎src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php
+38-6Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,25 @@ public function testTransWithoutCaching()
5252
$this->assertEquals('foo (FR)', $translator->trans('foo'));
5353
$this->assertEquals('bar (EN)', $translator->trans('bar'));
5454
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
55-
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
5655
$this->assertEquals('no translation', $translator->trans('no translation'));
5756
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
58-
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
5957
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
6058
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
6159
}
6260

61+
/**
62+
* @group legacy
63+
*/
64+
public function testTransChoiceWithoutCaching()
65+
{
66+
$translator = $this->getTranslator($this->getLoader());
67+
$translator->setLocale('fr');
68+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
69+
70+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
71+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
72+
}
73+
6374
public function testTransWithCaching()
6475
{
6576
// prime the cache
@@ -70,10 +81,8 @@ public function testTransWithCaching()
7081
$this->assertEquals('foo (FR)', $translator->trans('foo'));
7182
$this->assertEquals('bar (EN)', $translator->trans('bar'));
7283
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
73-
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
7484
$this->assertEquals('no translation', $translator->trans('no translation'));
7585
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
76-
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
7786
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
7887
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
7988

@@ -88,14 +97,37 @@ public function testTransWithCaching()
8897
$this->assertEquals('foo (FR)', $translator->trans('foo'));
8998
$this->assertEquals('bar (EN)', $translator->trans('bar'));
9099
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
91-
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
92100
$this->assertEquals('no translation', $translator->trans('no translation'));
93101
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
94-
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
95102
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
96103
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
97104
}
98105

106+
/**
107+
* @group legacy
108+
*/
109+
public function testTransChoiceWithCaching()
110+
{
111+
// prime the cache
112+
$translator = $this->getTranslator($this->getLoader(), array('cache_dir' => $this->tmpDir));
113+
$translator->setLocale('fr');
114+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
115+
116+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
117+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
118+
119+
// do it another time as the cache is primed now
120+
$loader = $this->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock();
121+
$loader->expects($this->never())->method('load');
122+
123+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir));
124+
$translator->setLocale('fr');
125+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
126+
127+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
128+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
129+
}
130+
99131
/**
100132
* @expectedException \InvalidArgumentException
101133
* @expectedExceptionMessage Invalid "invalid locale" locale.

‎src/Symfony/Component/Translation/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Translation/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* Started using ICU parent locales as fallback locales.
8+
* deprecated `Translator::transChoice()` in favor of using `Translator::trans()` with intl message format
89
* deprecated `TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`
910
* deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead
1011
* Added `IntlMessageFormatter` and `FallbackMessageFormatter`

‎src/Symfony/Component/Translation/DataCollectorTranslator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Translation/DataCollectorTranslator.php
+10-1Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
*/
2121
class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorBagInterface
2222
{
23+
use LegacyTranslatorTrait {
24+
transChoice as private doTransChoice;
25+
}
26+
2327
const MESSAGE_DEFINED = 0;
2428
const MESSAGE_MISSING = 1;
2529
const MESSAGE_EQUALS_FALLBACK = 2;
@@ -59,7 +63,12 @@ public function trans($id, array $parameters = array(), $domain = null, $locale
5963
*/
6064
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
6165
{
62-
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
66+
if ($this->translator instanceof LegacyTranslatorInterface) {
67+
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
68+
} else {
69+
$trans = $this->doTransChoice($id, $number, $parameters, $domain, $locale);
70+
}
71+
6372
$this->collectMessage($locale, $domain, $id, $trans, $parameters, $number);
6473

6574
return $trans;

‎src/Symfony/Component/Translation/IdentityTranslator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Translation/IdentityTranslator.php
+4-7Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
*/
2121
class IdentityTranslator implements TranslatorInterface
2222
{
23-
use TranslatorTrait {
23+
use TranslatorTrait;
24+
use LegacyTranslatorTrait {
2425
transChoice as private doTransChoice;
2526
}
2627

@@ -43,15 +44,11 @@ public function __construct(MessageSelector $selector = null)
4344
*/
4445
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
4546
{
47+
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "trans()" method with intl formatted messages instead.', __METHOD__), E_USER_DEPRECATED);
4648
if ($this->selector) {
47-
return strtr($this->selector->choose((string) $id, (int) $number, $locale ?: $this->getLocale()), $parameters);
49+
return strtr($this->selector->choose((string) $id, $number, $locale ?: $this->getLocale()), $parameters);
4850
}
4951

5052
return $this->doTransChoice($id, $number, $parameters, $domain, $locale);
5153
}
52-
53-
private function getPluralizationRule(int $number, string $locale): int
54-
{
55-
return PluralizationRules::get($number, $locale, false);
56-
}
5754
}
+110Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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;
13+
14+
use Symfony\Component\Translation\Exception\InvalidArgumentException;
15+
16+
/**
17+
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
18+
* @author Fabien Potencier <fabien@symfony.com>
19+
*
20+
* @deprecated since Symfony 4.2, use IdentityTranslator instead
21+
*/
22+
trait LegacyTranslatorTrait
23+
{
24+
/**
25+
* Implementation of Symfony\Component\Translation\TranslationInterface::transChoice
26+
* {@inheritdoc}
27+
*/
28+
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
29+
{
30+
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "trans()" method with intl formatted messages instead.', __METHOD__), E_USER_DEPRECATED);
31+
32+
$id = (string) $id;
33+
$number = (float) $number;
34+
$locale = (string) $locale ?: $this->getLocale();
35+
36+
$parts = array();
37+
if (preg_match('/^\|++$/', $id)) {
38+
$parts = explode('|', $id);
39+
} elseif (preg_match_all('/(?:\|\||[^\|])++/', $id, $matches)) {
40+
$parts = $matches[0];
41+
}
42+
43+
$intervalRegexp = <<<'EOF'
44+
/^(?P<interval>
45+
({\s*
46+
(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
47+
\s*})
48+
49+
|
50+
51+
(?P<left_delimiter>[\[\]])
52+
\s*
53+
(?P<left>-Inf|\-?\d+(\.\d+)?)
54+
\s*,\s*
55+
(?P<right>\+?Inf|\-?\d+(\.\d+)?)
56+
\s*
57+
(?P<right_delimiter>[\[\]])
58+
)\s*(?P<message>.*?)$/xs
59+
EOF;
60+
61+
$standardRules = array();
62+
foreach ($parts as $part) {
63+
$part = trim(str_replace('||', '|', $part));
64+
65+
// try to match an explicit rule, then fallback to the standard ones
66+
if (preg_match($intervalRegexp, $part, $matches)) {
67+
if ($matches[2]) {
68+
foreach (explode(',', $matches[3]) as $n) {
69+
if ($number == $n) {
70+
return strtr($matches['message'], $parameters);
71+
}
72+
}
73+
} else {
74+
$leftNumber = '-Inf' === $matches['left'] ? -INF : (float) $matches['left'];
75+
$rightNumber = \is_numeric($matches['right']) ? (float) $matches['right'] : INF;
76+
77+
if (('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
78+
&& (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
79+
) {
80+
return strtr($matches['message'], $parameters);
81+
}
82+
}
83+
} elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
84+
$standardRules[] = $matches[1];
85+
} else {
86+
$standardRules[] = $part;
87+
}
88+
}
89+
90+
$position = PluralizationRules::get($number, $locale, false);
91+
92+
if (!isset($standardRules[$position])) {
93+
// when there's exactly one rule given, and that rule is a standard
94+
// rule, use this rule
95+
if (1 === \count($parts) && isset($standardRules[0])) {
96+
return strtr($standardRules[0], $parameters);
97+
}
98+
99+
$message = sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number);
100+
101+
if (\class_exists(InvalidArgumentException::class)) {
102+
throw new InvalidArgumentException($message);
103+
}
104+
105+
throw new \InvalidArgumentException($message);
106+
}
107+
108+
return strtr($standardRules[$position], $parameters);
109+
}
110+
}

‎src/Symfony/Component/Translation/LoggingTranslator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Translation/LoggingTranslator.php
+10-1Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
*/
2222
class LoggingTranslator implements LegacyTranslatorInterface, TranslatorBagInterface
2323
{
24+
use LegacyTranslatorTrait {
25+
transChoice as private doTransChoice;
26+
}
27+
2428
/**
2529
* @var TranslatorInterface|TranslatorBagInterface
2630
*/
@@ -58,7 +62,12 @@ public function trans($id, array $parameters = array(), $domain = null, $locale
5862
*/
5963
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
6064
{
61-
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
65+
if ($this->translator instanceof LegacyTranslatorInterface) {
66+
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
67+
} else {
68+
$trans = $this->doTransChoice($id, $number, $parameters, $domain, $locale);
69+
}
70+
6271
$this->log($id, $domain, $locale);
6372

6473
return $trans;

‎src/Symfony/Component/Translation/MessageSelector.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Translation/MessageSelector.php
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ class MessageSelector
4343
* The two methods can also be mixed:
4444
* {0} There are no apples|one: There is one apple|more: There are %count% apples
4545
*
46-
* @param string $message The message being translated
47-
* @param int $number The number of items represented for the message
48-
* @param string $locale The locale to use for choosing
46+
* @param string $message The message being translated
47+
* @param int|float $number The number of items represented for the message
48+
* @param string $locale The locale to use for choosing
4949
*
5050
* @return string
5151
*

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.