minor #31912 [Translation] remove deprecated code paths (nicolas-grekas)

This PR was merged into the 5.0-dev branch.

Discussion
----------

[Translation] remove deprecated code paths

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | yes
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

Commits
-------

1a0bfbcbcb [Translation] remove deprecated code paths
This commit is contained in:
Nicolas Grekas 2019-06-07 17:30:38 +02:00
commit 17edc6ada6
52 changed files with 43 additions and 1879 deletions

View File

@ -5,6 +5,7 @@ CHANGELOG
-----
* removed `TwigEngine` class, use `\Twig\Environment` instead.
* removed `transChoice` filter and token
4.4.0
-----

View File

@ -13,10 +13,8 @@ namespace Symfony\Bridge\Twig\Extension;
use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor;
use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
use Symfony\Bridge\Twig\TokenParser\TransChoiceTokenParser;
use Symfony\Bridge\Twig\TokenParser\TransDefaultDomainTokenParser;
use Symfony\Bridge\Twig\TokenParser\TransTokenParser;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorTrait;
use Twig\Extension\AbstractExtension;
@ -36,14 +34,8 @@ class TranslationExtension extends AbstractExtension
private $translator;
private $translationNodeVisitor;
/**
* @param TranslatorInterface|null $translator
*/
public function __construct($translator = null, NodeVisitorInterface $translationNodeVisitor = null)
public function __construct(TranslatorInterface $translator = null, NodeVisitorInterface $translationNodeVisitor = null)
{
if (null !== $translator && !$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->translator = $translator;
$this->translationNodeVisitor = $translationNodeVisitor;
}
@ -73,7 +65,6 @@ class TranslationExtension extends AbstractExtension
{
return [
new TwigFilter('trans', [$this, 'trans']),
new TwigFilter('transchoice', [$this, 'transchoice'], ['deprecated' => '4.2', 'alternative' => 'trans" with parameter "%count%']),
];
}
@ -88,11 +79,6 @@ class TranslationExtension extends AbstractExtension
// {% trans %}Symfony is great!{% endtrans %}
new TransTokenParser(),
// {% transchoice count %}
// {0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples
// {% endtranschoice %}
new TransChoiceTokenParser(),
// {% trans_default_domain "foobar" %}
new TransDefaultDomainTokenParser(),
];
@ -120,20 +106,6 @@ class TranslationExtension extends AbstractExtension
return $this->getTranslator()->trans($message, $arguments, $domain, $locale);
}
/**
* @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
*/
public function transchoice($message, $count, array $arguments = [], $domain = null, $locale = null)
{
$translator = $this->getTranslator();
if ($translator instanceof TranslatorInterface) {
return $translator->trans($message, array_merge(['%count%' => $count], $arguments), $domain, $locale);
}
return $translator->transChoice($message, $count, array_merge(['%count%' => $count], $arguments), $domain, $locale);
}
/**
* {@inheritdoc}
*/

View File

@ -57,8 +57,6 @@ class TransNode extends Node
}
list($msg, $defaults) = $this->compileString($this->getNode('body'), $defaults, (bool) $vars);
$method = !$this->hasNode('count') ? 'trans' : 'transChoice';
$compiler
->write('echo $this->env->getExtension(\'Symfony\Bridge\Twig\Extension\TranslationExtension\')->trans(')
->subcompile($msg)

View File

@ -45,15 +45,6 @@ class TranslationExtensionTest extends TestCase
$this->assertEquals($expected, $this->getTemplate($template)->render($variables));
}
/**
* @group legacy
* @dataProvider getTransChoiceTests
*/
public function testTransChoice($template, $expected, array $variables = [])
{
$this->testTrans($template, $expected, $variables);
}
/**
* @expectedException \Twig\Error\SyntaxError
* @expectedExceptionMessage Unexpected token. Twig was looking for the "with", "from", or "into" keyword in "index" at line 3.
@ -72,16 +63,6 @@ class TranslationExtensionTest extends TestCase
$output = $this->getTemplate("{% trans %}\n{{ 1 + 2 }}{% endtrans %}")->render();
}
/**
* @group legacy
* @expectedException \Twig\Error\SyntaxError
* @expectedExceptionMessage A message inside a transchoice tag must be a simple text in "index" at line 2.
*/
public function testTransChoiceComplexBody()
{
$output = $this->getTemplate("{% transchoice count %}\n{{ 1 + 2 }}{% endtranschoice %}")->render();
}
public function getTransTests()
{
return [
@ -142,69 +123,6 @@ class TranslationExtensionTest extends TestCase
];
}
/**
* @group legacy
*/
public function getTransChoiceTests()
{
return [
// trans tag
['{% trans %}Hello{% endtrans %}', 'Hello'],
['{% trans %}%name%{% endtrans %}', 'Symfony', ['name' => 'Symfony']],
['{% trans from elsewhere %}Hello{% endtrans %}', 'Hello'],
['{% trans %}Hello %name%{% endtrans %}', 'Hello Symfony', ['name' => 'Symfony']],
['{% trans with { \'%name%\': \'Symfony\' } %}Hello %name%{% endtrans %}', 'Hello Symfony'],
['{% set vars = { \'%name%\': \'Symfony\' } %}{% trans with vars %}Hello %name%{% endtrans %}', 'Hello Symfony'],
['{% trans into "fr"%}Hello{% endtrans %}', 'Hello'],
// transchoice
[
'{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
'There is no apples',
['count' => 0],
],
[
'{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
'There is 5 apples',
['count' => 5],
],
[
'{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
'There is 5 apples (Symfony)',
['count' => 5, 'name' => 'Symfony'],
],
[
'{% transchoice count with { \'%name%\': \'Symfony\' } %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
'There is 5 apples (Symfony)',
['count' => 5],
],
[
'{% transchoice count into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
'There is no apples',
['count' => 0],
],
[
'{% transchoice 5 into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
'There is 5 apples',
],
// trans filter
['{{ "Hello"|trans }}', 'Hello'],
['{{ name|trans }}', 'Symfony', ['name' => 'Symfony']],
['{{ hello|trans({ \'%name%\': \'Symfony\' }) }}', 'Hello Symfony', ['hello' => 'Hello %name%']],
['{% set vars = { \'%name%\': \'Symfony\' } %}{{ hello|trans(vars) }}', 'Hello Symfony', ['hello' => 'Hello %name%']],
['{{ "Hello"|trans({}, "messages", "fr") }}', 'Hello'],
// transchoice filter
['{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count) }}', 'There is 5 apples', ['count' => 5]],
['{{ text|transchoice(5, {\'%name%\': \'Symfony\'}) }}', 'There is 5 apples (Symfony)', ['text' => '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%)']],
['{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count, {}, "messages", "fr") }}', 'There is 5 apples', ['count' => 5]],
];
}
public function testDefaultTranslationDomain()
{
$templates = [

View File

@ -79,15 +79,11 @@ class TranslationDefaultDomainNodeVisitorTest extends TestCase
{
return [
[TwigNodeProvider::getTransFilter(self::$message)],
[TwigNodeProvider::getTransChoiceFilter(self::$message)],
[TwigNodeProvider::getTransTag(self::$message)],
// with named arguments
[TwigNodeProvider::getTransFilter(self::$message, null, [
'arguments' => new ArrayExpression([], 0),
])],
[TwigNodeProvider::getTransChoiceFilter(self::$message), null, [
'arguments' => new ArrayExpression([], 0),
]],
];
}
}

View File

@ -57,10 +57,8 @@ class TranslationNodeVisitorTest extends TestCase
return [
[TwigNodeProvider::getTransFilter($message), [[$message, null]]],
[TwigNodeProvider::getTransChoiceFilter($message), [[$message, null]]],
[TwigNodeProvider::getTransTag($message), [[$message, null]]],
[TwigNodeProvider::getTransFilter($message, $domain), [[$message, $domain]]],
[TwigNodeProvider::getTransChoiceFilter($message, $domain), [[$message, $domain]]],
[TwigNodeProvider::getTransTag($message, $domain), [[$message, $domain]]],
];
}

