diff --git a/Library/Phalcon/Translate/Adapter/CsvMulti.php b/Library/Phalcon/Translate/Adapter/CsvMulti.php new file mode 100644 index 000000000..907b51945 --- /dev/null +++ b/Library/Phalcon/Translate/Adapter/CsvMulti.php @@ -0,0 +1,126 @@ + $locale) { + $this->locales[$pos] = $locale; + } + } else { + // the first row is the translation index (label) + $index = array_shift($data); + // store this index internally + $this->indexes[] = $index; + // the first element is removed as well, so the pos is according to the first line + foreach ($data as $pos => $translation) { + $this->_translate[$this->locales[$pos]][$index] = $translation; + } + } + } + + fclose($fileHandler); + } + + /** + * Sets locale information, according to one from the header row of the source csv + * Set it to false for enabling the "no translation mode" + * + * // Set locale to Dutch + * $adapter->setLocale('nl_NL'); + * + */ + public function setLocale($locale) + { + if ($locale !== false && !array_key_exists($locale, $this->_translate)) { + throw new Exception("The locale '{$locale}' is not available in the data source."); + return false; + } else { + return $this->locale = $locale; + } + } + + /** + * Returns the translation related to the given key and the previsouly set locale + */ + public function query($index, $placeholders = null) + { + if (!$this->exists($index)) { + throw new Exception("They key '{$index}' was not found."); + } + + if ($this->locale === false) { + // "no translation mode" + $translation = $index; + } else { + $translation = $this->_translate[$this->locale][$index]; + } + + return $this->replacePlaceholders($translation, $placeholders); + } + + /** + * Check whether is defined a translation key in the internal array + */ + public function exists($index) + { + if (is_null($this->locale)) { + throw new Exception('The locale must have been defined.'); + } + return in_array($index, $this->getIndexes()); + } + + /** + * Returns all the translation keys + */ + public function getIndexes() + { + return $this->indexes; + } +} diff --git a/Library/Phalcon/Translate/Adapter/README.md b/Library/Phalcon/Translate/Adapter/README.md index 83c3609d0..28e93fb6d 100644 --- a/Library/Phalcon/Translate/Adapter/README.md +++ b/Library/Phalcon/Translate/Adapter/README.md @@ -165,3 +165,24 @@ root { [1]: http://docs.phalconphp.com/en/latest/api/Phalcon_DI.html [2]: http://docs.phalconphp.com/en/latest/reference/volt.html [3]: http://php.net/manual/en/book.intl.php + +## MultiCsv + +This adapter extends *Phalcon\Translate\Adapter\Csv* by allowing one csv file for several languages. + +* CSV example (blank spaces added for readability): +```csv +#ignored; en_US; fr_FR; es_ES +label_street; street; rue; calle +label_car; car; voiture; coche +label_home; home; maison; casa +``` +* PHP example : +```php +// the constructor is inherited from Phalcon\Translate\Adapter\Csv +$titles_translater = new Phalcon\Translate\Adapter\MultiCsv([ + 'content' => "{$config->langDir}/titles.csv" +]); +$titles_translater->setLocale('es_ES'); +echo $titles_translater->query('label_home'); // string 'casa' +``` diff --git a/composer.json b/composer.json index 94301ee8d..fd6040263 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "phpdocumentor/reflection-docblock": "2.0.4", "phpunit/phpunit": "^4.8", "squizlabs/php_codesniffer": "^2.9", - "codeception/codeception": "2.3.6", + "codeception/codeception": "^2.5", "codeception/mockery-module": "0.2.2", "codeception/aerospike-module": "^1.0", "codeception/specify": "^0.4", diff --git a/tests/_data/assets/translation/csv/names.csv b/tests/_data/assets/translation/csv/names.csv new file mode 100644 index 000000000..f8853f67e --- /dev/null +++ b/tests/_data/assets/translation/csv/names.csv @@ -0,0 +1,4 @@ +;en_US;fr_FR;es_ES +label_street;street;rue;calle +label_car;car;voiture;coche +label_home;home;maison;casa \ No newline at end of file diff --git a/tests/unit/Session/Adapter/DatabaseTest.php b/tests/unit/Session/Adapter/DatabaseTest.php index 9a4f38d10..5a2afa906 100644 --- a/tests/unit/Session/Adapter/DatabaseTest.php +++ b/tests/unit/Session/Adapter/DatabaseTest.php @@ -84,22 +84,20 @@ function ($data, $expected) { }, [ 'examples' => [ - [$_SESSION['customer_id'], 'somekey'] + [$this->session->get('customer_id'), 'somekey'] ] ] ); - - + + session_start(); $this->session->write($sessionID, session_encode()); $this->tester->seeInDatabase(ModelSession::$table, ['session_id' => $sessionID]); $this->tester->seeInDatabase(ModelSession::$table, ['data' => 'customer_id|s:7:"somekey";']); $this->session->remove('customer_id'); - $sessionData = $this->session->read($sessionID); - session_start(); session_decode($sessionData); - + $this->specify( "Method read() hasn't worked", function ($data, $expected) { @@ -107,7 +105,7 @@ function ($data, $expected) { }, [ 'examples' => [ - [$_SESSION['customer_id'], 'somekey'] + [$this->session->get('customer_id'), 'somekey'] ] ] ); @@ -123,7 +121,20 @@ function ($data, $expected) { $sessionData = $this->session->read($sessionID); session_start(); session_decode($sessionData); - + + $session = $this->session; + $this->specify( + "Method read() hasn't worked", + function ($data, $expected) use ($session) { + expect($data)->equals($expected); + }, + [ + 'examples' => [ + [$this->session->get('customer_id'), 'somekey'] + ] + ] + ); + $this->specify( "Method update() hasn't worked", function ($data, $expected) { @@ -131,8 +142,8 @@ function ($data, $expected) { }, [ 'examples' => [ - [$_SESSION['customer_id'], 'somekey'], - [$_SESSION['customer_id2'], 'somekey2'] + [$this->session->get('customer_id'), 'somekey'], + [$this->session->get('customer_id2'), 'somekey2'] ] ] ); diff --git a/tests/unit/Translate/Adapter/CsvMulti/Base.php b/tests/unit/Translate/Adapter/CsvMulti/Base.php new file mode 100644 index 000000000..49d3a23e2 --- /dev/null +++ b/tests/unit/Translate/Adapter/CsvMulti/Base.php @@ -0,0 +1,27 @@ + $content]; + $this->adapter = new CsvMulti($params); + } + + public function _after() + { + $this->adapter = null; + } + +} \ No newline at end of file diff --git a/tests/unit/Translate/Adapter/CsvMulti/ExistsCest.php b/tests/unit/Translate/Adapter/CsvMulti/ExistsCest.php new file mode 100644 index 000000000..1714ecb8d --- /dev/null +++ b/tests/unit/Translate/Adapter/CsvMulti/ExistsCest.php @@ -0,0 +1,43 @@ +wantToTest('Translate\Adapter\CsvMulti - exists cannot work without a locale having been set'); + $I->expectThrowable( + new Exception('The locale must have been defined.'), + function () { + $this->adapter->exists('label_street'); + } + ); + } + + public function translateAdapterExistsItDoesnt(UnitTester $I) + { + $I->wantToTest('Translate\Adapter\CsvMulti - exists returns false'); + $this->adapter->setLocale('en_US'); + $I->assertFalse($this->adapter->exists('label_cat')); + } + + public function translateAdapterExistsItDoes(UnitTester $I) + { + $I->wantToTest('Translate\Adapter\CsvMulti - exists returns true'); + $this->adapter->setLocale('en_US'); + $I->assertTrue($this->adapter->exists('label_street')); + $I->assertTrue($this->adapter->exists('label_car')); + $I->assertTrue($this->adapter->exists('label_home')); + } +} diff --git a/tests/unit/Translate/Adapter/CsvMulti/GetIndexCest.php b/tests/unit/Translate/Adapter/CsvMulti/GetIndexCest.php new file mode 100644 index 000000000..88ed5b138 --- /dev/null +++ b/tests/unit/Translate/Adapter/CsvMulti/GetIndexCest.php @@ -0,0 +1,22 @@ +wantToTest('Translate\Adapter\CsvMulti - getIndexes returns the indexes'); + $this->adapter->setLocale('en_US'); + $I->assertEquals(['label_street', 'label_car', 'label_home'], $this->adapter->getIndexes()); + } +} diff --git a/tests/unit/Translate/Adapter/CsvMulti/QueryCest.php b/tests/unit/Translate/Adapter/CsvMulti/QueryCest.php new file mode 100644 index 000000000..e2d5ef32a --- /dev/null +++ b/tests/unit/Translate/Adapter/CsvMulti/QueryCest.php @@ -0,0 +1,54 @@ +wantToTest('Translate\Adapter\CsvMulti - query returns the key when locale is false'); + $this->adapter->setLocale(false); + $I->assertEquals('label_street', $this->adapter->query('label_street')); + $I->assertEquals('label_street', $this->adapter->query('label_street', 'placeholder_for_street')); + } + + public function queryDoesTranslate(UnitTester $I) + { + $I->wantToTest('Translate\Adapter\CsvMulti - query returns the translated string matching the index'); + $this->adapter->setLocale('en_US'); + $I->assertEquals('street', $this->adapter->query('label_street')); + $I->assertEquals('car', $this->adapter->query('label_car')); + $I->assertEquals('home', $this->adapter->query('label_home')); + $this->adapter->setLocale('fr_FR'); + $I->assertEquals('rue', $this->adapter->query('label_street')); + $I->assertEquals('voiture', $this->adapter->query('label_car')); + $I->assertEquals('maison', $this->adapter->query('label_home')); + $this->adapter->setLocale('es_ES'); + $I->assertEquals('calle', $this->adapter->query('label_street')); + $I->assertEquals('coche', $this->adapter->query('label_car')); + $I->assertEquals('casa', $this->adapter->query('label_home')); + } + + public function queryKeyDoesntExist(UnitTester $I) + { + $I->wantToTest('Translate\Adapter\CsvMulti - query raises an exception when the key doesn\'t match'); + $I->expectThrowable( + new Exception("They key 'label_unexists' was not found."), + function () { + $this->adapter->setLocale('en_US'); + $this->adapter->query('label_unexists'); + } + ); + } +}