Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Commit

Permalink
Merge branch 'feature/i18n-translator-ini' into develop
Browse files Browse the repository at this point in the history
Close #2706
  • Loading branch information
weierophinney committed Dec 10, 2012
2 parents 129b628 + c6a496c commit ad6a44d
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 8 deletions.
86 changes: 86 additions & 0 deletions library/Zend/I18n/Translator/Loader/Ini.php
@@ -0,0 +1,86 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_I18n
*/

namespace Zend\I18n\Translator\Loader;

use Zend\Config\Reader\Ini as IniReader;
use Zend\I18n\Exception;
use Zend\I18n\Translator\Plural\Rule as PluralRule;
use Zend\I18n\Translator\TextDomain;

/**
* PHP INI format loader.
*
* @category Zend
* @package Zend_I18n
* @subpackage Translator
*/
class Ini implements FileLoaderInterface
{
/**
* load(): defined by FileLoaderInterface.
*
* @see FileLoaderInterface::load()
* @param string $locale
* @param string $filename
* @return TextDomain|null
* @throws Exception\InvalidArgumentException
*/
public function load($locale, $filename)
{
if (!is_file($filename) || !is_readable($filename)) {
throw new Exception\InvalidArgumentException(sprintf(
'Could not open file %s for reading',
$filename
));
}

$messages = array();
$iniReader = new IniReader();
$messagesNamespaced = $iniReader->fromFile($filename);

$list = $messagesNamespaced;
if (isset($messagesNamespaced['translation'])) {
$list = $messagesNamespaced['translation'];
}

foreach ($list as $message) {
if (!is_array($message) || count($message) < 2) {
throw new Exception\InvalidArgumentException(
'Each INI row must be an array with message and translation'
);
}
if (isset($message['message']) && isset($message['translation'])) {
$messages[$message['message']] = $message['translation'];
continue;
}
$messages[array_shift($message)] = array_shift($message);
}

if (!is_array($messages)) {
throw new Exception\InvalidArgumentException(sprintf(
'Expected an array, but received %s',
gettype($messages)
));
}

$textDomain = new TextDomain($messages);

if (array_key_exists('plural', $messagesNamespaced)
&& isset($messagesNamespaced['plural']['plural_forms'])
) {
$textDomain->setPluralRule(
PluralRule::fromString($messagesNamespaced['plural']['plural_forms'])
);
}

return $textDomain;
}
}
3 changes: 2 additions & 1 deletion library/Zend/I18n/Translator/LoaderPluginManager.php
Expand Up @@ -32,8 +32,9 @@ class LoaderPluginManager extends AbstractPluginManager
* @var array * @var array
*/ */
protected $invokableClasses = array( protected $invokableClasses = array(
'phparray' => 'Zend\I18n\Translator\Loader\PhpArray',
'gettext' => 'Zend\I18n\Translator\Loader\Gettext', 'gettext' => 'Zend\I18n\Translator\Loader\Gettext',
'ini' => 'Zend\I18n\Translator\Loader\Ini',
'phparray' => 'Zend\I18n\Translator\Loader\PhpArray',
); );