View File

@ -53,24 +53,6 @@ class TwigNodeProvider
);
}
public static function getTransChoiceFilter($message, $domain = null, $arguments = null)
{
if (!$arguments) {
$arguments = $domain ? [
new ConstantExpression(0, 0),
new ArrayExpression([], 0),
new ConstantExpression($domain, 0),
] : [];
}
return new FilterExpression(
new ConstantExpression($message, 0),
new ConstantExpression('transchoice', 0),
new Node($arguments),
0
);
}
public static function getTransTag($message, $domain = null)
{
return new TransNode(

View File

@ -50,15 +50,6 @@ class TwigExtractorTest extends TestCase
}
}
/**
* @group legacy
* @dataProvider getLegacyExtractData
*/
public function testLegacyExtract($template, $messages)
{
$this->testExtract($template, $messages);
}
public function getExtractData()
{
return [
@ -80,24 +71,6 @@ class TwigExtractorTest extends TestCase
];
}
/**
* @group legacy
*/
public function getLegacyExtractData()
{
return [
['{{ "new key" | transchoice(1) }}', ['new key' => 'messages']],
['{{ "new key" | transchoice(1) | upper }}', ['new key' => 'messages']],
['{{ "new key" | transchoice(1, {}, "domain") }}', ['new key' => 'domain']],
// make sure 'trans_default_domain' tag is supported
['{% trans_default_domain "domain" %}{{ "new key"|transchoice }}', ['new key' => 'domain']],
// make sure this works with twig's named arguments
['{{ "new key" | transchoice(domain="domain", count=1) }}', ['new key' => 'domain']],
];
}
/**
* @expectedException \Twig\Error\Error
* @dataProvider resourcesWithSyntaxErrorsProvider

View File

@ -1,97 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\TokenParser;
use Symfony\Bridge\Twig\Node\TransNode;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Node;
use Twig\Node\TextNode;
use Twig\Token;
/**
* Token Parser for the 'transchoice' tag.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since Symfony 4.2, use the "trans" tag with a "%count%" parameter instead
*/
class TransChoiceTokenParser extends TransTokenParser
{
/**
* Parses a token and returns a node.
*
* @return Node
*
* @throws SyntaxError
*/
public function parse(Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
@trigger_error(sprintf('The "transchoice" tag is deprecated since Symfony 4.2, use the "trans" one instead with a "%%count%%" parameter in %s line %d.', $stream->getSourceContext()->getName(), $lineno), E_USER_DEPRECATED);
$vars = new ArrayExpression([], $lineno);
$count = $this->parser->getExpressionParser()->parseExpression();
$domain = null;
$locale = null;
if ($stream->test('with')) {
// {% transchoice count with vars %}
$stream->next();
$vars = $this->parser->getExpressionParser()->parseExpression();
}
if ($stream->test('from')) {
// {% transchoice count from "messages" %}
$stream->next();
$domain = $this->parser->getExpressionParser()->parseExpression();
}
if ($stream->test('into')) {
// {% transchoice count into "fr" %}
$stream->next();
$locale = $this->parser->getExpressionParser()->parseExpression();
}
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this, 'decideTransChoiceFork'], true);
if (!$body instanceof TextNode && !$body instanceof AbstractExpression) {
throw new SyntaxError('A message inside a transchoice tag must be a simple text.', $body->getTemplateLine(), $stream->getSourceContext());
}
$stream->expect(Token::BLOCK_END_TYPE);
return new TransNode($body, $domain, $count, $vars, $locale, $lineno, $this->getTag());
}
public function decideTransChoiceFork($token)
{
return $token->test(['endtranschoice']);
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'transchoice';
}
}

View File

@ -7,7 +7,6 @@
<defaults public="false" />
<service id="translator" class="Symfony\Component\Translation\IdentityTranslator" public="true" />
<service id="Symfony\Component\Translation\TranslatorInterface" alias="translator" />
<service id="Symfony\Contracts\Translation\TranslatorInterface" alias="translator" />
<service id="identity_translator" class="Symfony\Component\Translation\IdentityTranslator" />

View File

@ -21,7 +21,6 @@
</call>
<tag name="kernel.locale_aware" />
</service>
<service id="Symfony\Component\Translation\TranslatorInterface" alias="translator" />
<service id="Symfony\Contracts\Translation\TranslatorInterface" alias="translator" />
<service id="translator.logging" class="Symfony\Component\Translation\LoggingTranslator">

View File

@ -26,12 +26,6 @@ EOF
<?php echo $view['translator']->trans('single-quoted key with "quote mark at the end"') ?>
<?php echo $view['translator']->transChoice(
'{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples',
10,
['%count%' => 10]
) ?>
<?php echo $view['translator']->trans('other-domain-test-no-params-short-array', [], 'not_messages'); ?>
<?php echo $view['translator']->trans('other-domain-test-no-params-long-array', [], 'not_messages'); ?>
@ -40,10 +34,4 @@ EOF
<?php echo $view['translator']->trans('other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>
<?php echo $view['translator']->transChoice('other-domain-test-trans-choice-short-array-%count%', 10, ['%count%' => 10], 'not_messages'); ?>
<?php echo $view['translator']->transChoice('other-domain-test-trans-choice-long-array-%count%', 10, ['%count%' => 10], 'not_messages'); ?>
<?php echo $view['translator']->trans('typecast', ['a' => (int) '123'], 'not_messages'); ?>
<?php echo $view['translator']->transChoice('msg1', 10 + 1, [], 'not_messages'); ?>
<?php echo $view['translator']->transChoice('msg2', ceil(4.5), [], 'not_messages'); ?>

View File

@ -49,7 +49,7 @@
"symfony/serializer": "^4.4|^5.0",
"symfony/stopwatch": "^4.4|^5.0",
"symfony/translation": "^4.4|^5.0",
"symfony/twig-bundle": "^5.0",
"symfony/twig-bundle": "^4.4|^5.0",
"symfony/validator": "^4.4|^5.0",
"symfony/var-dumper": "^4.4|^5.0",
"symfony/workflow": "^4.4|^5.0",
@ -76,7 +76,7 @@
"symfony/serializer": "<4.4",
"symfony/stopwatch": "<4.4",
"symfony/translation": "<4.4",
"symfony/twig-bundle": "<5.0",
"symfony/twig-bundle": "<4.4",
"symfony/twig-bridge": "<4.4",
"symfony/validator": "<4.4",
"symfony/workflow": "<4.4"

View File

@ -19,7 +19,6 @@ use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
use Symfony\Component\Form\Extension\Core\Type\TransformationFailureExtension;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@ -33,14 +32,8 @@ class CoreExtension extends AbstractExtension
private $choiceListFactory;
private $translator;
/**
* @param TranslatorInterface|null $translator
*/
public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null, $translator = null)
public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null, TranslatorInterface $translator = null)
{
if (null !== $translator && !$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 3 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
$this->choiceListFactory = $choiceListFactory ?: new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor));
$this->translator = $translator;

View File

