diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 48a63a2..ca467af 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -7,6 +7,7 @@ Yii Framework 2 Change Log - Enh #11490: Added `yii\data\ArrayDataProvider::$modelClass` property to specify a model used to provide column labels even when data array is empty (PowerGamer1) - Bug #9950: Updated `yii\grid\DataColumn::getHeaderCellLabel()` to extract attribute label from the `filterModel` of Grid (silverfire) +- Bug #11429: Fixed `yii\i18n\PhpMessageSource::loadFallbackMessages()` not to log error when source and language is same, but locales are different (silverfire) - Enh #11428: Speedup SQL query in `yii\db\oci\Schema::findColumns()` (SSiwek) - Enh #11414: Files specified as `null` in `yii\web\AssetBundle` won't be registered (Razzwan) - Enh #11432: Added HTTP status 421 "Misdirected Request" to list of statuses in `yii\web\Response` (dasmfm) diff --git a/framework/i18n/GettextMessageSource.php b/framework/i18n/GettextMessageSource.php index 215a977..18981a6 100644 --- a/framework/i18n/GettextMessageSource.php +++ b/framework/i18n/GettextMessageSource.php @@ -103,7 +103,11 @@ class GettextMessageSource extends MessageSource $fallbackMessageFile = $this->getMessageFilePath($fallbackLanguage); $fallbackMessages = $this->loadMessagesFromFile($fallbackMessageFile, $category); - if ($messages === null && $fallbackMessages === null && $fallbackLanguage !== $this->sourceLanguage) { + if ( + $messages === null && $fallbackMessages === null + && $fallbackLanguage !== $this->sourceLanguage + && $fallbackLanguage !== substr($this->sourceLanguage, 0, 2) + ) { Yii::error("The message file for category '$category' does not exist: $originalMessageFile " . "Fallback file does not exist as well: $fallbackMessageFile", __METHOD__); } elseif (empty($messages)) { diff --git a/framework/i18n/PhpMessageSource.php b/framework/i18n/PhpMessageSource.php index 388954a..1aa4a8a 100644 --- a/framework/i18n/PhpMessageSource.php +++ b/framework/i18n/PhpMessageSource.php @@ -105,7 +105,11 @@ class PhpMessageSource extends MessageSource $fallbackMessageFile = $this->getMessageFilePath($category, $fallbackLanguage); $fallbackMessages = $this->loadMessagesFromFile($fallbackMessageFile); - if ($messages === null && $fallbackMessages === null && $fallbackLanguage !== $this->sourceLanguage) { + if ( + $messages === null && $fallbackMessages === null + && $fallbackLanguage !== $this->sourceLanguage + && $fallbackLanguage !== substr($this->sourceLanguage, 0, 2) + ) { Yii::error("The message file for category '$category' does not exist: $originalMessageFile " . "Fallback file does not exist as well: $fallbackMessageFile", __METHOD__); } elseif (empty($messages)) { diff --git a/tests/framework/i18n/DbMessageSourceTest.php b/tests/framework/i18n/DbMessageSourceTest.php index ba6ffa7..8215d73 100644 --- a/tests/framework/i18n/DbMessageSourceTest.php +++ b/tests/framework/i18n/DbMessageSourceTest.php @@ -29,13 +29,19 @@ class DbMessageSourceTest extends I18NTest { $this->i18n = new I18N([ 'translations' => [ - 'test' => new DbMessageSource([ + 'test' => [ + 'class' => $this->getMessageSourceClass(), 'db' => static::$db, - ]) + ] ] ]); } + private function getMessageSourceClass() + { + return DbMessageSource::className(); + } + protected static function runConsoleAction($route, $params = []) { if (Yii::$app === null) { @@ -153,4 +159,10 @@ class DbMessageSourceTest extends I18NTest $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); Event::off(DbMessageSource::className(), DbMessageSource::EVENT_MISSING_TRANSLATION); } + + + public function testIssue11429($sourceLanguage = null) + { + $this->markTestSkipped('DbMessageSource does not produce any errors when messages file is missing.'); + } } diff --git a/tests/framework/i18n/I18NTest.php b/tests/framework/i18n/I18NTest.php index 4b09231..5b558e5 100644 --- a/tests/framework/i18n/I18NTest.php +++ b/tests/framework/i18n/I18NTest.php @@ -7,6 +7,7 @@ namespace yiiunit\framework\i18n; +use Yii; use yii\base\Event; use yii\i18n\I18N; use yii\i18n\PhpMessageSource; @@ -35,13 +36,19 @@ class I18NTest extends TestCase { $this->i18n = new I18N([ 'translations' => [ - 'test' => new PhpMessageSource([ + 'test' => [ + 'class' => $this->getMessageSourceClass(), 'basePath' => '@yiiunit/data/i18n/messages', - ]) + ] ] ]); } + private function getMessageSourceClass() + { + return PhpMessageSource::className(); + } + public function testTranslate() { $msg = 'The dog runs fast.'; @@ -63,13 +70,14 @@ class I18NTest extends TestCase { $i18n = new I18N([ 'translations' => [ - '*' => new PhpMessageSource([ + '*' => [ + 'class' => $this->getMessageSourceClass(), 'basePath' => '@yiiunit/data/i18n/messages', 'fileMap' => [ 'test' => 'test.php', 'foo' => 'test.php', ], - ]) + ] ] ]); @@ -174,15 +182,15 @@ class I18NTest extends TestCase public function testUsingSourceLanguageForMissingTranslation() { - \Yii::$app->sourceLanguage = 'ru'; - \Yii::$app->language = 'en'; + Yii::$app->sourceLanguage = 'ru'; + Yii::$app->language = 'en'; $msg = '{n, plural, =0{Нет комментариев} =1{# комментарий} one{# комментарий} few{# комментария} many{# комментариев} other{# комментария}}'; - $this->assertEquals('5 комментариев', \Yii::t('app', $msg, ['n' => 5])); - $this->assertEquals('3 комментария', \Yii::t('app', $msg, ['n' => 3])); - $this->assertEquals('1 комментарий', \Yii::t('app', $msg, ['n' => 1])); - $this->assertEquals('21 комментарий', \Yii::t('app', $msg, ['n' => 21])); - $this->assertEquals('Нет комментариев', \Yii::t('app', $msg, ['n' => 0])); + $this->assertEquals('5 комментариев', Yii::t('app', $msg, ['n' => 5])); + $this->assertEquals('3 комментария', Yii::t('app', $msg, ['n' => 3])); + $this->assertEquals('1 комментарий', Yii::t('app', $msg, ['n' => 1])); + $this->assertEquals('21 комментарий', Yii::t('app', $msg, ['n' => 21])); + $this->assertEquals('Нет комментариев', Yii::t('app', $msg, ['n' => 0])); } /** @@ -213,6 +221,50 @@ class I18NTest extends TestCase Event::off(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION); } + public function sourceLanguageDataProvider() + { + return [ + ['en-GB'], + ['en'] + ]; + } + + /** + * @dataProvider sourceLanguageDataProvider + * @param $sourceLanguage + */ + public function testIssue11429($sourceLanguage) + { + $this->mockApplication(); + $this->setI18N(); + + Yii::$app->sourceLanguage = $sourceLanguage; + $logger = Yii::getLogger(); + $logger->messages = []; + $filter = function ($array) { + // Ensures that error message is related to PhpMessageSource + $className = $this->getMessageSourceClass(); + return substr_compare($array[2], $className, 0, strlen($className)) === 0; + }; + + $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', 'The dog runs fast.', [], 'en-GB')); + $this->assertEquals([], array_filter($logger->messages, $filter)); + + $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', 'The dog runs fast.', [], 'en')); + $this->assertEquals([], array_filter($logger->messages, $filter)); + + $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', 'The dog runs fast.', [], 'en-CA')); + $this->assertEquals([], array_filter($logger->messages, $filter)); + + $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', 'The dog runs fast.', [], 'hz-HZ')); + $this->assertCount(1, array_filter($logger->messages, $filter)); + $logger->messages = []; + + $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', 'The dog runs fast.', [], 'hz')); + $this->assertCount(1, array_filter($logger->messages, $filter)); + $logger->messages = []; + } + /** * Formatting a message that contains params but they are not provided. * https://github.com/yiisoft/yii2/issues/10884