/** /**
Expand Down
14 changes: 7 additions & 7 deletions resources/languages/fr/Zend_Validate.php
Expand Up @@ -81,7 +81,7 @@
// Zend_Validator_DateStep // Zend_Validator_DateStep
"Invalid type given. String, integer, array or DateTime expected" => "Entrée invalide. Chaîne, entier, tableau ou DateTime attendu", "Invalid type given. String, integer, array or DateTime expected" => "Entrée invalide. Chaîne, entier, tableau ou DateTime attendu",
"The input does not appear to be a valid date" => "L'entrée ne semble pas être une date valide", "The input does not appear to be a valid date" => "L'entrée ne semble pas être une date valide",
"The input is not a valid step" => "L'entrée n'est pas un intervalle valide", "The input is not a valid step" => "L'entrée n'est pas une step valide",


// Zend_Validator_Db_AbstractDb // Zend_Validator_Db_AbstractDb
"No record matching the input was found" => "Aucun enregistrement trouvé", "No record matching the input was found" => "Aucun enregistrement trouvé",
Expand All @@ -99,7 +99,7 @@
"'%hostname%' does not appear to have any valid MX or A records for the email address" => "'%hostname%' ne semble pas avoir d'enregistrement MX valide pour l'adresse email", "'%hostname%' does not appear to have any valid MX or A records for the email address" => "'%hostname%' ne semble pas avoir d'enregistrement MX valide pour l'adresse email",
"'%hostname%' is not in a routable network segment. The email address should not be resolved from public network" => "'%hostname%' n'est pas dans un segment réseau routable. L'adresse email ne devrait pas être résolue depuis un réseau public.", "'%hostname%' is not in a routable network segment. The email address should not be resolved from public network" => "'%hostname%' n'est pas dans un segment réseau routable. L'adresse email ne devrait pas être résolue depuis un réseau public.",
"'%localPart%' can not be matched against dot-atom format" => "'%localPart%' ne correspond pas au format dot-atom", "'%localPart%' can not be matched against dot-atom format" => "'%localPart%' ne correspond pas au format dot-atom",
"'%localPart%' can not be matched against quoted-string format" => "'%localPart%' ne correspond pas à une chaîne entre quotes", "'%localPart%' can not be matched against quoted-string format" => "'%localPart%' ne correspond pas au format quoted-string",
"'%localPart%' is not a valid local part for the email address" => "'%localPart%' n'est pas une partie locale valide pour l'adresse email", "'%localPart%' is not a valid local part for the email address" => "'%localPart%' n'est pas une partie locale valide pour l'adresse email",
"The input exceeds the allowed length" => "L'entrée dépasse la taille autorisée", "The input exceeds the allowed length" => "L'entrée dépasse la taille autorisée",


Expand Down Expand Up @@ -178,7 +178,7 @@
"File '%value%' is not readable or does not exist" => "Le fichier '%value%' n'est pas lisible ou n'existe pas", "File '%value%' is not readable or does not exist" => "Le fichier '%value%' n'est pas lisible ou n'existe pas",


// Zend_Validator_File_Upload // Zend_Validator_File_Upload
"File '%value%' exceeds the defined ini size" => "Le fichier '%value%' dépasse la taille définie dans le fichier INI", "File '%value%' exceeds the defined ini size" => "File '%value%' dépasse la taille défini dans le fichier INI",
"File '%value%' exceeds the defined form size" => "Le fichier '%value%' dépasse la taille définie dans le formulaire", "File '%value%' exceeds the defined form size" => "Le fichier '%value%' dépasse la taille définie dans le formulaire",
"File '%value%' was only partially uploaded" => "Le fichier '%value%' n'a été que partiellement envoyé", "File '%value%' was only partially uploaded" => "Le fichier '%value%' n'a été que partiellement envoyé",
"File '%value%' was not uploaded" => "Le fichier '%value%' n'a pas été envoyé", "File '%value%' was not uploaded" => "Le fichier '%value%' n'a pas été envoyé",
Expand Down Expand Up @@ -250,11 +250,11 @@
"There was an internal error while using the pattern '%pattern%'" => "Une erreur interne est survenue avec l'expression '%pattern%'", "There was an internal error while using the pattern '%pattern%'" => "Une erreur interne est survenue avec l'expression '%pattern%'",


// Zend_Validator_Sitemap_Changefreq // Zend_Validator_Sitemap_Changefreq
"The input is not a valid sitemap changefreq" => "L'entrée n'est pas une valeur de fréquence de changement de sitemap valide", "The input is not a valid sitemap changefreq" => "L'entrée n'est pas une valeur de fréquence de sitemap valide",
"Invalid type given. String expected" => "Type invalide. Chaîne attendue", "Invalid type given. String expected" => "Type invalide. Chaîne attendue",


// Zend_Validator_Sitemap_Lastmod // Zend_Validator_Sitemap_Lastmod
"The input is not a valid sitemap lastmod" => "L'entrée n'est pas une date de dernière modification de sitemap valide", "The input is not a valid sitemap lastmod" => "L'entrée n'est pas une date de modification de sitemap valide",
"Invalid type given. String expected" => "Type invalide. Chaîne attendue", "Invalid type given. String expected" => "Type invalide. Chaîne attendue",


// Zend_Validator_Sitemap_Loc // Zend_Validator_Sitemap_Loc
Expand All @@ -267,11 +267,11 @@


// Zend_Validator_Step // Zend_Validator_Step
"Invalid value given. Scalar expected" => "Type invalide. Scalaire attendu", "Invalid value given. Scalar expected" => "Type invalide. Scalaire attendu",
"The input is not a valid step" => "L'entrée n'est pas un intervalle valide", "The input is not a valid step" => "L'entrée n'est pas un multiple valide",


// Zend_Validator_StringLength // Zend_Validator_StringLength
"Invalid type given. String expected" => "Type invalide. Chaîne attendue", "Invalid type given. String expected" => "Type invalide. Chaîne attendue",
"The input is less than %min% characters long" => "L'entrée contient moins de %min% caractères", "The input is less than %min% characters long" => "L'entrée conteint moins de %min% caractères",
"The input is more than %max% characters long" => "L'entrée contient plus de %max% caractères", "The input is more than %max% characters long" => "L'entrée contient plus de %max% caractères",


// Zend_Validator_Uri // Zend_Validator_Uri
Expand Down
94 changes: 94 additions & 0 deletions tests/ZendTest/I18n/Translator/Loader/IniTest.php
@@ -0,0 +1,94 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_I18n
*/