@ -15,7 +15,6 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@ -25,14 +24,8 @@ class TransformationFailureListener implements EventSubscriberInterface
{
private $translator;
/**
* @param TranslatorInterface|null $translator
*/
public function __construct($translator = null)
public function __construct(TranslatorInterface $translator = null)
{
if (null !== $translator && !$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->translator = $translator;
}

View File

@ -20,7 +20,7 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class FileType extends AbstractType
{

View File

@ -14,7 +14,6 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\EventListener\TransformationFailureListener;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@ -24,14 +23,8 @@ class TransformationFailureExtension extends AbstractTypeExtension
{
private $translator;
/**
* @param TranslatorInterface|null $translator
*/
public function __construct($translator = null)
public function __construct(TranslatorInterface $translator = null)
{
if (null !== $translator && !$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->translator = $translator;
}

View File

@ -13,7 +13,6 @@ namespace Symfony\Component\Form\Extension\Csrf;
use Symfony\Component\Form\AbstractExtension;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@ -27,16 +26,8 @@ class CsrfExtension extends AbstractExtension
private $translator;
private $translationDomain;
/**
* @param CsrfTokenManagerInterface $tokenManager The CSRF token manager
* @param TranslatorInterface|null $translator The translator for translating error messages
* @param string|null $translationDomain The translation domain for translating
*/
public function __construct(CsrfTokenManagerInterface $tokenManager, $translator = null, string $translationDomain = null)
public function __construct(CsrfTokenManagerInterface $tokenManager, TranslatorInterface $translator = null, string $translationDomain = null)
{
if (null !== $translator && !$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 2 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->tokenManager = $tokenManager;
$this->translator = $translator;
$this->translationDomain = $translationDomain;

View File

@ -18,7 +18,6 @@ use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Util\ServerParams;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@ -41,14 +40,8 @@ class CsrfValidationListener implements EventSubscriberInterface
];
}
/**
* @param TranslatorInterface|null $translator
*/
public function __construct(string $fieldName, CsrfTokenManagerInterface $tokenManager, string $tokenId, string $errorMessage, $translator = null, string $translationDomain = null, ServerParams $serverParams = null)
public function __construct(string $fieldName, CsrfTokenManagerInterface $tokenManager, string $tokenId, string $errorMessage, TranslatorInterface $translator = null, string $translationDomain = null, ServerParams $serverParams = null)
{
if (null !== $translator && !$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 5 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->fieldName = $fieldName;
$this->tokenManager = $tokenManager;
$this->tokenId = $tokenId;

View File

@ -20,7 +20,6 @@ use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Util\ServerParams;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@ -35,14 +34,8 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
private $translationDomain;
private $serverParams;
/**
* @param TranslatorInterface|null $translator
*/
public function __construct(CsrfTokenManagerInterface $defaultTokenManager, bool $defaultEnabled = true, string $defaultFieldName = '_token', $translator = null, string $translationDomain = null, ServerParams $serverParams = null)
public function __construct(CsrfTokenManagerInterface $defaultTokenManager, bool $defaultEnabled = true, string $defaultFieldName = '_token', TranslatorInterface $translator = null, string $translationDomain = null, ServerParams $serverParams = null)
{
if (null !== $translator && !$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 4 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->defaultTokenManager = $defaultTokenManager;
$this->defaultEnabled = $defaultEnabled;
$this->defaultFieldName = $defaultFieldName;

View File

@ -15,7 +15,6 @@ use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@ -27,14 +26,8 @@ class UploadValidatorExtension extends AbstractTypeExtension
private $translator;
private $translationDomain;
/**
* @param TranslatorInterface $translator
*/
public function __construct($translator, string $translationDomain = null)
public function __construct(TranslatorInterface $translator, string $translationDomain = null)
{
if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->translator = $translator;
$this->translationDomain = $translationDomain;
}

View File

@ -17,7 +17,7 @@ use Symfony\Component\Form\NativeRequestHandler;
use Symfony\Component\Form\RequestHandlerInterface;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class FileTypeTest extends BaseTypeTest
{

View File

@ -15,6 +15,7 @@ use Symfony\Component\Form\Extension\Validator\Type\UploadValidatorExtension;
use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class UploadValidatorExtensionTest extends TypeTestCase
@ -38,18 +39,13 @@ class UploadValidatorExtensionTest extends TypeTestCase
}
}
class DummyTranslator implements TranslatorInterface
class DummyTranslator implements TranslatorInterface, LocaleAwareInterface
{
public function trans($id, array $parameters = [], $domain = null, $locale = null)
{
return 'translated max {{ max }}!';
}
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
{
return 'translated max {{ max }}!';
}
public function setLocale($locale)
{
}

View File

@ -8,6 +8,7 @@ CHANGELOG
* removed `ConfigDataCollector::getApplicationName()`
* removed `ConfigDataCollector::getApplicationVersion()`
* removed support for `Symfony\Component\Templating\EngineInterface` in `HIncludeFragmentRenderer`, use a `Twig\Environment` only
* removed `TranslatorListener`
4.3.0
-----

View File

@ -1,80 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3 and will be removed in 5.0, use LocaleAwareListener instead.', TranslatorListener::class), E_USER_DEPRECATED);
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
/**
* Synchronizes the locale between the request and the translator.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since Symfony 4.3, use LocaleAwareListener instead
*/
class TranslatorListener implements EventSubscriberInterface
{
private $translator;
private $requestStack;
/**
* @param LocaleAwareInterface $translator
*/
public function __construct($translator, RequestStack $requestStack)
{
if (!$translator instanceof TranslatorInterface && !$translator instanceof LocaleAwareInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, LocaleAwareInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->translator = $translator;
$this->requestStack = $requestStack;
}
public function onKernelRequest(GetResponseEvent $event)
{
$this->setLocale($event->getRequest());
}
public function onKernelFinishRequest(FinishRequestEvent $event)
{
if (null === $parentRequest = $this->requestStack->getParentRequest()) {
return;
}
$this->setLocale($parentRequest);
}
public static function getSubscribedEvents()
{
return [
// must be registered after the Locale listener
KernelEvents::REQUEST => [['onKernelRequest', 10]],
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],
];
}
private function setLocale(Request $request)
{
try {
$this->translator->setLocale($request->getLocale());
} catch (\InvalidArgumentException $e) {
$this->translator->setLocale($request->getDefaultLocale());
}
}
}

View File

@ -1,122 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\EventListener\TranslatorListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
/**
* @group legacy
*/
class TranslatorListenerTest extends TestCase
{
private $listener;
private $translator;
private $requestStack;
protected function setUp()
{
$this->translator = $this->getMockBuilder(LocaleAwareInterface::class)->getMock();
$this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
$this->listener = new TranslatorListener($this->translator, $this->requestStack);
}
public function testLocaleIsSetInOnKernelRequest()
{
$this->translator
->expects($this->once())
->method('setLocale')
->with($this->equalTo('fr'));
$event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);
}
public function testDefaultLocaleIsUsedOnExceptionsInOnKernelRequest()
{
$this->translator
->expects($this->at(0))
->method('setLocale')
->willThrowException(new \InvalidArgumentException());
$this->translator
->expects($this->at(1))
->method('setLocale')
->with($this->equalTo('en'));
$event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);
}
public function testLocaleIsSetInOnKernelFinishRequestWhenParentRequestExists()
{
$this->translator
->expects($this->once())
->method('setLocale')
->with($this->equalTo('fr'));
$this->setMasterRequest($this->createRequest('fr'));
$event = new FinishRequestEvent($this->createHttpKernel(), $this->createRequest('de'), HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
public function testLocaleIsNotSetInOnKernelFinishRequestWhenParentRequestDoesNotExist()
{
$this->translator
->expects($this->never())
->method('setLocale');
$event = new FinishRequestEvent($this->createHttpKernel(), $this->createRequest('de'), HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
public function testDefaultLocaleIsUsedOnExceptionsInOnKernelFinishRequest()
{
$this->translator
->expects($this->at(0))
->method('setLocale')
->willThrowException(new \InvalidArgumentException());
$this->translator
->expects($this->at(1))
->method('setLocale')
->with($this->equalTo('en'));
$this->setMasterRequest($this->createRequest('fr'));
$event = new FinishRequestEvent($this->createHttpKernel(), $this->createRequest('de'), HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
private function createHttpKernel()
{
return $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
}
private function createRequest($locale)
{
$request = new Request();
$request->setLocale($locale);
return $request;
}
private function setMasterRequest($request)
{
$this->requestStack
->expects($this->any())
->method('getParentRequest')
->willReturn($request);
}
}

View File

@ -1,6 +1,19 @@
CHANGELOG
=========
5.0.0
-----
* removed `TranslatorInterface`
* removed `MessageSelector`
* removed `ChoiceMessageFormatterInterface`
* removed `PluralizationRule`
* removed `Interval`
* removed `transChoice()` methods, use the trans() method instead with a %count% parameter
* removed `FileDumper::setBackup()` and `TranslationWriter::disableBackup()`
* removed `MessageFormatter::choiceFormat()`
* added argument `$filename` to `PhpExtractor::parseTokens()`
4.3.0
-----

View File

@ -13,14 +13,13 @@ namespace Symfony\Component\Translation;
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorInterface, TranslatorBagInterface, WarmableInterface
class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface, WarmableInterface
{
const MESSAGE_DEFINED = 0;
const MESSAGE_MISSING = 1;
@ -36,11 +35,8 @@ class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorIn
/**
* @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
*/
public function __construct($translator)
public function __construct(TranslatorInterface $translator)
{
if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) {
throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', \get_class($translator)));
}
@ -59,24 +55,6 @@ class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorIn
return $trans;
}
/**
* {@inheritdoc}
*
* @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
*/
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
{
if ($this->translator instanceof TranslatorInterface) {
$trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
} else {
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
}
$this->collectMessage($locale, $domain, $id, $trans, ['%count%' => $number] + $parameters);
return $trans;
}
/**
* {@inheritdoc}
*/

View File

@ -42,22 +42,6 @@ abstract class FileDumper implements DumperInterface
$this->relativePathTemplate = $relativePathTemplate;
}
/**
* Sets backup flag.
*
* @param bool $backup
*
* @deprecated since Symfony 4.1
*/
public function setBackup($backup)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
if (false !== $backup) {
throw new \LogicException('The backup feature is no longer supported.');
}
}
/**
* {@inheritdoc}
*/

View File

@ -48,30 +48,12 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
',',
self::DOMAIN_TOKEN,
],
[
'->',
'transChoice',
'(',
self::MESSAGE_TOKEN,
',',
self::METHOD_ARGUMENTS_TOKEN,
',',
self::METHOD_ARGUMENTS_TOKEN,
',',
self::DOMAIN_TOKEN,
],
[
'->',
'trans',
'(',
self::MESSAGE_TOKEN,
],
[
'->',
'transChoice',
'(',
self::MESSAGE_TOKEN,
],
];
/**
@ -194,18 +176,9 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
/**
* Extracts trans message from PHP tokens.
*
* @param array $tokens
* @param MessageCatalogue $catalog
* @param string $filename
*/
protected function parseTokens($tokens, MessageCatalogue $catalog/*, string $filename*/)
protected function parseTokens(array $tokens, MessageCatalogue $catalog, string $filename)
{
if (\func_num_args() < 3 && __CLASS__ !== \get_class($this) && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface) {
@trigger_error(sprintf('The "%s()" method will have a new "string $filename" argument in version 5.0, not defining it is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED);
}
$filename = 2 < \func_num_args() ? \func_get_arg(2) : '';
$tokenIterator = new \ArrayIterator($tokens);
for ($key = 0; $key < $tokenIterator->count(); ++$key) {

View File

@ -1,32 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Formatter;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*
* @deprecated since Symfony 4.2, use MessageFormatterInterface::format() with a %count% parameter instead
*/
interface ChoiceMessageFormatterInterface
{
/**
* Formats a localized message pattern with given arguments.
*
* @param string $message The message (may also be an object that can be cast to string)
* @param int $number The number to use to find the indice of the message
* @param string $locale The message locale
* @param array $parameters An array of parameters for the message
*
* @return string
*/
public function choiceFormat($message, $number, $locale, array $parameters = []);
}

View File

@ -12,14 +12,12 @@
namespace Symfony\Component\Translation\Formatter;
use Symfony\Component\Translation\IdentityTranslator;
use Symfony\Component\Translation\MessageSelector;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class MessageFormatter implements MessageFormatterInterface, IntlFormatterInterface, ChoiceMessageFormatterInterface
class MessageFormatter implements MessageFormatterInterface, IntlFormatterInterface
{
private $translator;
private $intlFormatter;
@ -27,14 +25,8 @@ class MessageFormatter implements MessageFormatterInterface, IntlFormatterInterf
/**
* @param TranslatorInterface|null $translator An identity translator to use as selector for pluralization
*/
public function __construct($translator = null, IntlFormatterInterface $intlFormatter = null)
public function __construct(TranslatorInterface $translator = null, IntlFormatterInterface $intlFormatter = null)
{
if ($translator instanceof MessageSelector) {
$translator = new IdentityTranslator($translator);
} elseif (null !== $translator && !$translator instanceof TranslatorInterface && !$translator instanceof LegacyTranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
$this->translator = $translator ?? new IdentityTranslator();
$this->intlFormatter = $intlFormatter ?? new IntlFormatter();
}
@ -58,22 +50,4 @@ class MessageFormatter implements MessageFormatterInterface, IntlFormatterInterf
{
return $this->intlFormatter->formatIntl($message, $locale, $parameters);
}
/**
* {@inheritdoc}
*
* @deprecated since Symfony 4.2, use format() with a %count% parameter instead
*/
public function choiceFormat($message, $number, $locale, array $parameters = [])
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the format() one instead with a %%count%% parameter.', __METHOD__), E_USER_DEPRECATED);
$parameters = ['%count%' => $number] + $parameters;
if ($this->translator instanceof TranslatorInterface) {
return $this->format($message, $locale, $parameters);
}
return $this->format($this->translator->transChoice($message, $number, [], null, $locale), $locale, $parameters);
}
}

View File

@ -11,7 +11,7 @@
namespace Symfony\Component\Translation;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorTrait;
@ -20,42 +20,7 @@ use Symfony\Contracts\Translation\TranslatorTrait;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class IdentityTranslator implements LegacyTranslatorInterface, TranslatorInterface
class IdentityTranslator implements TranslatorInterface, LocaleAwareInterface
{
use TranslatorTrait;
private $selector;
/**
* @param MessageSelector|null $selector The message selector for pluralization
*/
public function __construct(MessageSelector $selector = null)
{
$this->selector = $selector;
if (__CLASS__ !== \get_class($this)) {
@trigger_error(sprintf('Calling "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
}
}
/**
* {@inheritdoc}
*
* @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
*/
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED);
if ($this->selector) {
return strtr($this->selector->choose((string) $id, $number, $locale ?: $this->getLocale()), $parameters);
}
return $this->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
}
private function getPluralizationRule(int $number, string $locale): int
{
return PluralizationRules::get($number, $locale, false);
}
}

View File

@ -1,112 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2, use IdentityTranslator instead.', Interval::class), E_USER_DEPRECATED);
use Symfony\Component\Translation\Exception\InvalidArgumentException;
/**
* Tests if a given number belongs to a given math interval.
*
* An interval can represent a finite set of numbers:
*
* {1,2,3,4}
*
* An interval can represent numbers between two numbers:
*
* [1, +Inf]
* ]-1,2[
*
* The left delimiter can be [ (inclusive) or ] (exclusive).
* The right delimiter can be [ (exclusive) or ] (inclusive).
* Beside numbers, you can use -Inf and +Inf for the infinite.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
* @deprecated since Symfony 4.2, use IdentityTranslator instead
*/
class Interval
{
/**
* Tests if the given number is in the math interval.
*
* @param int $number A number
* @param string $interval An interval
*
* @return bool
*
* @throws InvalidArgumentException
*/
public static function test($number, $interval)
{
$interval = trim($interval);
if (!preg_match('/^'.self::getIntervalRegexp().'$/x', $interval, $matches)) {
throw new InvalidArgumentException(sprintf('"%s" is not a valid interval.', $interval));
}
if ($matches[1]) {
foreach (explode(',', $matches[2]) as $n) {
if ($number == $n) {
return true;
}
}
} else {
$leftNumber = self::convertNumber($matches['left']);
$rightNumber = self::convertNumber($matches['right']);
return
('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
&& (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
;
}
return false;
}
/**
* Returns a Regexp that matches valid intervals.
*
* @return string A Regexp (without the delimiters)
*/
public static function getIntervalRegexp()
{
return <<<EOF
({\s*
(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
\s*})
|
(?P<left_delimiter>[\[\]])
\s*
(?P<left>-Inf|\-?\d+(\.\d+)?)
\s*,\s*
(?P<right>\+?Inf|\-?\d+(\.\d+)?)
\s*
(?P<right_delimiter>[\[\]])
EOF;
}
private static function convertNumber($number)
{
if ('-Inf' === $number) {
return log(0);
} elseif ('+Inf' === $number || 'Inf' === $number) {
return -log(0);
}
return (float) $number;
}
}

View File

@ -13,14 +13,13 @@ namespace Symfony\Component\Translation;
use Psr\Log\LoggerInterface;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class LoggingTranslator implements TranslatorInterface, LegacyTranslatorInterface, TranslatorBagInterface
class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface
{
/**
* @var TranslatorInterface|TranslatorBagInterface
@ -33,11 +32,8 @@ class LoggingTranslator implements TranslatorInterface, LegacyTranslatorInterfac
* @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
* @param LoggerInterface $logger
*/
public function __construct($translator, LoggerInterface $logger)
public function __construct(TranslatorInterface $translator, LoggerInterface $logger)
{
if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
}
if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) {
throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', \get_class($translator)));
}
@ -57,26 +53,6 @@ class LoggingTranslator implements TranslatorInterface, LegacyTranslatorInterfac
return $trans;
}
/**
* {@inheritdoc}
*
* @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
*/
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED);
if ($this->translator instanceof TranslatorInterface) {
$trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
} else {
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
}
$this->log($id, $domain, $locale);
return $trans;
}
/**
* {@inheritdoc}
*/

View File

@ -1,98 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2, use IdentityTranslator instead.', MessageSelector::class), E_USER_DEPRECATED);
use Symfony\Component\Translation\Exception\InvalidArgumentException;
/**
* MessageSelector.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since Symfony 4.2, use IdentityTranslator instead.
*/
class MessageSelector
{
/**
* Given a message with different plural translations separated by a
* pipe (|), this method returns the correct portion of the message based
* on the given number, locale and the pluralization rules in the message
* itself.
*
* The message supports two different types of pluralization rules:
*
* interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples
* indexed: There is one apple|There are %count% apples
*
* The indexed solution can also contain labels (e.g. one: There is one apple).
* This is purely for making the translations more clear - it does not
* affect the functionality.
*
* The two methods can also be mixed:
* {0} There are no apples|one: There is one apple|more: There are %count% apples
*
* @param string $message The message being translated
* @param int|float $number The number of items represented for the message
* @param string $locale The locale to use for choosing
*
* @return string
*
* @throws InvalidArgumentException
*/
public function choose($message, $number, $locale)
{
$parts = [];
if (preg_match('/^\|++$/', $message)) {
$parts = explode('|', $message);
} elseif (preg_match_all('/(?:\|\||[^\|])++/', $message, $matches)) {
$parts = $matches[0];
}
$explicitRules = [];
$standardRules = [];
foreach ($parts as $part) {
$part = trim(str_replace('||', '|', $part));
if (preg_match('/^(?P<interval>'.Interval::getIntervalRegexp().')\s*(?P<message>.*?)$/xs', $part, $matches)) {
$explicitRules[$matches['interval']] = $matches['message'];
} elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
$standardRules[] = $matches[1];
} else {
$standardRules[] = $part;
}
}
// try to match an explicit rule, then fallback to the standard ones
foreach ($explicitRules as $interval => $m) {
if (Interval::test($number, $interval)) {
return $m;
}
}
$position = PluralizationRules::get($number, $locale);
if (!isset($standardRules[$position])) {
// when there's exactly one rule given, and that rule is a standard
// rule, use this rule
if (1 === \count($parts) && isset($standardRules[0])) {
return $standardRules[0];
}
throw new InvalidArgumentException(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").', $message, $locale, $number));
}
return $standardRules[$position];
}
}

View File

@ -1,218 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
/**
* Returns the plural rules for a given locale.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since Symfony 4.2, use IdentityTranslator instead
*/
class PluralizationRules
{
private static $rules = [];
/**
* Returns the plural position to use for the given locale and number.
*
* @param int $number The number
* @param string $locale The locale
*
* @return int The plural position
*/
public static function get($number, $locale/*, bool $triggerDeprecation = true*/)
{
if (3 > \func_num_args() || \func_get_arg(2)) {
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED);
}
if ('pt_BR' === $locale) {
// temporary set a locale for brazilian
$locale = 'xbr';
}
if (\strlen($locale) > 3) {
$locale = substr($locale, 0, -\strlen(strrchr($locale, '_')));
}
if (isset(self::$rules[$locale])) {
$return = self::$rules[$locale]($number);
if (!\is_int($return) || $return < 0) {
return 0;
}
return $return;
}
/*
* The plural rules are derived from code of the Zend Framework (2010-09-25),
* which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
* Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
*/
switch ($locale) {
case 'az':
case 'bo':
case 'dz':
case 'id':
case 'ja':
case 'jv':
case 'ka':
case 'km':
case 'kn':
case 'ko':
case 'ms':
case 'th':
case 'tr':
case 'vi':
case 'zh':
return 0;
case 'af':
case 'bn':
case 'bg':
case 'ca':
case 'da':
case 'de':
case 'el':
case 'en':
case 'eo':
case 'es':
case 'et':
case 'eu':
case 'fa':
case 'fi':
case 'fo':
case 'fur':
case 'fy':
case 'gl':
case 'gu':
case 'ha':
case 'he':
case 'hu':
case 'is':
case 'it':
case 'ku':
case 'lb':
case 'ml':
case 'mn':
case 'mr':
case 'nah':
case 'nb':
case 'ne':
case 'nl':
case 'nn':
case 'no':
case 'oc':
case 'om':
case 'or':
case 'pa':
case 'pap':
case 'ps':
case 'pt':
case 'so':
case 'sq':
case 'sv':
case 'sw':
case 'ta':
case 'te':
case 'tk':
case 'ur':
case 'zu':
return (1 == $number) ? 0 : 1;
case 'am':
case 'bh':
case 'fil':
case 'fr':
case 'gun':
case 'hi':
case 'hy':
case 'ln':
case 'mg':
case 'nso':
case 'xbr':
case 'ti':
case 'wa':
return ((0 == $number) || (1 == $number)) ? 0 : 1;
case 'be':
case 'bs':
case 'hr':
case 'ru':
case 'sh':
case 'sr':
case 'uk':
return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
case 'cs':
case 'sk':
return (1 == $number) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2);
case 'ga':
return (1 == $number) ? 0 : ((2 == $number) ? 1 : 2);
case 'lt':
return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
case 'sl':
return (1 == $number % 100) ? 0 : ((2 == $number % 100) ? 1 : (((3 == $number % 100) || (4 == $number % 100)) ? 2 : 3));
case 'mk':
return (1 == $number % 10) ? 0 : 1;
case 'mt':
return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3));
case 'lv':
return (0 == $number) ? 0 : (((1 == $number % 10) && (11 != $number % 100)) ? 1 : 2);
case 'pl':
return (1 == $number) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2);
case 'cy':
return (1 == $number) ? 0 : ((2 == $number) ? 1 : (((8 == $number) || (11 == $number)) ? 2 : 3));
case 'ro':
return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2);
case 'ar':
return (0 == $number) ? 0 : ((1 == $number) ? 1 : ((2 == $number) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5))));
default:
return 0;
}
}
/**
* Overrides the default plural rule for a given locale.
*
* @param callable $rule A PHP callable
* @param string $locale The locale
*/
public static function set(callable $rule, $locale)
{
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED);
if ('pt_BR' === $locale) {
// temporary set a locale for brazilian
$locale = 'xbr';
}
if (\strlen($locale) > 3) {
$locale = substr($locale, 0, -\strlen(strrchr($locale, '_')));
}
self::$rules[$locale] = $rule;
}
}

View File

@ -79,30 +79,6 @@ class DataCollectorTranslatorTest extends TestCase
$this->assertEquals($expectedMessages, $collector->getCollectedMessages());
}
/**
* @group legacy
*/
public function testCollectMessagesTransChoice()
{
$collector = $this->createCollector();
$collector->setFallbackLocales(['fr', 'ru']);
$collector->transChoice('choice', 0);
$expectedMessages = [];
$expectedMessages[] = [
'id' => 'choice',
'translation' => 'choice',
'locale' => 'en',
'domain' => 'messages',
'state' => DataCollectorTranslator::MESSAGE_MISSING,
'parameters' => ['%count%' => 0],
'transChoiceNumber' => 0,
];
$this->assertEquals($expectedMessages, $collector->getCollectedMessages());
}
private function createCollector()
{
$translator = new Translator('en');

View File

@ -50,7 +50,6 @@ EOF;
'single-quoted key with "quote mark at the end"' => 'prefixsingle-quoted key with "quote mark at the end"',
$expectedHeredoc => 'prefix'.$expectedHeredoc,
$expectedNowdoc => 'prefix'.$expectedNowdoc,
'{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples' => 'prefix{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples',
'concatenated message with heredoc and nowdoc' => 'prefixconcatenated message with heredoc and nowdoc',
'default domain' => 'prefixdefault domain',
],
@ -59,11 +58,7 @@ EOF;
'other-domain-test-no-params-long-array' => 'prefixother-domain-test-no-params-long-array',
'other-domain-test-params-short-array' => 'prefixother-domain-test-params-short-array',
'other-domain-test-params-long-array' => 'prefixother-domain-test-params-long-array',
'other-domain-test-trans-choice-short-array-%count%' => 'prefixother-domain-test-trans-choice-short-array-%count%',
'other-domain-test-trans-choice-long-array-%count%' => 'prefixother-domain-test-trans-choice-long-array-%count%',
'typecast' => 'prefixtypecast',
'msg1' => 'prefixmsg1',
'msg2' => 'prefixmsg2',
],
];
$actualCatalogue = $catalogue->all();
@ -72,7 +67,7 @@ EOF;
$filename = str_replace(\DIRECTORY_SEPARATOR, '/', __DIR__).'/../fixtures/extractor/translation.html.php';
$this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('single-quoted key'));
$this->assertEquals(['sources' => [$filename.':43']], $catalogue->getMetadata('other-domain-test-no-params-short-array', 'not_messages'));
$this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('other-domain-test-no-params-short-array', 'not_messages'));
}
public function resourcesProvider()

