diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md
index a14fdda35b..c485bf6112 100644
--- a/UPGRADE-2.2.md
+++ b/UPGRADE-2.2.md
@@ -64,6 +64,26 @@
Symfony\Component\Form\Exception namespace or to create custom exception
classes for your purpose.
+ * Translating validation errors is now optional. You can still do so
+ manually if you like, or you can simplify your templates to simply output
+ the already translated message.
+
+ Before:
+
+ ```
+ {{
+ error.messagePluralization is null
+ ? error.messageTemplate|trans(error.messageParameters, 'validators')
+ : error.messageTemplate|transchoice(error.messagePluralization, error.messageParameters, 'validators')
+ }}
+ ```
+
+ After:
+
+ ```
+ {{ error.message }}
+ ```
+
#### Deprecations
* The methods `getParent()`, `setParent()` and `hasParent()` in
@@ -186,6 +206,27 @@
}
```
+ * The sources of the pluralized messages in translation files have changed
+ from the singular to the pluralized version. If you created custom
+ translation files for validator errors, you should adapt them.
+
+ Before:
+
+
+ You must select at least {{ limit }} choices.
+ Sie müssen mindestens {{ limit }} Möglichkeit wählen.|Sie müssen mindestens {{ limit }} Möglichkeiten wählen.
+
+
+ After:
+
+
+ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.
+ Sie müssen mindestens {{ limit }} Möglichkeit wählen.|Sie müssen mindestens {{ limit }} Möglichkeiten wählen.
+
+
+ Check the file src/Symfony/Component/Validator/Resources/translations/validators.en.xlf
+ for the new message sources.
+
#### Deprecations
* The interface `ClassMetadataFactoryInterface` was deprecated and will be
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueValidatorTest.php
index efa077a63c..db80925111 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueValidatorTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueValidatorTest.php
@@ -12,6 +12,7 @@
namespace Symfony\Bridge\Doctrine\Tests\Validator\Constraints;
use Symfony\Bridge\Doctrine\Tests\DoctrineOrmTestCase;
+use Symfony\Component\Validator\DefaultTranslator;
use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory;
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIdentEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleIdentEntity;
@@ -132,7 +133,7 @@ class UniqueValidatorTest extends DoctrineOrmTestCase
$metadataFactory->addMetadata($metadata);
$validatorFactory = $this->createValidatorFactory($uniqueValidator);
- return new Validator($metadataFactory, $validatorFactory);
+ return new Validator($metadataFactory, $validatorFactory, new DefaultTranslator());
}
private function createSchema($em)
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
index d7be0986a9..870cdd99dd 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
@@ -275,11 +275,7 @@
{% if errors|length > 0 %}
-
diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md
index c229302a5e..d8e309637f 100644
--- a/src/Symfony/Component/Form/CHANGELOG.md
+++ b/src/Symfony/Component/Form/CHANGELOG.md
@@ -12,6 +12,7 @@ CHANGELOG
* deprecated FormException and introduced ExceptionInterface instead
* [BC BREAK] FormException is now an interface
* protected FormBuilder methods from being called when it is turned into a FormConfigInterface with getFormConfig()
+ * [BC BREAK] inserted argument `$message` in the constructor of `FormError`
2.1.0
-----
diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
index 9ac6bb69b3..cece98804e 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
@@ -123,6 +123,7 @@ class ViolationMapper implements ViolationMapperInterface
// Only add the error if the form is synchronized
if ($this->acceptsErrors($scope)) {
$scope->addError(new FormError(
+ $violation->getMessage(),
$violation->getMessageTemplate(),
$violation->getMessageParameters(),
$violation->getMessagePluralization()
diff --git a/src/Symfony/Component/Form/FormError.php b/src/Symfony/Component/Form/FormError.php
index b336a40388..343165ca46 100644
--- a/src/Symfony/Component/Form/FormError.php
+++ b/src/Symfony/Component/Form/FormError.php
@@ -18,6 +18,11 @@ namespace Symfony\Component\Form;
*/
class FormError
{
+ /**
+ * @var string
+ */
+ private $message;
+
/**
* The template for the error message
* @var string
@@ -41,16 +46,19 @@ class FormError
*
* Any array key in $messageParameters will be used as a placeholder in
* $messageTemplate.
- * @see \Symfony\Component\Translation\Translator
*
- * @param string $messageTemplate The template for the error message
+ * @param string $message The translated error message
+ * @param string|null $messageTemplate The template for the error message
* @param array $messageParameters The parameters that should be
* substituted in the message template.
* @param integer|null $messagePluralization The value for error message pluralization
+ *
+ * @see \Symfony\Component\Translation\Translator
*/
- public function __construct($messageTemplate, array $messageParameters = array(), $messagePluralization = null)
+ public function __construct($message, $messageTemplate = null, array $messageParameters = array(), $messagePluralization = null)
{
- $this->messageTemplate = $messageTemplate;
+ $this->message = $message;
+ $this->messageTemplate = $messageTemplate ?: $message;
$this->messageParameters = $messageParameters;
$this->messagePluralization = $messagePluralization;
}
@@ -62,7 +70,7 @@ class FormError
*/
public function getMessage()
{
- return strtr($this->messageTemplate, $this->messageParameters);
+ return $this->message;
}
/**
diff --git a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php
index ac9b18b065..7fd743006e 100644
--- a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php
@@ -19,7 +19,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRow()
{
$form = $this->factory->createNamed('name', 'text');
- $form->addError(new FormError('Error!'));
+ $form->addError(new FormError('[trans]Error![/trans]'));
$view = $form->createView();
$html = $this->renderRow($view);
@@ -58,7 +58,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testRepeatedRow()
{
$form = $this->factory->createNamed('name', 'repeated');
- $form->addError(new FormError('Error!'));
+ $form->addError(new FormError('[trans]Error![/trans]'));
$view = $form->createView();
$html = $this->renderRow($view);
@@ -398,7 +398,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
)
->getForm();
- $form->get('child')->addError(new FormError('Error!'));
+ $form->get('child')->addError(new FormError('[trans]Error![/trans]'));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php
index a7ff80e9de..e2801c2d8e 100644
--- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php
@@ -283,8 +283,8 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
public function testErrors()
{
$form = $this->factory->createNamed('name', 'text');
- $form->addError(new FormError('Error 1'));
- $form->addError(new FormError('Error 2'));
+ $form->addError(new FormError('[trans]Error 1[/trans]'));
+ $form->addError(new FormError('[trans]Error 2[/trans]'));
$view = $form->createView();
$html = $this->renderErrors($view);
@@ -1151,7 +1151,7 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
{
$child = $this->factory->createNamed('date', 'date');
$form = $this->factory->createNamed('form', 'form')->add($child);
- $child->addError(new FormError('Error!'));
+ $child->addError(new FormError('[trans]Error![/trans]'));
$view = $form->createView();
$this->assertEmpty($this->renderErrors($view));
@@ -1676,7 +1676,7 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
{
$child = $this->factory->createNamed('time', 'time');
$form = $this->factory->createNamed('form', 'form')->add($child);
- $child->addError(new FormError('Error!'));
+ $child->addError(new FormError('[trans]Error![/trans]'));
$view = $form->createView();
$this->assertEmpty($this->renderErrors($view));
diff --git a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php
index efa957fb0b..e0f62c4ab1 100644
--- a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php
@@ -18,7 +18,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testRow()
{
$form = $this->factory->createNamed('name', 'text');
- $form->addError(new FormError('Error!'));
+ $form->addError(new FormError('[trans]Error![/trans]'));
$view = $form->createView();
$html = $this->renderRow($view);
@@ -91,7 +91,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testRepeatedRowWithErrors()
{
$form = $this->factory->createNamed('name', 'repeated');
- $form->addError(new FormError('Error!'));
+ $form->addError(new FormError('[trans]Error![/trans]'));
$view = $form->createView();
$html = $this->renderRow($view);
@@ -250,7 +250,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
)
->getForm();
- $form->get('child')->addError(new FormError('Error!'));
+ $form->get('child')->addError(new FormError('[trans]Error![/trans]'));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/table
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php
index 7e358910e2..d9555e13e1 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php
@@ -49,6 +49,8 @@ class ValidationListenerTest extends \PHPUnit_Framework_TestCase
private $message;
+ private $messageTemplate;
+
private $params;
protected function setUp()
@@ -63,17 +65,13 @@ class ValidationListenerTest extends \PHPUnit_Framework_TestCase
$this->violationMapper = $this->getMock('Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface');
$this->listener = new ValidationListener($this->validator, $this->violationMapper);
$this->message = 'Message';
+ $this->messageTemplate = 'Message template';
$this->params = array('foo' => 'bar');
}
private function getConstraintViolation($code = null)
{
- return new ConstraintViolation($this->message, $this->params, null, 'prop.path', null, null, $code);
- }
-
- private function getFormError()
- {
- return new FormError($this->message, $this->params);
+ return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code);
}
private function getBuilder($name = 'name', $propertyPath = null, $dataClass = null)
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php
index e192f07108..2f41a99101 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php
@@ -48,6 +48,11 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
*/
private $message;
+ /**
+ * @var string
+ */
+ private $messageTemplate;
+
/**
* @var array
*/
@@ -62,6 +67,7 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->mapper = new ViolationMapper();
$this->message = 'Message';
+ $this->messageTemplate = 'Message template';
$this->params = array('foo' => 'bar');
}
@@ -101,7 +107,7 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
*/
protected function getConstraintViolation($propertyPath)
{
- return new ConstraintViolation($this->message, $this->params, null, $propertyPath, null);
+ return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, $propertyPath, null);
}
/**
@@ -109,7 +115,7 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
*/
protected function getFormError()
{
- return new FormError($this->message, $this->params);
+ return new FormError($this->message, $this->messageTemplate, $this->params);
}
public function testMapToVirtualFormIfDataDoesNotMatch()
diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md
index 20d499f855..fa26425aef 100644
--- a/src/Symfony/Component/Validator/CHANGELOG.md
+++ b/src/Symfony/Component/Validator/CHANGELOG.md
@@ -28,6 +28,17 @@ CHANGELOG
As of Symfony 2.3, this method will be typed against `MetadataFactoryInterface` instead.
* [BC BREAK] the switches `traverse` and `deep` in the `Valid` constraint and in `GraphWalker::walkReference`
are ignored for arrays now. Arrays are always traversed recursively.
+ * added dependency to Translation component
+ * violation messages are now translated with a TranslatorInterface implementation
+ * [BC BREAK] inserted argument `$message` in the constructor of `ConstraintViolation`
+ * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ExecutionContext`
+ * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `GraphWalker`
+ * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ValidationVisitor`
+ * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `Validator`
+ * [BC BREAK] added `setTranslator()` and `setTranslationDomain()` to `ValidatorBuilderInterface`
+ * improved the Validator to support pluralized messages by default
+ * [BC BREAK] changed the source of all pluralized messages in the translation files to the pluralized version
+ * added ExceptionInterface, BadMethodCallException and InvalidArgumentException
2.1.0
-----
diff --git a/src/Symfony/Component/Validator/ConstraintViolation.php b/src/Symfony/Component/Validator/ConstraintViolation.php
index 7b6f1e1928..8f73d50c85 100644
--- a/src/Symfony/Component/Validator/ConstraintViolation.php
+++ b/src/Symfony/Component/Validator/ConstraintViolation.php
@@ -18,6 +18,11 @@ namespace Symfony\Component\Validator;
*/
class ConstraintViolation implements ConstraintViolationInterface
{
+ /**
+ * @var string
+ */
+ private $message;
+
/**
* @var string
*/
@@ -56,6 +61,7 @@ class ConstraintViolation implements ConstraintViolationInterface
/**
* Creates a new constraint violation.
*
+ * @param string $message The violation message.
* @param string $messageTemplate The raw violation message.
* @param array $messageParameters The parameters to substitute
* in the raw message.
@@ -70,8 +76,9 @@ class ConstraintViolation implements ConstraintViolationInterface
* @param mixed $code The error code of the
* violation, if any.
*/
- public function __construct($messageTemplate, array $messageParameters, $root, $propertyPath, $invalidValue, $messagePluralization = null, $code = null)
+ public function __construct($message, $messageTemplate, array $messageParameters, $root, $propertyPath, $invalidValue, $messagePluralization = null, $code = null)
{
+ $this->message = $message;
$this->messageTemplate = $messageTemplate;
$this->messageParameters = $messageParameters;
$this->messagePluralization = $messagePluralization;
@@ -132,15 +139,7 @@ class ConstraintViolation implements ConstraintViolationInterface
*/
public function getMessage()
{
- $parameters = $this->messageParameters;
-
- foreach ($parameters as $i => $parameter) {
- if (is_array($parameter)) {
- $parameters[$i] = 'Array';
- }
- }
-
- return strtr($this->messageTemplate, $parameters);
+ return $this->message;
}
/**
diff --git a/src/Symfony/Component/Validator/Constraints/Choice.php b/src/Symfony/Component/Validator/Constraints/Choice.php
index b73bd77ca3..70d6fd4da9 100644
--- a/src/Symfony/Component/Validator/Constraints/Choice.php
+++ b/src/Symfony/Component/Validator/Constraints/Choice.php
@@ -28,8 +28,8 @@ class Choice extends Constraint
public $max = null;
public $message = 'The value you selected is not a valid choice.';
public $multipleMessage = 'One or more of the given values is invalid.';
- public $minMessage = 'You must select at least {{ limit }} choices.';
- public $maxMessage = 'You must select at most {{ limit }} choices.';
+ public $minMessage = 'You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.';
+ public $maxMessage = 'You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.';
/**
* {@inheritDoc}
diff --git a/src/Symfony/Component/Validator/Constraints/Count.php b/src/Symfony/Component/Validator/Constraints/Count.php
index db0661d0d1..afb0089282 100644
--- a/src/Symfony/Component/Validator/Constraints/Count.php
+++ b/src/Symfony/Component/Validator/Constraints/Count.php
@@ -21,9 +21,9 @@ use Symfony\Component\Validator\Exception\MissingOptionsException;
*/
class Count extends Constraint
{
- public $minMessage = 'This collection should contain {{ limit }} elements or more.';
- public $maxMessage = 'This collection should contain {{ limit }} elements or less.';
- public $exactMessage = 'This collection should contain exactly {{ limit }} elements.';
+ public $minMessage = 'This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.';
+ public $maxMessage = 'This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.';
+ public $exactMessage = 'This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.';
public $min;
public $max;
diff --git a/src/Symfony/Component/Validator/Constraints/Length.php b/src/Symfony/Component/Validator/Constraints/Length.php
index 70554c0686..cc355574ef 100644
--- a/src/Symfony/Component/Validator/Constraints/Length.php
+++ b/src/Symfony/Component/Validator/Constraints/Length.php
@@ -21,9 +21,9 @@ use Symfony\Component\Validator\Exception\MissingOptionsException;
*/
class Length extends Constraint
{
- public $maxMessage = 'This value is too long. It should have {{ limit }} characters or less.';
- public $minMessage = 'This value is too short. It should have {{ limit }} characters or more.';
- public $exactMessage = 'This value should have exactly {{ limit }} characters.';
+ public $maxMessage = 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.';
+ public $minMessage = 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.';
+ public $exactMessage = 'This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.';
public $max;
public $min;
public $charset = 'UTF-8';
diff --git a/src/Symfony/Component/Validator/Constraints/MaxLength.php b/src/Symfony/Component/Validator/Constraints/MaxLength.php
index 57b9bff7db..a737e38c46 100644
--- a/src/Symfony/Component/Validator/Constraints/MaxLength.php
+++ b/src/Symfony/Component/Validator/Constraints/MaxLength.php
@@ -22,7 +22,7 @@ use Symfony\Component\Validator\Constraint;
*/
class MaxLength extends Constraint
{
- public $message = 'This value is too long. It should have {{ limit }} characters or less.';
+ public $message = 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.';
public $limit;
public $charset = 'UTF-8';
diff --git a/src/Symfony/Component/Validator/Constraints/MinLength.php b/src/Symfony/Component/Validator/Constraints/MinLength.php
index 78c5d2c99b..9827ac330e 100644
--- a/src/Symfony/Component/Validator/Constraints/MinLength.php
+++ b/src/Symfony/Component/Validator/Constraints/MinLength.php
@@ -22,7 +22,7 @@ use Symfony\Component\Validator\Constraint;
*/
class MinLength extends Constraint
{
- public $message = 'This value is too short. It should have {{ limit }} characters or more.';
+ public $message = 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.';
public $limit;
public $charset = 'UTF-8';
diff --git a/src/Symfony/Component/Validator/DefaultTranslator.php b/src/Symfony/Component/Validator/DefaultTranslator.php
new file mode 100644
index 0000000000..c4f685e693
--- /dev/null
+++ b/src/Symfony/Component/Validator/DefaultTranslator.php
@@ -0,0 +1,167 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Validator;
+
+use Symfony\Component\Validator\Exception\BadMethodCallException;
+use Symfony\Component\Validator\Exception\InvalidArgumentException;
+use Symfony\Component\Translation\TranslatorInterface;
+
+/**
+ * Simple translator implementation that simply replaces the parameters in
+ * the message IDs.
+ *
+ * Example usage:
+ *
+ * $translator = new DefaultTranslator();
+ *
+ * echo $translator->trans(
+ * 'This is a {{ var }}.',
+ * array('{{ var }}' => 'donkey')
+ * );
+ *
+ * // -> This is a donkey.
+ *
+ * echo $translator->transChoice(
+ * 'This is {{ count }} donkey.|These are {{ count }} donkeys.',
+ * 3,
+ * array('{{ count }}' => 'three')
+ * );
+ *
+ * // -> These are three donkeys.
+ *
+ * This translator does not support message catalogs, translation domains or
+ * locales. Instead, it implements a subset of the capabilities of
+ * {@link \Symfony\Component\Translation\Translator} and can be used in places
+ * where translation is not required by default but should be optional.
+ *
+ * @author Bernhard Schussek
+ */
+class DefaultTranslator implements TranslatorInterface
+{
+ /**
+ * Interpolates the given message.
+ *
+ * Parameters are replaced in the message in the same manner that
+ * {@link strtr()} uses.
+ *
+ * Example usage:
+ *
+ * $translator = new DefaultTranslator();
+ *
+ * echo $translator->trans(
+ * 'This is a {{ var }}.',
+ * array('{{ var }}' => 'donkey')
+ * );
+ *
+ * // -> This is a donkey.
+ *
+ * @param string $id The message id
+ * @param array $parameters An array of parameters for the message
+ * @param string $domain Ignored
+ * @param string $locale Ignored
+ *
+ * @return string The interpolated string
+ */
+ public function trans($id, array $parameters = array(), $domain = null, $locale = null)
+ {
+ return strtr($id, $parameters);
+ }
+
+ /**
+ * Interpolates the given choice message by choosing a variant according to a number.
+ *
+ * The variants are passed in the message ID using the format
+ * "|". "" is chosen if the passed $number is
+ * exactly 1. "" is chosen otherwise.
+ *
+ * This format is consistent with the format supported by
+ * {@link \Symfony\Component\Translation\Translator}, but it does not
+ * have the same expressiveness. While Translator supports intervals in
+ * message translations, which are needed for languages other than English,
+ * this translator does not. You should use Translator or a custom
+ * implementation of {@link TranslatorInterface} if you need this or similar
+ * functionality.
+ *
+ * Example usage:
+ *
+ * echo $translator->transChoice(
+ * 'This is {{ count }} donkey.|These are {{ count }} donkeys.',
+ * 0,
+ * array('{{ count }}' => 0)
+ * );
+ *
+ * // -> These are 0 donkeys.
+ *
+ * echo $translator->transChoice(
+ * 'This is {{ count }} donkey.|These are {{ count }} donkeys.',
+ * 1,
+ * array('{{ count }}' => 1)
+ * );
+ *
+ * // -> This is 1 donkey.
+ *
+ * echo $translator->transChoice(
+ * 'This is {{ count }} donkey.|These are {{ count }} donkeys.',
+ * 3,
+ * array('{{ count }}' => 3)
+ * );
+ *
+ * // -> These are 3 donkeys.
+ *
+ * @param string $id The message id
+ * @param integer $number The number to use to find the index of the message
+ * @param array $parameters An array of parameters for the message
+ * @param string $domain Ignored
+ * @param string $locale Ignored
+ *
+ * @return string The translated string
+ *
+ * @throws InvalidArgumentException If the message id does not have the format
+ * "singular|plural".
+ */
+ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
+ {
+ $ids = explode('|', $id);
+
+ if (1 == $number) {
+ return strtr($ids[0], $parameters);
+ }
+
+ if (!isset($ids[1])) {
+ throw new InvalidArgumentException(sprintf('The message "%s" cannot be pluralized, because it is missing a plural (e.g. "There is one apple|There are %%count%% apples").', $id));
+ }
+
+ return strtr($ids[1], $parameters);
+ }
+
+ /**
+ * Not supported.
+ *
+ * @param string $locale The locale
+ *
+ * @throws BadMethodCallException
+ */
+ public function setLocale($locale)
+ {
+ throw new BadMethodCallException('Unsupported method.');
+ }
+
+ /**
+ * Returns the locale of the translator.
+ *
+ * @return string Always returns 'en'
+ */
+ public function getLocale()
+ {
+ return 'en';
+ }
+}
diff --git a/src/Symfony/Component/Validator/Exception/BadMethodCallException.php b/src/Symfony/Component/Validator/Exception/BadMethodCallException.php
new file mode 100644
index 0000000000..939161bff3
--- /dev/null
+++ b/src/Symfony/Component/Validator/Exception/BadMethodCallException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Validator\Exception;
+
+/**
+ * Base BadMethodCallException for the Validator component.
+ *
+ * @author Bernhard Schussek
+ */
+class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
+{
+}
diff --git a/src/Symfony/Component/Validator/Exception/ExceptionInterface.php b/src/Symfony/Component/Validator/Exception/ExceptionInterface.php
new file mode 100644
index 0000000000..77d09b9029
--- /dev/null
+++ b/src/Symfony/Component/Validator/Exception/ExceptionInterface.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Validator\Exception;
+
+/**
+ * Base ExceptionInterface for the Validator component.
+ *
+ * @author Bernhard Schussek
+ */
+interface ExceptionInterface
+{
+}
diff --git a/src/Symfony/Component/Validator/Exception/InvalidArgumentException.php b/src/Symfony/Component/Validator/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000000..22da39bb26
--- /dev/null
+++ b/src/Symfony/Component/Validator/Exception/InvalidArgumentException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Validator\Exception;
+
+/**
+ * Base InvalidArgumentException for the Validator component.
+ *
+ * @author Bernhard Schussek
+ */
+class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/src/Symfony/Component/Validator/ExecutionContext.php b/src/Symfony/Component/Validator/ExecutionContext.php
index bfcaba891f..864f749da8 100644
--- a/src/Symfony/Component/Validator/ExecutionContext.php
+++ b/src/Symfony/Component/Validator/ExecutionContext.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Validator;
+use Symfony\Component\Translation\TranslatorInterface;
+
/**
* Default implementation of {@link ExecutionContextInterface}.
*
@@ -26,6 +28,16 @@ class ExecutionContext implements ExecutionContextInterface
*/
private $globalContext;
+ /**
+ * @var TranslatorInterface
+ */
+ private $translator;
+
+ /**
+ * @var null|string
+ */
+ private $translationDomain;
+
/**
* @var MetadataInterface
*/
@@ -49,19 +61,23 @@ class ExecutionContext implements ExecutionContextInterface
/**
* Creates a new execution context.
*
- * @param GlobalExecutionContextInterface $globalContext The global context storing node-independent state.
- * @param MetadataInterface $metadata The metadata of the validated node.
- * @param mixed $value The value of the validated node.
- * @param string $group The current validation group.
- * @param string $propertyPath The property path to the current node.
+ * @param GlobalExecutionContextInterface $globalContext The global context storing node-independent state.
+ * @param TranslatorInterface $translator The translator for translating violation messages.
+ * @param null|string $translationDomain The domain of the validation messages.
+ * @param MetadataInterface $metadata The metadata of the validated node.
+ * @param mixed $value The value of the validated node.
+ * @param string $group The current validation group.
+ * @param string $propertyPath The property path to the current node.
*/
- public function __construct(GlobalExecutionContextInterface $globalContext, MetadataInterface $metadata = null, $value = null, $group = null, $propertyPath = '')
+ public function __construct(GlobalExecutionContextInterface $globalContext, TranslatorInterface $translator, $translationDomain = null, MetadataInterface $metadata = null, $value = null, $group = null, $propertyPath = '')
{
if (null === $group) {
$group = Constraint::DEFAULT_GROUP;
}
$this->globalContext = $globalContext;
+ $this->translator = $translator;
+ $this->translationDomain = $translationDomain;
$this->metadata = $metadata;
$this->value = $value;
$this->propertyPath = $propertyPath;
@@ -74,6 +90,9 @@ class ExecutionContext implements ExecutionContextInterface
public function addViolation($message, array $params = array(), $invalidValue = null, $pluralization = null, $code = null)
{
$this->globalContext->getViolations()->add(new ConstraintViolation(
+ null === $pluralization
+ ? $this->translator->trans($message, $params, $this->translationDomain)
+ : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain),
$message,
$params,
$this->globalContext->getRoot(),
@@ -103,6 +122,9 @@ class ExecutionContext implements ExecutionContextInterface
trigger_error('addViolationAtPath() is deprecated since version 2.2 and will be removed in 2.3.', E_USER_DEPRECATED);
$this->globalContext->getViolations()->add(new ConstraintViolation(
+ null === $pluralization
+ ? $this->translator->trans($message, $params, $this->translationDomain)
+ : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain),
$message,
$params,
$this->globalContext->getRoot(),
@@ -146,6 +168,9 @@ class ExecutionContext implements ExecutionContextInterface
public function addViolationAt($subPath, $message, array $params = array(), $invalidValue = null, $pluralization = null, $code = null)
{
$this->globalContext->getViolations()->add(new ConstraintViolation(
+ null === $pluralization
+ ? $this->translator->trans($message, $params, $this->translationDomain)
+ : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain),
$message,
$params,
$this->globalContext->getRoot(),
diff --git a/src/Symfony/Component/Validator/GraphWalker.php b/src/Symfony/Component/Validator/GraphWalker.php
index 8af1a56153..ca212489a6 100644
--- a/src/Symfony/Component/Validator/GraphWalker.php
+++ b/src/Symfony/Component/Validator/GraphWalker.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Validator;
use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\MemberMetadata;
@@ -39,6 +40,16 @@ class GraphWalker
*/
private $metadataFactory;
+ /**
+ * @var TranslatorInterface
+ */
+ private $translator;
+
+ /**
+ * @var null|string
+ */
+ private $translationDomain;
+
/**
* @var array
*/
@@ -49,16 +60,20 @@ class GraphWalker
*
* @param ValidationVisitor $visitor
* @param MetadataFactoryInterface $metadataFactory
+ * @param TranslatorInterface $translator
+ * @param null|string $translationDomain
* @param array $validatedObjects
*
* @deprecated Deprecated since version 2.2, to be removed in 2.3.
*/
- public function __construct(ValidationVisitor $visitor, MetadataFactoryInterface $metadataFactory, array &$validatedObjects = array())
+ public function __construct(ValidationVisitor $visitor, MetadataFactoryInterface $metadataFactory, TranslatorInterface $translator, $translationDomain = null, array &$validatedObjects = array())
{
trigger_error('GraphWalker is deprecated since version 2.2 and will be removed in 2.3. This class has been replaced by ValidationVisitorInterface and MetadataInterface.', E_USER_DEPRECATED);
$this->visitor = $visitor;
$this->metadataFactory = $metadataFactory;
+ $this->translator = $translator;
+ $this->translationDomain = $translationDomain;
$this->validatedObjects = &$validatedObjects;
}
@@ -208,6 +223,8 @@ class GraphWalker
$context = new ExecutionContext(
$this->visitor,
+ $this->translator,
+ $this->translationDomain,
$metadata,
$value,
$group,
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf
index e6a29653b1..6100400159 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf
@@ -23,11 +23,11 @@
Die waarde wat jy gekies het is nie 'n geldige keuse nie.
- You must select at least {{ limit }} choices.
+ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.Jy moet ten minste {{ limit }} kies.|Jy moet ten minste {{ limit }} keuses kies.
- You must select at most {{ limit }} choices.
+ You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.Jy moet by die meeste {{ limit }} keuse kies.|Jy moet by die meeste {{ limit }} keuses kies.
@@ -75,7 +75,7 @@
Hierdie waarde moet {{ limit }} of minder wees.
- This value is too long. It should have {{ limit }} characters or less.
+ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.Hierdie waarde is te lank. Dit moet {{ limit }} karakter of minder wees.|Hierdie waarde is te lank. Dit moet {{ limit }} karakters of minder wees.
@@ -83,7 +83,7 @@
Hierdie waarde moet {{ limit }} of meer wees.
- This value is too short. It should have {{ limit }} characters or more.
+ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.Hierdie waarde is te kort. Dit moet {{ limit }} karakter of meer wees.|Hierdie waarde is te kort. Dit moet {{ limit }} karakters of meer wees.
@@ -179,7 +179,7 @@
Hierdie waarde moet die huidige wagwoord van die gebruiker wees.
- This value should have exactly {{ limit }} characters.
+ This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.Hierdie waarde moet presies {{ limit }} karakter wees.|Hierdie waarde moet presies {{ limit }} karakters wees.
@@ -203,15 +203,15 @@
'n PHP-uitbreiding veroorsaak die oplaai van die lêer om te misluk.
- This collection should contain {{ limit }} elements or more.
+ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.Hierdie versameling moet {{ limit }} element of meer bevat.|Hierdie versameling moet {{ limit }} elemente of meer bevat.
- This collection should contain {{ limit }} elements or less.
+ This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.Hierdie versameling moet {{ limit }} element of minder bevat.|Hierdie versameling moet {{ limit }} elemente of meer bevat.
- This collection should contain exactly {{ limit }} elements.
+ This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.Hierdie versameling moet presies {{ limit }} element bevat.|Hierdie versameling moet presies {{ limit }} elemente bevat.
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf
index 9d5754c3cd..f6a67e7257 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf
@@ -23,11 +23,11 @@
Избраната стойност е невалидна.
- You must select at least {{ limit }} choices.
+ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.Трябва да изберете поне {{ limit }} опция.|Трябва да изберете поне {{ limit }} опции.
- You must select at most {{ limit }} choices.
+ You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.Трябва да изберете най-много {{ limit }} опция.|Трябва да изберете най-много {{ limit }} опции.
@@ -75,7 +75,7 @@
Стойността трябва да бъде {{ limit }} или по-малко.
- This value is too long. It should have {{ limit }} characters or less.
+ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.Стойността е твърде дълга. Трябва да съдържа най-много {{ limit }} символ.|Стойността е твърде дълга. Трябва да съдържа най-много {{ limit }} символа.
@@ -83,7 +83,7 @@
Стойността трябва да бъде {{ limit }} или повече.
- This value is too short. It should have {{ limit }} characters or more.
+ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.Стойността е твърде кратка. Трябва да съдържа поне {{ limit }} символ.|Стойността е твърде кратка. Трябва да съдържа поне {{ limit }} символа.
@@ -179,7 +179,7 @@
Стойността трябва да бъде текущата потребителска парола.
- This value should have exactly {{ limit }} characters.
+ This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.Стойността трябва да бъде точно {{ limit }} символ.|Стойността трябва да бъде точно {{ limit }} символа.
@@ -203,17 +203,17 @@
PHP разширение предизвика прекъсване на качването.
- This collection should contain {{ limit }} elements or more.
+ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.Колекцията трябва да съдържа поне {{ limit }} елемент.|Колекцията трябва да съдържа поне {{ limit }} елемента.
- This collection should contain {{ limit }} elements or less.
+ This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.Колекцията трябва да съдържа най-много {{ limit }} елемент.|Колекцията трябва да съдържа най-много {{ limit }} елемента.
- This collection should contain exactly {{ limit }} elements.
+ This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.Колекцията трябва да съдържа точно {{ limit }} елемент.|Колекцията трябва да съдържа точно {{ limit }} елемента.