namespace ZendTest\I18n\Translator\Loader;

use PHPUnit_Framework_TestCase as TestCase;
use Locale;
use Zend\I18n\Translator\Loader\Ini as IniLoader;

class IniTest extends TestCase
{
protected $testFilesDir;
protected $originalLocale;

public function setUp()
{
$this->testFilesDir = realpath(__DIR__ . '/../_files');
}

public function testLoaderFailsToLoadMissingFile()
{
$loader = new IniLoader();
$this->setExpectedException('Zend\I18n\Exception\InvalidArgumentException', 'Could not open file');
$loader->load('en_EN', 'missing');
}

public function testLoaderLoadsEmptyFile()
{
$loader = new IniLoader();
$textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_empty.ini');
$this->assertInstanceOf('Zend\I18n\Translator\TextDomain', $textDomain);
}

public function testLoaderFailsToLoadNonArray()
{
$loader = new IniLoader();
$this->setExpectedException('Zend\I18n\Exception\InvalidArgumentException',
'Each INI row must be an array with message and translation');
$loader->load('en_EN', $this->testFilesDir . '/failed.ini');
}

public function testLoaderFailsToLoadBadSyntax()
{
$loader = new IniLoader();
$this->setExpectedException('Zend\I18n\Exception\InvalidArgumentException',
'Each INI row must be an array with message and translation');
$loader->load('en_EN', $this->testFilesDir . '/failed_syntax.ini');
}

public function testLoaderReturnsValidTextDomain()
{
$loader = new IniLoader();
$textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_en.ini');

$this->assertEquals('Message 1 (en)', $textDomain['Message 1']);
$this->assertEquals('Message 4 (en)', $textDomain['Message 4']);
}

public function testLoaderReturnsValidTextDomainWithFileWithoutPlural()
{
$loader = new IniLoader();
$textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_en_without_plural.ini');

$this->assertEquals('Message 1 (en)', $textDomain['Message 1']);
$this->assertEquals('Message 4 (en)', $textDomain['Message 4']);
}

public function testLoaderReturnsValidTextDomainWithSimpleSyntax()
{
$loader = new IniLoader();
$textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_en_simple_syntax.ini');

$this->assertEquals('Message 1 (en)', $textDomain['Message 1']);
$this->assertEquals('Message 4 (en)', $textDomain['Message 4']);
}

public function testLoaderLoadsPluralRules()
{
$loader = new IniLoader();
$textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_en.ini');

$this->assertEquals(2, $textDomain->getPluralRule()->evaluate(0));
$this->assertEquals(0, $textDomain->getPluralRule()->evaluate(1));
$this->assertEquals(1, $textDomain->getPluralRule()->evaluate(2));
$this->assertEquals(2, $textDomain->getPluralRule()->evaluate(10));
}
}
1 change: 1 addition & 0 deletions tests/ZendTest/I18n/Translator/_files/failed.ini
@@ -0,0 +1 @@
identifier1 = "Message 1"
1 change: 1 addition & 0 deletions tests/ZendTest/I18n/Translator/_files/failed_syntax.ini
@@ -0,0 +1 @@
identifier1[] = "Message 1"
Empty file.
26 changes: 26 additions & 0 deletions tests/ZendTest/I18n/Translator/_files/translation_en.ini
@@ -0,0 +1,26 @@
[plural]
plural_forms = 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);'