View File

@ -24,15 +24,6 @@ class MessageFormatterTest extends TestCase
$this->assertEquals($expected, $this->getMessageFormatter()->format($message, 'en', $parameters));
}
/**
* @dataProvider getTransChoiceMessages
* @group legacy
*/
public function testFormatPlural($expected, $message, $number, $parameters)
{
$this->assertEquals($expected, $this->getMessageFormatter()->choiceFormat($message, $number, 'fr', $parameters));
}
public function getTransMessages()
{
return [
@ -53,29 +44,6 @@ class MessageFormatterTest extends TestCase
];
}
public function getTransChoiceMessages()
{
return [
['Il y a 0 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, ['%count%' => 0]],
['Il y a 1 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, ['%count%' => 1]],
['Il y a 10 pommes', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, ['%count%' => 10]],
['Il y a 0 pomme', 'Il y a %count% pomme|Il y a %count% pommes', 0, ['%count%' => 0]],
['Il y a 1 pomme', 'Il y a %count% pomme|Il y a %count% pommes', 1, ['%count%' => 1]],
['Il y a 10 pommes', 'Il y a %count% pomme|Il y a %count% pommes', 10, ['%count%' => 10]],
['Il y a 0 pomme', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, ['%count%' => 0]],
['Il y a 1 pomme', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, ['%count%' => 1]],
['Il y a 10 pommes', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, ['%count%' => 10]],
['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, ['%count%' => 0]],
['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, ['%count%' => 1]],
['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, ['%count%' => 10]],
['Il y a 0 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, ['%count%' => 0]],
];
}
private function getMessageFormatter()
{
return new MessageFormatter();

View File

@ -1,52 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Translation\Interval;
/**
* @group legacy
*/
class IntervalTest extends TestCase
{
/**
* @dataProvider getTests
*/
public function testTest($expected, $number, $interval)
{
$this->assertEquals($expected, Interval::test($number, $interval));
}
/**
* @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
*/
public function testTestException()
{
Interval::test(1, 'foobar');
}
public function getTests()
{
return [
[true, 3, '{1,2, 3 ,4}'],
[false, 10, '{1,2, 3 ,4}'],
[false, 3, '[1,2]'],
[true, 1, '[1,2]'],
[true, 2, '[1,2]'],
[false, 1, ']1,2['],
[false, 2, ']1,2['],
[true, log(0), '[-Inf,2['],
[true, -log(0), '[-2,+Inf]'],
];
}
}

View File

@ -12,7 +12,6 @@
namespace Symfony\Component\Translation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\LoggingTranslator;
use Symfony\Component\Translation\Translator;
@ -30,39 +29,4 @@ class LoggingTranslatorTest extends TestCase
$loggableTranslator = new LoggingTranslator($translator, $logger);
$loggableTranslator->trans('bar');
}
/**
* @group legacy
*/
public function testTransChoiceFallbackIsLogged()
{
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logger->expects($this->once())
->method('debug')
->with('Translation use fallback catalogue.')
;
$translator = new Translator('ar');
$translator->setFallbackLocales(['en']);
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', ['some_message2' => 'one thing|%count% things'], 'en');
$loggableTranslator = new LoggingTranslator($translator, $logger);
$loggableTranslator->transChoice('some_message2', 10, ['%count%' => 10]);
}
/**
* @group legacy
*/
public function testTransChoiceWithNoTranslationIsLogged()
{
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logger->expects($this->exactly(1))
->method('warning')
->with('Translation not found.')
;
$translator = new Translator('ar');
$loggableTranslator = new LoggingTranslator($translator, $logger);
$loggableTranslator->transChoice('some_message2', 10, ['%count%' => 10]);
}
}

View File

@ -1,140 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Translation\MessageSelector;
/**
* @group legacy
*/
class MessageSelectorTest extends TestCase
{
/**
* @dataProvider getChooseTests
*/
public function testChoose($expected, $id, $number)
{
$selector = new MessageSelector();
$this->assertEquals($expected, $selector->choose($id, $number, 'en'));
}
public function testReturnMessageIfExactlyOneStandardRuleIsGiven()
{
$selector = new MessageSelector();
$this->assertEquals('There are two apples', $selector->choose('There are two apples', 2, 'en'));
}
/**
* @dataProvider getNonMatchingMessages
* @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
*/
public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number)
{
$selector = new MessageSelector();
$selector->choose($id, $number, 'en');
}
public function getNonMatchingMessages()
{
return [
['{0} There are no apples|{1} There is one apple', 2],
['{1} There is one apple|]1,Inf] There are %count% apples', 0],
['{1} There is one apple|]2,Inf] There are %count% apples', 2],
['{0} There are no apples|There is one apple', 2],
];
}
public function getChooseTests()
{
return [
['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['There are no apples', '{0}There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1],
['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf]There are %count% apples', 10],
['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
['There are %count% apples', 'There is one apple|There are %count% apples', 0],
['There is one apple', 'There is one apple|There are %count% apples', 1],
['There are %count% apples', 'There is one apple|There are %count% apples', 10],
['There are %count% apples', 'one: There is one apple|more: There are %count% apples', 0],
['There is one apple', 'one: There is one apple|more: There are %count% apples', 1],
['There are %count% apples', 'one: There is one apple|more: There are %count% apples', 10],
['There are no apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 0],
['There is one apple', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 1],
['There are %count% apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 10],
['', '{0}|{1} There is one apple|]1,Inf] There are %count% apples', 0],
['', '{0} There are no apples|{1}|]1,Inf] There are %count% apples', 1],
// Indexed only tests which are Gettext PoFile* compatible strings.
['There are %count% apples', 'There is one apple|There are %count% apples', 0],
['There is one apple', 'There is one apple|There are %count% apples', 1],
['There are %count% apples', 'There is one apple|There are %count% apples', 2],
// Tests for float numbers
['There is almost one apple', '{0} There are no apples|]0,1[ There is almost one apple|{1} There is one apple|[1,Inf] There is more than one apple', 0.7],
['There is one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1],
['There is more than one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1.7],
['There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0],
['There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0.0],
['There are no apples', '{0.0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0],
// Test texts with new-lines
// with double-quotes and \n in id & double-quotes and actual newlines in text
["This is a text with a\n new-line in it. Selector = 0.", '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 0],
// with double-quotes and \n in id and single-quotes and actual newlines in text
["This is a text with a\n new-line in it. Selector = 1.", '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 1],
["This is a text with a\n new-line in it. Selector > 1.", '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 5],
// with double-quotes and id split accros lines
['This is a text with a
new-line in it. Selector = 1.', '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 1],
// with single-quotes and id split accros lines
['This is a text with a
new-line in it. Selector > 1.', '{0}This is a text with a
new-line in it. Selector = 0.|{1}This is a text with a
new-line in it. Selector = 1.|[1,Inf]This is a text with a
new-line in it. Selector > 1.', 5],
// with single-quotes and \n in text
['This is a text with a\nnew-line in it. Selector = 0.', '{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.', 0],
// with double-quotes and id split accros lines
["This is a text with a\nnew-line in it. Selector = 1.", "{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.", 1],
// esacape pipe
['This is a text with | in it. Selector = 0.', '{0}This is a text with || in it. Selector = 0.|{1}This is a text with || in it. Selector = 1.', 0],
// Empty plural set (2 plural forms) from a .PO file
['', '|', 1],
// Empty plural set (3 plural forms) from a .PO file
['', '||', 1],
];
}
}

View File

@ -1,124 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Translation\PluralizationRules;
/**
* Test should cover all languages mentioned on http://translate.sourceforge.net/wiki/l10n/pluralforms
* and Plural forms mentioned on http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms.
*
* See also https://developer.mozilla.org/en/Localization_and_Plurals which mentions 15 rules having a maximum of 6 forms.
* The mozilla code is also interesting to check for.
*
* As mentioned by chx http://drupal.org/node/1273968 we can cover all by testing number from 0 to 199
*
* The goal to cover all languages is to far fetched so this test case is smaller.
*
* @author Clemens Tolboom clemens@build2be.nl
*
* @group legacy
*/
class PluralizationRulesTest extends TestCase
{
/**
* We test failed langcode here.
*
* TODO: The languages mentioned in the data provide need to get fixed somehow within PluralizationRules.
*
* @dataProvider failingLangcodes
*/
public function testFailedLangcodes($nplural, $langCodes)
{
$matrix = $this->generateTestData($langCodes);
$this->validateMatrix($nplural, $matrix, false);
}
/**
* @dataProvider successLangcodes
*/
public function testLangcodes($nplural, $langCodes)
{
$matrix = $this->generateTestData($langCodes);
$this->validateMatrix($nplural, $matrix);
}
/**
* This array should contain all currently known langcodes.
*
* As it is impossible to have this ever complete we should try as hard as possible to have it almost complete.
*
* @return array
*/
public function successLangcodes()
{
return [
['1', ['ay', 'bo', 'cgg', 'dz', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky']],
['2', ['nl', 'fr', 'en', 'de', 'de_GE', 'hy', 'hy_AM']],
['3', ['be', 'bs', 'cs', 'hr']],
['4', ['cy', 'mt', 'sl']],
['6', ['ar']],
];
}
/**
* This array should be at least empty within the near future.
*
* This both depends on a complete list trying to add above as understanding
* the plural rules of the current failing languages.
*
* @return array with nplural together with langcodes
*/
public function failingLangcodes()
{
return [
['1', ['fa']],
['2', ['jbo']],
['3', ['cbs']],
['4', ['gd', 'kw']],
['5', ['ga']],
];
}
/**
* We validate only on the plural coverage. Thus the real rules is not tested.
*
* @param string $nplural Plural expected
* @param array $matrix Containing langcodes and their plural index values
* @param bool $expectSuccess
*/
protected function validateMatrix($nplural, $matrix, $expectSuccess = true)
{
foreach ($matrix as $langCode => $data) {
$indexes = array_flip($data);
if ($expectSuccess) {
$this->assertEquals($nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
} else {
$this->assertNotEquals((int) $nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
}
}
}
protected function generateTestData($langCodes)
{
$matrix = [];
foreach ($langCodes as $langCode) {
for ($count = 0; $count < 200; ++$count) {
$plural = PluralizationRules::get($count, $langCode);
$matrix[$langCode][$count] = $plural;
}
}
return $matrix;
}
}

View File

@ -391,48 +391,6 @@ class TranslatorTest extends TestCase
$this->assertEquals($expected, $translator->trans($id, [], '', 'fr'));
}
/**
* @dataProvider getTransChoiceTests
* @group legacy
*/
public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain)
{
$translator = new Translator('en');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [(string) $id => $translation], $locale, $domain);
$this->assertEquals($expected, $translator->transChoice($id, $number, $parameters, $domain, $locale));
}
/**
* @dataProvider getInvalidLocalesTests
* @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
* @group legacy
*/
public function testTransChoiceInvalidLocale($locale)
{
$translator = new Translator('en');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', ['foo' => 'foofoo'], 'en');
$translator->transChoice('foo', 1, [], '', $locale);
}
/**
* @dataProvider getValidLocalesTests
* @group legacy
*/
public function testTransChoiceValidLocale($locale)
{
$translator = new Translator('en');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', ['foo' => 'foofoo'], 'en');
$translator->transChoice('foo', 1, [], '', $locale);
// no assertion. this method just asserts that no exception is thrown
$this->addToAssertionCount(1);
}
public function getTransFileTests()
{
return [
@ -480,32 +438,6 @@ class TranslatorTest extends TestCase
];
}
public function getTransChoiceTests()
{
return [
['Il y a 0 pomme', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, [], 'fr', ''],
['Il y a 1 pomme', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, [], 'fr', ''],
['Il y a 10 pommes', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, [], 'fr', ''],
['Il y a 0 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 0, [], 'fr', ''],
['Il y a 1 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 1, [], 'fr', ''],
['Il y a 10 pommes', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 10, [], 'fr', ''],
['Il y a 0 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, [], 'fr', ''],
['Il y a 1 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, [], 'fr', ''],
['Il y a 10 pommes', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, [], 'fr', ''],
['Il n\'y a aucune pomme', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 0, [], 'fr', ''],
['Il y a 1 pomme', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 1, [], 'fr', ''],
['Il y a 10 pommes', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, [], 'fr', ''],
['Il y a 0 pomme', new StringClass('{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples'), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, [], 'fr', ''],
// Override %count% with a custom value
['Il y a quelques pommes', 'one: There is one apple|more: There are %count% apples', 'one: Il y a %count% pomme|more: Il y a quelques pommes', 2, ['%count%' => 'quelques'], 'fr', ''],
];
}
public function getInvalidLocalesTests()
{
return [
@ -554,46 +486,6 @@ class TranslatorTest extends TestCase
$translator->addResource('array', ['some_message' => 'Hi {name}'], 'en', 'messages+intl-icu');
$this->assertSame('Hi Bob', $translator->trans('some_message', ['%name%' => 'Bob']));
}
/**
* @group legacy
*/
public function testTransChoiceFallback()
{
$translator = new Translator('ru');
$translator->setFallbackLocales(['en']);
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', ['some_message2' => 'one thing|%count% things'], 'en');
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, ['%count%' => 10]));
}
/**
* @group legacy
*/
public function testTransChoiceFallbackBis()
{
$translator = new Translator('ru');
$translator->setFallbackLocales(['en_US', 'en']);
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', ['some_message2' => 'one thing|%count% things'], 'en_US');
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, ['%count%' => 10]));
}
/**
* @group legacy
*/
public function testTransChoiceFallbackWithNoTranslation()
{
$translator = new Translator('ru');
$translator->setFallbackLocales(['en']);
$translator->addLoader('array', new ArrayLoader());
// consistent behavior with Translator::trans(), which returns the string
// unchanged if it can't be found
$this->assertEquals('some_message2', $translator->transChoice('some_message2', 10, ['%count%' => 10]));
}
}
class StringClass

View File

@ -12,7 +12,6 @@
namespace Symfony\Component\Translation\Tests\Writer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Translation\Dumper\DumperInterface;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Writer\TranslationWriter;
@ -29,41 +28,4 @@ class TranslationWriterTest extends TestCase
$writer->addDumper('test', $dumper);
$writer->write(new MessageCatalogue('en'), 'test');
}
/**
* @group legacy
*/
public function testDisableBackup()
{
$nonBackupDumper = new NonBackupDumper();
$backupDumper = new BackupDumper();
$writer = new TranslationWriter();
$writer->addDumper('non_backup', $nonBackupDumper);
$writer->addDumper('backup', $backupDumper);
$writer->disableBackup();
$this->assertFalse($backupDumper->backup, 'backup can be disabled if setBackup() method does exist');
}
}
class NonBackupDumper implements DumperInterface
{
public function dump(MessageCatalogue $messages, $options = [])
{
}
}
class BackupDumper implements DumperInterface
{
public $backup = true;
public function dump(MessageCatalogue $messages, $options = [])
{
}
public function setBackup($backup)
{
$this->backup = $backup;
}
}

View File

@ -26,12 +26,6 @@ EOF
<?php echo $view['translator']->trans('single-quoted key with "quote mark at the end"'); ?>
<?php echo $view['translator']->transChoice(
'{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples',
10,
['%count%' => 10]
); ?>
<?php echo $view['translator']->trans('concatenated'.' message'.<<<EOF
with heredoc
EOF
@ -48,12 +42,6 @@ EOF
<?php echo $view['translator']->trans('other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>
<?php echo $view['translator']->transChoice('other-domain-test-trans-choice-short-array-%count%', 10, ['%count%' => 10], 'not_messages'); ?>
<?php echo $view['translator']->transChoice('other-domain-test-trans-choice-long-array-%count%', 10, ['%count%' => 10], 'not_messages'); ?>
<?php echo $view['translator']->trans('typecast', ['a' => (int) '123'], 'not_messages'); ?>
<?php echo $view['translator']->transChoice('msg1', 10 + 1, [], 'not_messages'); ?>
<?php echo $view['translator']->transChoice('msg2', ceil(4.5), [], 'not_messages'); ?>
<?php echo $view['translator']->trans('default domain', [], null); ?>

View File

@ -15,21 +15,19 @@ use Symfony\Component\Config\ConfigCacheFactory;
use Symfony\Component\Config\ConfigCacheFactoryInterface;
use Symfony\Component\Config\ConfigCacheInterface;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\Exception\LogicException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\Exception\RuntimeException;
use Symfony\Component\Translation\Formatter\ChoiceMessageFormatterInterface;
use Symfony\Component\Translation\Formatter\IntlFormatterInterface;
use Symfony\Component\Translation\Formatter\MessageFormatter;
use Symfony\Component\Translation\Formatter\MessageFormatterInterface;
use Symfony\Component\Translation\Loader\LoaderInterface;
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class Translator implements LegacyTranslatorInterface, TranslatorInterface, TranslatorBagInterface
class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface
{
/**
* @var MessageCatalogueInterface[]
@ -219,42 +217,6 @@ class Translator implements LegacyTranslatorInterface, TranslatorInterface, Tran
return $this->formatter->format($catalogue->get($id, $domain), $locale, $parameters);
}
/**
* {@inheritdoc}
*
* @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
*/
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED);
if (!$this->formatter instanceof ChoiceMessageFormatterInterface) {
throw new LogicException(sprintf('The formatter "%s" does not support plural translations.', \get_class($this->formatter)));
}
if (null === $domain) {
$domain = 'messages';
}
$id = (string) $id;
$catalogue = $this->getCatalogue($locale);
$locale = $catalogue->getLocale();
while (!$catalogue->defines($id, $domain)) {
if ($cat = $catalogue->getFallbackCatalogue()) {
$catalogue = $cat;
$locale = $catalogue->getLocale();
} else {
break;
}
}
if ($this->hasIntlFormatter && $catalogue->defines($id, $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX)) {
return $this->formatter->formatIntl($catalogue->get($id, $domain), $locale, ['%count%' => $number] + $parameters);
}
return $this->formatter->choiceFormat($catalogue->get($id, $domain), $number, $locale, $parameters);
}
/**
* {@inheritdoc}
*/

View File

@ -1,70 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Contracts\Translation\LocaleAwareInterface;
/**
* TranslatorInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since Symfony 4.2, use Symfony\Contracts\Translation\TranslatorInterface instead
*/
interface TranslatorInterface extends LocaleAwareInterface
{
/**
* Translates the given message.
*
* @param string $id The message id (may also be an object that can be cast to string)
* @param array $parameters An array of parameters for the message
* @param string|null $domain The domain for the message or null to use the default
* @param string|null $locale The locale or null to use the default
*
* @return string The translated string
*
* @throws InvalidArgumentException If the locale contains invalid characters
*/
public function trans($id, array $parameters = [], $domain = null, $locale = null);
/**
* Translates the given choice message by choosing a translation according to a number.
*
* @param string $id The message id (may also be an object that can be cast to string)
* @param int $number The number to use to find the index of the message
* @param array $parameters An array of parameters for the message
* @param string|null $domain The domain for the message or null to use the default
* @param string|null $locale The locale or null to use the default
*
* @return string The translated string
*
* @throws InvalidArgumentException If the locale contains invalid characters
*/
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null);
/**
* Sets the current locale.
*
* @param string $locale The locale
*
* @throws InvalidArgumentException If the locale contains invalid characters
*/
public function setLocale($locale);
/**
* Returns the current locale.
*
* @return string The locale
*/
public function getLocale();
}

View File

@ -36,22 +36,6 @@ class TranslationWriter implements TranslationWriterInterface
$this->dumpers[$format] = $dumper;
}
/**
* Disables dumper backup.
*
* @deprecated since Symfony 4.1
*/
public function disableBackup()
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
foreach ($this->dumpers as $dumper) {
if (method_exists($dumper, 'setBackup')) {
$dumper->setBackup(false);
}
}
}
/**
* Obtains the list of supported formats.
*

View File

@ -150,27 +150,12 @@ class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface
$this->parameters,
$this->translationDomain
);
} elseif ($this->translator instanceof TranslatorInterface) {
} else {
$translatedMessage = $this->translator->trans(
$this->message,
['%count%' => $this->plural] + $this->parameters,
$this->translationDomain
);
} else {
try {
$translatedMessage = $this->translator->transChoice(
$this->message,
$this->plural,
$this->parameters,
$this->translationDomain
);
} catch (\InvalidArgumentException $e) {
$translatedMessage = $this->translator->trans(
$this->message,
$this->parameters,
$this->translationDomain
);
}
}
$this->violations->add(new ConstraintViolation(

View File

@ -85,7 +85,7 @@ interface ConstraintViolationBuilderInterface
*
* @return $this
*
* @see \Symfony\Contracts\Translation\TranslatorInterface::transChoice()
* @see \Symfony\Contracts\Translation\TranslatorInterface::trans()
*/
public function setPlural($number);