diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md index 2e17ce0..9d12f65 100644 --- a/docs/guide/i18n.md +++ b/docs/guide/i18n.md @@ -53,6 +53,9 @@ TBD: https://github.com/yiisoft/yii2/issues/930 ### Named placeholders +You can add parameters to a translation message that will be substituted with the corresponding value after translation. +The format for this is to use curly brackets around the parameter name as you can see in the following example: + ```php $username = 'Alexander'; echo \Yii::t('app', 'Hello, {username}!', array( @@ -60,6 +63,8 @@ echo \Yii::t('app', 'Hello, {username}!', array( )); ``` +Note that the parameter assignment is without the brackets. + ### Positional placeholders ```php diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index a96f081..3c32609 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -73,24 +73,31 @@ class I18N extends Component public function translate($category, $message, $params, $language) { $message = $this->getMessageSource($category)->translate($category, $message, $language); - $params = (array)$params; + if (empty($params)) { + return $message; + } + $params = (array)$params; if (class_exists('MessageFormatter', false) && preg_match('~{\s*[\d\w]+\s*,~u', $message)) { $formatter = new MessageFormatter($language, $message); if ($formatter === null) { - \Yii::$app->getLog()->log("$language message from category $category failed. Message is: $message.", Logger::LEVEL_WARNING, 'application'); - } - $result = $formatter->format($params); - if ($result === false) { - $errorMessage = $formatter->getErrorMessage(); - \Yii::$app->getLog()->log("$language message from category $category failed with error: $errorMessage. Message is: $message.", Logger::LEVEL_WARNING, 'application'); - } - else { - return $result; + \Yii::$app->getLog()->log("$language message from category $category is invalid. Message is: $message.", Logger::LEVEL_WARNING, 'application'); + } else { + $result = $formatter->format($params); + if ($result === false) { + $errorMessage = $formatter->getErrorMessage(); + \Yii::$app->getLog()->log("$language message from category $category failed with error: $errorMessage. Message is: $message.", Logger::LEVEL_WARNING, 'application'); + } else { + return $result; + } } } - return empty($params) ? $message : strtr($message, $params); + $p = array(); + foreach($params as $name => $value) { + $p['{' . $name . '}'] = $value; + } + return strtr($message, $p); } /** diff --git a/tests/unit/data/i18n/messages/de_DE/test.php b/tests/unit/data/i18n/messages/de_DE/test.php new file mode 100644 index 0000000..9cb1369 --- /dev/null +++ b/tests/unit/data/i18n/messages/de_DE/test.php @@ -0,0 +1,9 @@ + 'Der Hund rennt schnell.', + 'His speed is about {n} km/h.' => 'Seine Geschwindigkeit beträgt {n} km/h.', + 'His name is {name} and his speed is about {n, number} km/h.' => 'Er heißt {name} und ist {n, number} km/h schnell.', +); \ No newline at end of file diff --git a/tests/unit/data/i18n/messages/en_US/test.php b/tests/unit/data/i18n/messages/en_US/test.php new file mode 100644 index 0000000..dcd3bc9 --- /dev/null +++ b/tests/unit/data/i18n/messages/en_US/test.php @@ -0,0 +1,7 @@ + 'Der Hund rennt schell.', +); \ No newline at end of file diff --git a/tests/unit/framework/i18n/I18NTest.php b/tests/unit/framework/i18n/I18NTest.php new file mode 100644 index 0000000..e46b8cd --- /dev/null +++ b/tests/unit/framework/i18n/I18NTest.php @@ -0,0 +1,65 @@ + + * @since 2.0 + * @group i18n + */ +class I18NTest extends TestCase +{ + /** + * @var I18N + */ + public $i18n; + + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + $this->i18n = new I18N(array( + 'translations' => array( + 'test' => new PhpMessageSource(array( + 'basePath' => '@yiiunit/data/i18n/messages', + )) + ) + )); + } + + public function testTranslate() + { + $msg = 'The dog runs fast.'; + $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', $msg, array(), 'en_US')); + $this->assertEquals('Der Hund rennt schnell.', $this->i18n->translate('test', $msg, array(), 'de_DE')); + } + + public function testTranslateParams() + { + $msg = 'His speed is about {n} km/h.'; + $params = array( + 'n' => 42, + ); + $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en_US')); + $this->assertEquals('Seine Geschwindigkeit beträgt 42 km/h.', $this->i18n->translate('test', $msg, $params, 'de_DE')); + + $msg = 'His name is {name} and his speed is about {n, number} km/h.'; + $params = array( + 'n' => 42, + 'name' => 'DA VINCI', // http://petrix.com/dognames/d.html + ); + $this->assertEquals('His name is DA VINCI and his speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en_US')); + $this->assertEquals('Er heißt DA VINCI und ist 42 km/h schnell.', $this->i18n->translate('test', $msg, $params, 'de_DE')); + } + +} \ No newline at end of file diff --git a/tests/unit/framework/i18n/MessageFormatterTest.php b/tests/unit/framework/i18n/MessageFormatterTest.php index d9ae728..e65e3e9 100644 --- a/tests/unit/framework/i18n/MessageFormatterTest.php +++ b/tests/unit/framework/i18n/MessageFormatterTest.php @@ -140,4 +140,23 @@ _MSG_ $this->assertEquals($expected, $result); } + + /** + * when instantiating a MessageFormatter with invalid pattern it should be null + */ + public function testNullConstructor() + { + $this->assertNull(new MessageFormatter('en_US', '')); + } + + public function testNoParams() + { + $pattern = '{'.self::SUBJECT.'} is '.self::N; + $result = MessageFormatter::formatMessage('en_US', $pattern, array()); + $this->assertEquals($pattern, $result); + + $formatter = new MessageFormatter('en_US', $pattern); + $result = $formatter->format(array()); + $this->assertEquals($pattern, $result); + } } \ No newline at end of file