[translation]
identifier1.message = "Message 1"
identifier1.translation = "Message 1 (en)"

identifier2.message = "Message 2"
identifier2.translation = "Message 2 (en)"

identifier3.message = "Message 3"
identifier3.translation = "Message 3 (en)"

identifier4.message = "Message 4"
identifier4.translation = "Message 4 (en)"

identifier5.message = "Message 5"
identifier5.translation.0 = "Message 5 (en) Plural 0"
identifier5.translation.1 = "Message 5 (en) Plural 1"
identifier5.translation.2 = "Message 5 (en) Plural 2"

identifier6.message = "Cooking furniture"
identifier6.translation = "Küchen Möbel (en)"

identifier7.message = "Küchen Möbel"
identifier7.translation = "Cooking furniture (en)"
@@ -0,0 +1,26 @@
[plural]
plural_forms = 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);'

[translation]
identifier1[] = "Message 1"
identifier1[] = "Message 1 (en)"

identifier2[] = "Message 2"
identifier2[] = "Message 2 (en)"

identifier3[] = "Message 3"
identifier3[] = "Message 3 (en)"

identifier4[] = "Message 4"
identifier4[] = "Message 4 (en)"

identifier5.message = "Message 5"
identifier5.translation.0 = "Message 5 (en) Plural 0"
identifier5.translation.1 = "Message 5 (en) Plural 1"
identifier5.translation.2 = "Message 5 (en) Plural 2"

identifier6[] = "Cooking furniture"
identifier6[] = "Küchen Möbel (en)"

identifier7[] = "Küchen Möbel"
identifier7[] = "Cooking furniture (en)"
@@ -0,0 +1,22 @@
identifier1.message = "Message 1"
identifier1.translation = "Message 1 (en)"

identifier2.message = "Message 2"
identifier2.translation = "Message 2 (en)"

identifier3.message = "Message 3"
identifier3.translation = "Message 3 (en)"

identifier4.message = "Message 4"
identifier4.translation = "Message 4 (en)"

identifier5.message = "Message 5"
identifier5.translation.0 = "Message 5 (en) Plural 0"
identifier5.translation.1 = "Message 5 (en) Plural 1"
identifier5.translation.2 = "Message 5 (en) Plural 2"

identifier6.message = "Cooking furniture"
identifier6.translation = "Küchen Möbel (en)"

identifier7.message = "Küchen Möbel"
identifier7.translation = "Cooking furniture (en)"

0 comments on commit ad6a44d

Please sign in to comment.