From cfc57c20f06a207a74b1effd9e46d6f31b5300aa Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:25:38 +0200 Subject: [PATCH 1/5] Allow ITU message format in validator messages fixes #991 --- framework/yii/i18n/I18N.php | 41 +++++++++++++++++++++++ framework/yii/validators/BooleanValidator.php | 4 +-- framework/yii/validators/CompareValidator.php | 4 +-- framework/yii/validators/FileValidator.php | 10 +++--- framework/yii/validators/NumberValidator.php | 4 +-- framework/yii/validators/RequiredValidator.php | 2 +- framework/yii/validators/StringValidator.php | 6 ++-- framework/yii/validators/Validator.php | 6 ++-- tests/unit/framework/validators/ValidatorTest.php | 2 +- 9 files changed, 60 insertions(+), 19 deletions(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index 57978a0..bd9409c 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -63,6 +63,9 @@ class I18N extends Component /** * Translates a message to the specified language. * + * After translation the message will be parsed using [[MessageFormatter]] if it contains + * ITU message format and `$params` are not empty. + * * @param string $category the message category. * @param string $message the message to be translated. * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. @@ -102,6 +105,44 @@ class I18N extends Component } /** + * Formats a message using using [[MessageFormatter]]. + * + * @param string $message the message to be formatted. + * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. + * @param string $language the language code (e.g. `en_US`, `en`). + * @return string the formatted message. + */ + public function format($message, $params, $language) + { + $params = (array)$params; + if ($params === []) { + return $message; + } + + if (preg_match('~{\s*[\d\w]+\s*,~u', $message)) { + $formatter = new MessageFormatter($language, $message); + if ($formatter === null) { + Yii::warning("Message for $language is invalid: $message."); + return $message; + } + $result = $formatter->format($params); + if ($result === false) { + $errorMessage = $formatter->getErrorMessage(); + Yii::warning("Formatting message for $language failed with error: $errorMessage. Message is: $message."); + return $message; + } else { + return $result; + } + } + + $p = []; + foreach($params as $name => $value) { + $p['{' . $name . '}'] = $value; + } + return strtr($message, $p); + } + + /** * Returns the message source for the given category. * @param string $category the category name. * @return MessageSource the message source for the given category. diff --git a/framework/yii/validators/BooleanValidator.php b/framework/yii/validators/BooleanValidator.php index 2504b8a..02b11d7 100644 --- a/framework/yii/validators/BooleanValidator.php +++ b/framework/yii/validators/BooleanValidator.php @@ -58,8 +58,8 @@ class BooleanValidator extends Validator $value = $object->$attribute; if (!$this->validateValue($value)) { $this->addError($object, $attribute, $this->message, [ - '{true}' => $this->trueValue, - '{false}' => $this->falseValue, + 'true' => $this->trueValue, + 'false' => $this->falseValue, ]); } } diff --git a/framework/yii/validators/CompareValidator.php b/framework/yii/validators/CompareValidator.php index 3ff459b..8a694ad 100644 --- a/framework/yii/validators/CompareValidator.php +++ b/framework/yii/validators/CompareValidator.php @@ -143,8 +143,8 @@ class CompareValidator extends Validator } if (!$valid) { $this->addError($object, $attribute, $this->message, [ - '{compareAttribute}' => $compareLabel, - '{compareValue}' => $compareValue, + 'compareAttribute' => $compareLabel, + 'compareValue' => $compareValue, ]); } } diff --git a/framework/yii/validators/FileValidator.php b/framework/yii/validators/FileValidator.php index 8024d10..f27c010 100644 --- a/framework/yii/validators/FileValidator.php +++ b/framework/yii/validators/FileValidator.php @@ -144,7 +144,7 @@ class FileValidator extends Validator $this->addError($object, $attribute, $this->uploadRequired); } if (count($files) > $this->maxFiles) { - $this->addError($object, $attribute, $this->tooMany, ['{attribute}' => $attribute, '{limit}' => $this->maxFiles]); + $this->addError($object, $attribute, $this->tooMany, ['limit' => $this->maxFiles]); } else { foreach ($files as $file) { $this->validateFile($object, $attribute, $file); @@ -171,18 +171,18 @@ class FileValidator extends Validator switch ($file->error) { case UPLOAD_ERR_OK: if ($this->maxSize !== null && $file->size > $this->maxSize) { - $this->addError($object, $attribute, $this->tooBig, ['{file}' => $file->name, '{limit}' => $this->getSizeLimit()]); + $this->addError($object, $attribute, $this->tooBig, ['file' => $file->name, 'limit' => $this->getSizeLimit()]); } if ($this->minSize !== null && $file->size < $this->minSize) { - $this->addError($object, $attribute, $this->tooSmall, ['{file}' => $file->name, '{limit}' => $this->minSize]); + $this->addError($object, $attribute, $this->tooSmall, ['file' => $file->name, 'limit' => $this->minSize]); } if (!empty($this->types) && !in_array(strtolower(pathinfo($file->name, PATHINFO_EXTENSION)), $this->types, true)) { - $this->addError($object, $attribute, $this->wrongType, ['{file}' => $file->name, '{extensions}' => implode(', ', $this->types)]); + $this->addError($object, $attribute, $this->wrongType, ['file' => $file->name, 'extensions' => implode(', ', $this->types)]); } break; case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: - $this->addError($object, $attribute, $this->tooBig, ['{file}' => $file->name, '{limit}' => $this->getSizeLimit()]); + $this->addError($object, $attribute, $this->tooBig, ['file' => $file->name, 'limit' => $this->getSizeLimit()]); break; case UPLOAD_ERR_PARTIAL: $this->addError($object, $attribute, $this->message); diff --git a/framework/yii/validators/NumberValidator.php b/framework/yii/validators/NumberValidator.php index ec72dcf..0df73e6 100644 --- a/framework/yii/validators/NumberValidator.php +++ b/framework/yii/validators/NumberValidator.php @@ -91,10 +91,10 @@ class NumberValidator extends Validator $this->addError($object, $attribute, $this->message); } if ($this->min !== null && $value < $this->min) { - $this->addError($object, $attribute, $this->tooSmall, ['{min}' => $this->min]); + $this->addError($object, $attribute, $this->tooSmall, ['min' => $this->min]); } if ($this->max !== null && $value > $this->max) { - $this->addError($object, $attribute, $this->tooBig, ['{max}' => $this->max]); + $this->addError($object, $attribute, $this->tooBig, ['max' => $this->max]); } } diff --git a/framework/yii/validators/RequiredValidator.php b/framework/yii/validators/RequiredValidator.php index 88bd03d..eb4a394 100644 --- a/framework/yii/validators/RequiredValidator.php +++ b/framework/yii/validators/RequiredValidator.php @@ -75,7 +75,7 @@ class RequiredValidator extends Validator $this->addError($object, $attribute, $this->message); } else { $this->addError($object, $attribute, $this->message, [ - '{requiredValue}' => $this->requiredValue, + 'requiredValue' => $this->requiredValue, ]); } } diff --git a/framework/yii/validators/StringValidator.php b/framework/yii/validators/StringValidator.php index a6383b9..329cab0 100644 --- a/framework/yii/validators/StringValidator.php +++ b/framework/yii/validators/StringValidator.php @@ -112,13 +112,13 @@ class StringValidator extends Validator $length = mb_strlen($value, $this->encoding); if ($this->min !== null && $length < $this->min) { - $this->addError($object, $attribute, $this->tooShort, ['{min}' => $this->min]); + $this->addError($object, $attribute, $this->tooShort, ['min' => $this->min]); } if ($this->max !== null && $length > $this->max) { - $this->addError($object, $attribute, $this->tooLong, ['{max}' => $this->max]); + $this->addError($object, $attribute, $this->tooLong, ['max' => $this->max]); } if ($this->length !== null && $length !== $this->length) { - $this->addError($object, $attribute, $this->notEqual, ['{length}' => $this->length]); + $this->addError($object, $attribute, $this->notEqual, ['length' => $this->length]); } } diff --git a/framework/yii/validators/Validator.php b/framework/yii/validators/Validator.php index 46ab673..dc0e935 100644 --- a/framework/yii/validators/Validator.php +++ b/framework/yii/validators/Validator.php @@ -251,9 +251,9 @@ abstract class Validator extends Component public function addError($object, $attribute, $message, $params = []) { $value = $object->$attribute; - $params['{attribute}'] = $object->getAttributeLabel($attribute); - $params['{value}'] = is_array($value) ? 'array()' : $value; - $object->addError($attribute, strtr($message, $params)); + $params['attribute'] = $object->getAttributeLabel($attribute); + $params['value'] = is_array($value) ? 'array()' : $value; + $object->addError($attribute, Yii::$app->getI18n()->format($message, $params, Yii::$app->language)); } /** diff --git a/tests/unit/framework/validators/ValidatorTest.php b/tests/unit/framework/validators/ValidatorTest.php index 351dba8..0cd56d9 100644 --- a/tests/unit/framework/validators/ValidatorTest.php +++ b/tests/unit/framework/validators/ValidatorTest.php @@ -220,7 +220,7 @@ class ValidatorTest extends TestCase $errors = $m->getErrors('attr_msg_val'); $this->assertEquals('attr_msg_val::array()', $errors[0]); $m = $this->getTestModel(['attr_msg_val' => 'abc']); - $val->addError($m, 'attr_msg_val', '{attribute}::{value}::{param}', ['{param}' => 'param_value']); + $val->addError($m, 'attr_msg_val', '{attribute}::{value}::{param}', ['param' => 'param_value']); $errors = $m->getErrors('attr_msg_val'); $this->assertEquals('attr_msg_val::abc::param_value', $errors[0]); } From 58e6a72987336e50e43ce5b2f8627ff01915e781 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:35:28 +0200 Subject: [PATCH 2/5] fixes #991 for gridview summary, use ITU message format --- framework/yii/widgets/BaseListView.php | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php index bfa984f..27b2eaf 100644 --- a/framework/yii/widgets/BaseListView.php +++ b/framework/yii/widgets/BaseListView.php @@ -131,30 +131,32 @@ abstract class BaseListView extends Widget public function renderSummary() { $count = $this->dataProvider->getCount(); - if (($pagination = $this->dataProvider->getPagination()) !== false && $count > 0) { + if (($pagination = $this->dataProvider->getPagination()) !== false) { $totalCount = $this->dataProvider->getTotalCount(); $begin = $pagination->getPage() * $pagination->pageSize + 1; $end = $begin + $count - 1; $page = $pagination->getPage() + 1; $pageCount = $pagination->pageCount; if (($summaryContent = $this->summary) === null) { - $summaryContent = '
' . Yii::t('yii', 'Showing {begin}-{end} of {totalCount} {0, plural, =1{item} other{items}}.', $totalCount) . '
'; + $summaryContent = '
' + . Yii::t('yii', 'Showing {totalCount, plural, =0{0} other{{begin}-{end}}} of {totalCount} {totalCount, plural, one{item} other{items}}.') + . '
'; } } else { $begin = $page = $pageCount = 1; $end = $totalCount = $count; if (($summaryContent = $this->summary) === null) { - $summaryContent = '
' . Yii::t('yii', 'Total {count} {0, plural, =1{item} other{items}}.', $count) . '
'; + $summaryContent = '
' . Yii::t('yii', 'Total {count} {count, plural, one{item} other{items}}.') . '
'; } } - return strtr($summaryContent, [ - '{begin}' => $begin, - '{end}' => $end, - '{count}' => $count, - '{totalCount}' => $totalCount, - '{page}' => $page, - '{pageCount}' => $pageCount, - ]); + return Yii::$app->getI18n()->format($summaryContent, [ + 'begin' => $begin, + 'end' => $end, + 'count' => $count, + 'totalCount' => $totalCount, + 'page' => $page, + 'pageCount' => $pageCount, + ], Yii::$app->language); } /** From 47dfa69616f095989294e21005f16925e9a3eeca Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:40:59 +0200 Subject: [PATCH 3/5] doc wording [ci skip] --- framework/yii/i18n/I18N.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index bd9409c..82ba86e 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -63,7 +63,7 @@ class I18N extends Component /** * Translates a message to the specified language. * - * After translation the message will be parsed using [[MessageFormatter]] if it contains + * After translation the message will be formatted using [[MessageFormatter]] if it contains * ITU message format and `$params` are not empty. * * @param string $category the message category. From 7e1dd6729358f5debf36ad8633011e648d14108e Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:48:04 +0200 Subject: [PATCH 4/5] typo ITU -> ICU they are not responsible for i18n ;) --- framework/yii/i18n/I18N.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index 82ba86e..ef775a4 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -64,7 +64,7 @@ class I18N extends Component * Translates a message to the specified language. * * After translation the message will be formatted using [[MessageFormatter]] if it contains - * ITU message format and `$params` are not empty. + * ICU message format and `$params` are not empty. * * @param string $category the message category. * @param string $message the message to be translated. From 3631890cba7e4700499d440fe840e9f0ccdc4e28 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 24 Oct 2013 00:00:32 +0200 Subject: [PATCH 5/5] fixed failing validator tests --- tests/unit/framework/validators/BooleanValidatorTest.php | 6 ++++++ tests/unit/framework/validators/CompareValidatorTest.php | 5 +++++ tests/unit/framework/validators/DateValidatorTest.php | 6 ++++++ tests/unit/framework/validators/DefaultValueValidatorTest.php | 6 ++++++ tests/unit/framework/validators/EmailValidatorTest.php | 6 ++++++ tests/unit/framework/validators/ExistValidatorTest.php | 1 + tests/unit/framework/validators/FilterValidatorTest.php | 6 ++++++ tests/unit/framework/validators/NumberValidatorTest.php | 6 ++++++ tests/unit/framework/validators/RangeValidatorTest.php | 6 ++++++ tests/unit/framework/validators/RegularExpressionValidatorTest.php | 6 ++++++ tests/unit/framework/validators/RequiredValidatorTest.php | 6 ++++++ tests/unit/framework/validators/UniqueValidatorTest.php | 1 + tests/unit/framework/validators/UrlValidatorTest.php | 6 ++++++ tests/unit/framework/validators/ValidatorTest.php | 5 +++++ 14 files changed, 72 insertions(+) diff --git a/tests/unit/framework/validators/BooleanValidatorTest.php b/tests/unit/framework/validators/BooleanValidatorTest.php index f30aa3d..0f09daf 100644 --- a/tests/unit/framework/validators/BooleanValidatorTest.php +++ b/tests/unit/framework/validators/BooleanValidatorTest.php @@ -10,6 +10,12 @@ use yiiunit\TestCase; */ class BooleanValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValue() { $val = new BooleanValidator; diff --git a/tests/unit/framework/validators/CompareValidatorTest.php b/tests/unit/framework/validators/CompareValidatorTest.php index b3fd6b4..d1bdf34 100644 --- a/tests/unit/framework/validators/CompareValidatorTest.php +++ b/tests/unit/framework/validators/CompareValidatorTest.php @@ -10,6 +10,11 @@ use yiiunit\TestCase; class CompareValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } public function testValidateValueException() { diff --git a/tests/unit/framework/validators/DateValidatorTest.php b/tests/unit/framework/validators/DateValidatorTest.php index 28a6a4a..6ae3521 100644 --- a/tests/unit/framework/validators/DateValidatorTest.php +++ b/tests/unit/framework/validators/DateValidatorTest.php @@ -10,6 +10,12 @@ use yiiunit\TestCase; class DateValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testEnsureMessageIsSet() { $val = new DateValidator; diff --git a/tests/unit/framework/validators/DefaultValueValidatorTest.php b/tests/unit/framework/validators/DefaultValueValidatorTest.php index 05a71b5..48537d8 100644 --- a/tests/unit/framework/validators/DefaultValueValidatorTest.php +++ b/tests/unit/framework/validators/DefaultValueValidatorTest.php @@ -8,6 +8,12 @@ use yiiunit\TestCase; */ class DefaultValueValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateAttribute() { $val = new DefaultValueValidator; diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php index 950ac97..eee708d 100644 --- a/tests/unit/framework/validators/EmailValidatorTest.php +++ b/tests/unit/framework/validators/EmailValidatorTest.php @@ -11,6 +11,12 @@ use yiiunit\TestCase; */ class EmailValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValue() { $validator = new EmailValidator(); diff --git a/tests/unit/framework/validators/ExistValidatorTest.php b/tests/unit/framework/validators/ExistValidatorTest.php index 5a3a175..a0f0328 100644 --- a/tests/unit/framework/validators/ExistValidatorTest.php +++ b/tests/unit/framework/validators/ExistValidatorTest.php @@ -18,6 +18,7 @@ class ExistValidatorTest extends DatabaseTestCase public function setUp() { parent::setUp(); + $this->mockApplication(); ActiveRecord::$db = $this->getConnection(); } diff --git a/tests/unit/framework/validators/FilterValidatorTest.php b/tests/unit/framework/validators/FilterValidatorTest.php index 139d51d..ec96f21 100644 --- a/tests/unit/framework/validators/FilterValidatorTest.php +++ b/tests/unit/framework/validators/FilterValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; class FilterValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testAssureExceptionOnInit() { $this->setExpectedException('yii\base\InvalidConfigException'); diff --git a/tests/unit/framework/validators/NumberValidatorTest.php b/tests/unit/framework/validators/NumberValidatorTest.php index c2352ec..4e9897e 100644 --- a/tests/unit/framework/validators/NumberValidatorTest.php +++ b/tests/unit/framework/validators/NumberValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; class NumberValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testEnsureMessageOnInit() { $val = new NumberValidator; diff --git a/tests/unit/framework/validators/RangeValidatorTest.php b/tests/unit/framework/validators/RangeValidatorTest.php index bfa7cae..345951c 100644 --- a/tests/unit/framework/validators/RangeValidatorTest.php +++ b/tests/unit/framework/validators/RangeValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; class RangeValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testInitException() { $this->setExpectedException('yii\base\InvalidConfigException', 'The "range" property must be set.'); diff --git a/tests/unit/framework/validators/RegularExpressionValidatorTest.php b/tests/unit/framework/validators/RegularExpressionValidatorTest.php index 3262025..e5b33b2 100644 --- a/tests/unit/framework/validators/RegularExpressionValidatorTest.php +++ b/tests/unit/framework/validators/RegularExpressionValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; class RegularExpressionValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValue() { $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); diff --git a/tests/unit/framework/validators/RequiredValidatorTest.php b/tests/unit/framework/validators/RequiredValidatorTest.php index f60e69e..0708cc9 100644 --- a/tests/unit/framework/validators/RequiredValidatorTest.php +++ b/tests/unit/framework/validators/RequiredValidatorTest.php @@ -8,6 +8,12 @@ use yiiunit\TestCase; class RequiredValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValueWithDefaults() { $val = new RequiredValidator(); diff --git a/tests/unit/framework/validators/UniqueValidatorTest.php b/tests/unit/framework/validators/UniqueValidatorTest.php index 37d666f..d3d0882 100644 --- a/tests/unit/framework/validators/UniqueValidatorTest.php +++ b/tests/unit/framework/validators/UniqueValidatorTest.php @@ -19,6 +19,7 @@ class UniqueValidatorTest extends DatabaseTestCase public function setUp() { parent::setUp(); + $this->mockApplication(); ActiveRecord::$db = $this->getConnection(); } diff --git a/tests/unit/framework/validators/UrlValidatorTest.php b/tests/unit/framework/validators/UrlValidatorTest.php index 4d5fae2..1323434 100644 --- a/tests/unit/framework/validators/UrlValidatorTest.php +++ b/tests/unit/framework/validators/UrlValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; */ class UrlValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValue() { $val = new UrlValidator; diff --git a/tests/unit/framework/validators/ValidatorTest.php b/tests/unit/framework/validators/ValidatorTest.php index 0cd56d9..fc69c2f 100644 --- a/tests/unit/framework/validators/ValidatorTest.php +++ b/tests/unit/framework/validators/ValidatorTest.php @@ -12,6 +12,11 @@ use yiiunit\TestCase; class ValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } protected function getTestModel($additionalAttributes = []) {