Browse Source

Merge pull request #4662 from AD7six/3.0-translate-default-locale

implement translation behavior default locale
Mark Story 11 years ago
parent
commit
c24f7ca060

+ 29 - 6
src/I18n/I18n.php

@@ -34,6 +34,13 @@ class I18n {
 	protected static $_collection;
 
 /**
+ * The environment default locale
+ *
+ * @var string
+ */
+	protected static $_defaultLocale;
+
+/**
  * Returns the translators collection instance. It can be used
  * for getting specific translators based of their name and locale
  * or to configure some aspect of future translations that are not yet constructed.
@@ -56,13 +63,13 @@ class I18n {
 				},
 			]),
 			new TranslatorFactory,
-			static::defaultLocale()
+			static::locale()
 		);
 	}
 
 /**
  * Returns an instance of a translator that was configured for the name and passed
- * locale. If no locale is passed then it takes the value returned by the `defaultLocale()` method.
+ * locale. If no locale is passed then it takes the value returned by the `locale()` method.
  *
  * This method can be used to configure future translators, this is achieved by passing a callable
  * as the last argument of this function.
@@ -103,7 +110,7 @@ class I18n {
 	public static function translator($name = 'default', $locale = null, callable $loader = null) {
 		if ($loader !== null) {
 			$packages = static::translators()->getPackages();
-			$locale = $locale ?: static::defaultLocale();
+			$locale = $locale ?: static::locale();
 
 			if ($name !== 'default') {
 				$loader = function () use ($loader) {
@@ -184,15 +191,17 @@ class I18n {
 
 /**
  * Sets the default locale to use for future translator instances.
- * This also affects the `intl.default_locale` php setting.
+ * This also affects the `intl.default_locale` PHP setting.
  *
  * When called with no arguments it will return the currently configure
- * defaultLocale as stored in the `intl.default_locale` php setting.
+ * locale as stored in the `intl.default_locale` PHP setting.
  *
  * @param string $locale The name of the locale to set as default.
  * @return string|null The name of the default locale.
  */
-	public static function defaultLocale($locale = null) {
+	public static function locale($locale = null) {
+		static::defaultLocale();
+
 		if (!empty($locale)) {
 			Locale::setDefault($locale);
 			static::translators()->setLocale($locale);
@@ -209,6 +218,20 @@ class I18n {
 	}
 
 /**
+ * This returns the default locale before any modifications, i.e.
+ * the value as stored in the `intl.default_locale` PHP setting before
+ * any manipulation by this class.
+ *
+ * @return string
+ */
+	public static function defaultLocale() {
+		if (static::$_defaultLocale === null) {
+			static::$_defaultLocale = Locale::getDefault() ?: 'en_US';
+		}
+		return static::$_defaultLocale;
+	}
+
+/**
  * Sets the name of the default messages formatter to use for future
  * translator instances. By default the `default` and `sprintf` formatters
  * are available.

+ 19 - 10
src/Model/Behavior/TranslateBehavior.php

@@ -17,6 +17,7 @@ namespace Cake\Model\Behavior;
 use ArrayObject;
 use Cake\Collection\Collection;
 use Cake\Event\Event;
+use Cake\I18n\I18n;
 use Cake\ORM\Behavior;
 use Cake\ORM\Entity;
 use Cake\ORM\Query;
@@ -63,7 +64,8 @@ class TranslateBehavior extends Behavior {
 		'implementedFinders' => ['translations' => 'findTranslations'],
 		'implementedMethods' => ['locale' => 'locale'],
 		'fields' => [],
-		'translationTable' => 'i18n'
+		'translationTable' => 'i18n',
+		'defaultLocale' => ''
 	];
 
 /**
@@ -73,7 +75,9 @@ class TranslateBehavior extends Behavior {
  * @param array $config The config for this behavior.
  */
 	public function __construct(Table $table, array $config = []) {
+		$config += ['defaultLocale' => I18n::defaultLocale()];
 		parent::__construct($table, $config);
+
 		$this->_table = $table;
 		$config = $this->_config;
 		$this->setupFieldAssociations($config['fields'], $config['translationTable']);
@@ -130,7 +134,7 @@ class TranslateBehavior extends Behavior {
 	public function beforeFind(Event $event, $query) {
 		$locale = $this->locale();
 
-		if (empty($locale)) {
+		if ($locale === $this->config('defaultLocale')) {
 			return;
 		}
 
@@ -170,7 +174,7 @@ class TranslateBehavior extends Behavior {
 
 		$this->_bundleTranslatedFields($entity);
 
-		if (!$locale) {
+		if ($locale === $this->config('defaultLocale')) {
 			return;
 		}
 
@@ -230,7 +234,7 @@ class TranslateBehavior extends Behavior {
  */
 	public function locale($locale = null) {
 		if ($locale === null) {
-			return $this->_locale;
+			return $this->_locale ?: I18n::locale();
 		}
 		return $this->_locale = (string)$locale;
 	}
@@ -281,26 +285,31 @@ class TranslateBehavior extends Behavior {
 	protected function _rowMapper($results, $locale) {
 		return $results->map(function ($row) use ($locale) {
 			$options = ['setter' => false, 'guard' => false];
+			$hydrated = !is_array($row);
 
 			foreach ($this->_config['fields'] as $field) {
+
 				$name = $field . '_translation';
-				$translation = $row->get($name);
+				$translation = isset($row[$name]) ? $row[$name] : null;
 
 				if ($translation === null || $translation === false) {
-					$row->unsetProperty($name);
+					unset($row[$name]);
 					continue;
 				}
 
-				$content = $translation->get('content');
+				$content = isset($translation['content']) ? $translation['content'] : null;
 				if ($content !== null) {
-					$row->set($field, $content, $options);
+					$row[$field] = $content;
 				}
 
 				unset($row[$name]);
 			}
 
-			$row->set('_locale', $locale, $options);
-			$row->clean();
+			$row['_locale'] = $locale;
+			if ($hydrated) {
+				$row->clean();
+			}
+
 			return $row;
 		});
 	}

+ 7 - 7
tests/TestCase/I18n/I18nTest.php

@@ -40,7 +40,7 @@ class I18nTest extends TestCase {
  */
 	public function setUp() {
 		parent::setUp();
-		$this->locale = I18n::defaultLocale();
+		$this->locale = I18n::locale();
 	}
 
 /**
@@ -52,7 +52,7 @@ class I18nTest extends TestCase {
 		parent::tearDown();
 		I18n::clear();
 		I18n::defaultFormatter('default');
-		I18n::defaultLocale($this->locale);
+		I18n::locale($this->locale);
 		Plugin::unload();
 		Cache::clear(false, '_cake_core_');
 	}
@@ -169,15 +169,15 @@ class I18nTest extends TestCase {
 	}
 
 /**
- * Tests the defaultLocale method
+ * Tests the locale method
  *
  * @return void
  */
 	public function testDefaultLocale() {
-		$this->assertEquals('en_US', I18n::defaultLocale());
+		$this->assertEquals('en_US', I18n::locale());
 		$this->assertEquals('en_US', ini_get('intl.default_locale'));
-		I18n::defaultLocale('fr_FR');
-		$this->assertEquals('fr_FR', I18n::defaultLocale());
+		I18n::locale('fr_FR');
+		$this->assertEquals('fr_FR', I18n::locale());
 		$this->assertEquals('fr_FR', ini_get('intl.default_locale'));
 	}
 
@@ -196,7 +196,7 @@ class I18nTest extends TestCase {
 			return $package;
 		});
 
-		I18n::defaultLocale('fr_FR');
+		I18n::locale('fr_FR');
 		$translator = I18n::translator('custom');
 		$this->assertEquals('Le moo', $translator->translate('Cow'));
 	}

+ 5 - 5
tests/TestCase/I18n/NumberTest.php

@@ -34,7 +34,7 @@ class NumberTest extends TestCase {
 	public function setUp() {
 		parent::setUp();
 		$this->Number = new Number();
-		$this->locale = I18n::defaultLocale();
+		$this->locale = I18n::locale();
 	}
 
 /**
@@ -45,7 +45,7 @@ class NumberTest extends TestCase {
 	public function tearDown() {
 		parent::tearDown();
 		unset($this->Number);
-		I18n::defaultLocale($this->locale);
+		I18n::locale($this->locale);
 		Number::defaultCurrency(false);
 	}
 
@@ -276,7 +276,7 @@ class NumberTest extends TestCase {
 		$this->assertEquals('USD', $result);
 
 		$this->Number->defaultCurrency(false);
-		I18n::defaultLocale('es_ES');
+		I18n::locale('es_ES');
 		$this->assertEquals('EUR', $this->Number->defaultCurrency());
 
 		$this->Number->defaultCurrency('JPY');
@@ -361,7 +361,7 @@ class NumberTest extends TestCase {
  * @return void
  */
 	public function testPrecisionLocalized() {
-		I18n::defaultLocale('fr_FR');
+		I18n::locale('fr_FR');
 		$result = $this->Number->precision(1.234);
 		$this->assertEquals('1,234', $result);
 	}
@@ -486,7 +486,7 @@ class NumberTest extends TestCase {
  * @return void
  */
 	public function testReadableSizeLocalized() {
-		I18n::defaultLocale('fr_FR');
+		I18n::locale('fr_FR');
 		$result = $this->Number->toReadableSize(1321205);
 		$this->assertEquals('1,26 MB', $result);
 

+ 99 - 0
tests/TestCase/Model/Behavior/TranslateBehaviorTest.php

@@ -16,6 +16,7 @@ namespace Cake\Test\TestCase\Model\Behavior;
 
 use Cake\Collection\Collection;
 use Cake\Event\Event;
+use Cake\I18n\I18n;
 use Cake\Model\Behavior\TranslateBehavior;
 use Cake\ORM\Entity;
 use Cake\ORM\TableRegistry;
@@ -40,6 +41,7 @@ class TranslateBehaviorTest extends TestCase {
 
 	public function tearDown() {
 		parent::tearDown();
+		I18n::locale(I18n::defaultLocale());
 		TableRegistry::clear();
 	}
 
@@ -80,6 +82,103 @@ class TranslateBehaviorTest extends TestCase {
 	}
 
 /**
+ * Tests that fields from a translated model use the I18n class locale
+ * and that it propogates to associated models
+ *
+ * @return void
+ */
+	public function testFindSingleLocaleAssociatedEnv() {
+		I18n::locale('eng');
+
+		$table = TableRegistry::get('Articles');
+		$table->addBehavior('Translate', ['fields' => ['title', 'body']]);
+
+		$table->hasMany('Comments');
+		$table->Comments->addBehavior('Translate', ['fields' => ['comment']]);
+
+		$results = $table->find()
+			->select(['id', 'title', 'body'])
+			->contain(['Comments' => ['fields' => ['article_id', 'comment']]])
+			->hydrate(false)
+			->toArray();
+
+		$expected = [
+			[
+				'id' => 1,
+				'title' => 'Title #1',
+				'body' => 'Content #1',
+				'comments' => [
+					['article_id' => 1, 'comment' => 'Comment #1', '_locale' => 'eng'],
+					['article_id' => 1, 'comment' => 'Comment #2', '_locale' => 'eng'],
+					['article_id' => 1, 'comment' => 'Comment #3', '_locale' => 'eng'],
+					['article_id' => 1, 'comment' => 'Comment #4', '_locale' => 'eng']
+				],
+				'_locale' => 'eng'
+			],
+			[
+				'id' => 2,
+				'title' => 'Title #2',
+				'body' => 'Content #2',
+				'comments' => [
+					['article_id' => 2, 'comment' => 'First Comment for Second Article', '_locale' => 'eng'],
+					['article_id' => 2, 'comment' => 'Second Comment for Second Article', '_locale' => 'eng']
+				],
+				'_locale' => 'eng'
+			],
+			[
+				'id' => 3,
+				'title' => 'Title #3',
+				'body' => 'Content #3',
+				'comments' => [],
+				'_locale' => 'eng'
+			]
+		];
+		$this->assertSame($expected, $results);
+
+		I18n::locale('spa');
+
+		$results = $table->find()
+			->select(['id', 'title', 'body'])
+			->contain(['Comments' => ['fields' => ['article_id', 'comment']]])
+			->hydrate(false)
+			->toArray();
+
+		$expected = [
+			[
+				'id' => 1,
+				'title' => 'First Article',
+				'body' => 'First Article Body',
+				'comments' => [
+					['article_id' => 1, 'comment' => 'First Comment for First Article', '_locale' => 'spa'],
+					['article_id' => 1, 'comment' => 'Second Comment for First Article', '_locale' => 'spa'],
+					['article_id' => 1, 'comment' => 'Third Comment for First Article', '_locale' => 'spa'],
+					['article_id' => 1, 'comment' => 'Comentario #4', '_locale' => 'spa']
+				],
+				'_locale' => 'spa'
+			],
+			[
+				'id' => 2,
+				'title' => 'Second Article',
+				'body' => 'Second Article Body',
+				'comments' => [
+					['article_id' => 2, 'comment' => 'First Comment for Second Article', '_locale' => 'spa'],
+					['article_id' => 2, 'comment' => 'Second Comment for Second Article', '_locale' => 'spa']
+				],
+				'_locale' => 'spa'
+			],
+			[
+				'id' => 3,
+				'title' => 'Third Article',
+				'body' => 'Third Article Body',
+				'comments' => [],
+				'_locale' => 'spa'
+			]
+		];
+		$this->assertSame($expected, $results);
+
+	}
+
+/**
  * Tests that fields from a translated model are not overriden if translation
  * is null
  *