Issue #2546618 by plach, dawehner, chx, bojanz: Replace the Symfony Translation component with a custom interface since we don't use it
parent
bc05470d2e
commit
3d2cf1a03f
|
@ -120,7 +120,8 @@
|
|||
"drupal/update": "self.version",
|
||||
"drupal/user": "self.version",
|
||||
"drupal/views": "self.version",
|
||||
"drupal/views_ui": "self.version"
|
||||
"drupal/views_ui": "self.version",
|
||||
"symfony/translation": "~2.4"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
|
@ -128,7 +129,8 @@
|
|||
"psr-4": {
|
||||
"Drupal\\Core\\": "lib/Drupal/Core",
|
||||
"Drupal\\Component\\": "lib/Drupal/Component",
|
||||
"Drupal\\Driver\\": "../drivers/lib/Drupal/Driver"
|
||||
"Drupal\\Driver\\": "../drivers/lib/Drupal/Driver",
|
||||
"Symfony\\Component\\Translation\\": "lib/Symfony/Component/Translation"
|
||||
},
|
||||
"files": [
|
||||
"lib/Drupal.php"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "e789e5736fbe96c9b9502e89b53dcebe",
|
||||
"hash": "5916317ae84f5caeb1bb254f4fe65775",
|
||||
"packages": [
|
||||
{
|
||||
"name": "behat/mink",
|
||||
|
@ -2916,67 +2916,6 @@
|
|||
"homepage": "https://symfony.com",
|
||||
"time": "2015-08-31 16:44:53"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v2.7.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Translation.git",
|
||||
"reference": "485877661835e188cd78345c6d4eef1290d17571"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Translation/zipball/485877661835e188cd78345c6d4eef1290d17571",
|
||||
"reference": "485877661835e188cd78345c6d4eef1290d17571",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<2.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.7",
|
||||
"symfony/intl": "~2.4",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/yaml": "~2.2"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "To use logging capability in translator",
|
||||
"symfony/config": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Translation\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-09-06 08:36:38"
|
||||
},
|
||||
{
|
||||
"name": "symfony/validator",
|
||||
"version": "v2.7.4",
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Validation;
|
||||
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Drupal\Core\Validation\TranslatorInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
use Symfony\Component\Validator\ConstraintViolationList;
|
||||
|
@ -68,7 +68,7 @@ class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface
|
|||
/**
|
||||
* The translator.
|
||||
*
|
||||
* @var \Symfony\Component\Translation\TranslatorInterface
|
||||
* @var \Drupal\Core\Validation\TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
|
@ -117,7 +117,7 @@ class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface
|
|||
* The property string.
|
||||
* @param mixed $invalidValue
|
||||
* The invalid value.
|
||||
* @param \Symfony\Component\Translation\TranslatorInterface $translator
|
||||
* @param \Drupal\Core\Validation\TranslatorInterface $translator
|
||||
* The translator.
|
||||
* @param null $translationDomain
|
||||
* (optional) The translation domain.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Validation;
|
||||
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Drupal\Core\Validation\TranslatorInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
use Symfony\Component\Validator\ConstraintViolationList;
|
||||
|
@ -38,7 +38,7 @@ class ExecutionContext implements ExecutionContextInterface {
|
|||
protected $root;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Translation\TranslatorInterface
|
||||
* @var \Drupal\Core\Validation\TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
|
@ -117,7 +117,7 @@ class ExecutionContext implements ExecutionContextInterface {
|
|||
* The validator.
|
||||
* @param mixed $root
|
||||
* The root.
|
||||
* @param \Symfony\Component\Translation\TranslatorInterface $translator
|
||||
* @param \Drupal\Core\Validation\TranslatorInterface $translator
|
||||
* The translator.
|
||||
* @param string $translationDomain
|
||||
* (optional) The translation domain.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Validation;
|
||||
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Drupal\Core\Validation\TranslatorInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextFactoryInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
|
@ -21,7 +21,7 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|||
class ExecutionContextFactory implements ExecutionContextFactoryInterface {
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface
|
||||
* @var \Drupal\Core\Validation\TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
|
@ -33,7 +33,7 @@ class ExecutionContextFactory implements ExecutionContextFactoryInterface {
|
|||
/**
|
||||
* Constructs a new ExecutionContextFactory instance.
|
||||
*
|
||||
* @param \Symfony\Component\Translation\TranslatorInterface $translator
|
||||
* @param \Drupal\Core\Validation\TranslatorInterface $translator
|
||||
* The translator instance.
|
||||
* @param string $translationDomain
|
||||
* (optional) The translation domain.
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Validation;
|
||||
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Translates strings using Drupal's translation system.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\TranslatorInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation;
|
||||
|
||||
use Symfony\Component\Translation\TranslatorInterface as SymfonyTranslatorInterface;
|
||||
|
||||
/**
|
||||
* Defines an interface used in validation.
|
||||
*
|
||||
* This extends the interface used by the Symfony validator in order to indicate
|
||||
* that the Drupal code is actually independent from the Symfony translation
|
||||
* component.
|
||||
*
|
||||
* @see https://github.com/symfony/symfony/pull/6189
|
||||
* @see https://github.com/symfony/symfony/issues/15714
|
||||
*/
|
||||
interface TranslatorInterface extends SymfonyTranslatorInterface {
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
Symfony component interfaces included as part of the Drupal codebase are used to
|
||||
provide Drupal-specific implementations of Symfony subsystems that are not
|
||||
available as standalone components and thus cannot be cherry-picked.
|
||||
|
||||
A composer.json "replace" entry is used in order to bypass the composer.json
|
||||
dependency onto the Symfony components originally including the interfaces
|
||||
provided here.
|
|
@ -16,10 +16,8 @@ use Drupal\Core\TypedData\Validation\ExecutionContextFactory;
|
|||
use Drupal\Core\TypedData\Validation\RecursiveValidator;
|
||||
use Drupal\Core\Validation\ConstraintManager;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\Translation\IdentityTranslator;
|
||||
use Symfony\Component\Validator\ConstraintValidatorFactory;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
use Symfony\Component\Validator\DefaultTranslator;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\TypedData\Validation\RecursiveContextualValidator
|
||||
|
@ -82,7 +80,12 @@ class RecursiveContextualValidatorTest extends UnitTestCase {
|
|||
$container->set('typed_data_manager', $this->typedDataManager);
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
$translator = new IdentityTranslator();
|
||||
$translator = $this->getMock('Drupal\Core\Validation\TranslatorInterface');
|
||||
$translator->expects($this->any())
|
||||
->method('trans')
|
||||
->willReturnCallback(function($id) {
|
||||
return $id;
|
||||
});
|
||||
$this->contextFactory = new ExecutionContextFactory($translator);
|
||||
$this->validatorFactory = new ConstraintValidatorFactory();
|
||||
$this->recursiveValidator = new RecursiveValidator($this->contextFactory, $this->validatorFactory, $this->typedDataManager);
|
||||
|
|
|
@ -12,7 +12,7 @@ return array(
|
|||
'Zend\\Diactoros\\' => array($vendorDir . '/zendframework/zend-diactoros/src'),
|
||||
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
|
||||
'Symfony\\Component\\Validator\\' => array($vendorDir . '/symfony/validator'),
|
||||
'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
|
||||
'Symfony\\Component\\Translation\\' => array($baseDir . '/lib/Symfony/Component/Translation'),
|
||||
'Symfony\\Component\\Serializer\\' => array($vendorDir . '/symfony/serializer'),
|
||||
'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'),
|
||||
'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
|
||||
|
|
|
@ -3130,69 +3130,6 @@
|
|||
"description": "Symfony Serializer Component",
|
||||
"homepage": "https://symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v2.7.4",
|
||||
"version_normalized": "2.7.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Translation.git",
|
||||
"reference": "485877661835e188cd78345c6d4eef1290d17571"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Translation/zipball/485877661835e188cd78345c6d4eef1290d17571",
|
||||
"reference": "485877661835e188cd78345c6d4eef1290d17571",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<2.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.7",
|
||||
"symfony/intl": "~2.4",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/yaml": "~2.2"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "To use logging capability in translator",
|
||||
"symfony/config": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"time": "2015-09-06 08:36:38",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Translation\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "symfony/validator",
|
||||
"version": "v2.7.4",
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
|
@ -1,47 +0,0 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.7.0
|
||||
-----
|
||||
|
||||
* added DataCollectorTranslator for collecting the translated messages.
|
||||
|
||||
2.6.0
|
||||
-----
|
||||
|
||||
* added possibility to cache catalogues
|
||||
* added TranslatorBagInterface
|
||||
* added LoggingTranslator
|
||||
* added Translator::getMessages() for retrieving the message catalogue as an array
|
||||
|
||||
2.5.0
|
||||
-----
|
||||
|
||||
* added relative file path template to the file dumpers
|
||||
* added optional backup to the file dumpers
|
||||
* changed IcuResFileDumper to extend FileDumper
|
||||
|
||||
2.3.0
|
||||
-----
|
||||
|
||||
* added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues)
|
||||
* added Translator::getFallbackLocales()
|
||||
* deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method
|
||||
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3.
|
||||
* [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now
|
||||
throws Symfony\Component\Translation\Exception\NotFoundResourceException when a resource cannot be found
|
||||
and Symfony\Component\Translation\Exception\InvalidResourceException when a resource is invalid.
|
||||
* changed the exception class thrown by some load() methods from \RuntimeException to \InvalidArgumentException
|
||||
(IcuDatFileLoader, IcuResFileLoader and QtFileLoader)
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* added support for more than one fallback locale
|
||||
* added support for extracting translation messages from templates (Twig and PHP)
|
||||
* added dumpers for translation catalogs
|
||||
* added support for QT, gettext, and ResourceBundles
|
|
@ -1,146 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Catalogue;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
/**
|
||||
* Base catalogues binary operation class.
|
||||
*
|
||||
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||
*/
|
||||
abstract class AbstractOperation implements OperationInterface
|
||||
{
|
||||
/**
|
||||
* @var MessageCatalogueInterface
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* @var MessageCatalogueInterface
|
||||
*/
|
||||
protected $target;
|
||||
|
||||
/**
|
||||
* @var MessageCatalogue
|
||||
*/
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* @var null|array
|
||||
*/
|
||||
private $domains;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $messages;
|
||||
|
||||
/**
|
||||
* @param MessageCatalogueInterface $source
|
||||
* @param MessageCatalogueInterface $target
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function __construct(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
|
||||
{
|
||||
if ($source->getLocale() !== $target->getLocale()) {
|
||||
throw new \LogicException('Operated catalogues must belong to the same locale.');
|
||||
}
|
||||
|
||||
$this->source = $source;
|
||||
$this->target = $target;
|
||||
$this->result = new MessageCatalogue($source->getLocale());
|
||||
$this->domains = null;
|
||||
$this->messages = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDomains()
|
||||
{
|
||||
if (null === $this->domains) {
|
||||
$this->domains = array_values(array_unique(array_merge($this->source->getDomains(), $this->target->getDomains())));
|
||||
}
|
||||
|
||||
return $this->domains;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessages($domain)
|
||||
{
|
||||
if (!in_array($domain, $this->getDomains())) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
|
||||
}
|
||||
|
||||
if (!isset($this->messages[$domain]['all'])) {
|
||||
$this->processDomain($domain);
|
||||
}
|
||||
|
||||
return $this->messages[$domain]['all'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewMessages($domain)
|
||||
{
|
||||
if (!in_array($domain, $this->getDomains())) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
|
||||
}
|
||||
|
||||
if (!isset($this->messages[$domain]['new'])) {
|
||||
$this->processDomain($domain);
|
||||
}
|
||||
|
||||
return $this->messages[$domain]['new'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getObsoleteMessages($domain)
|
||||
{
|
||||
if (!in_array($domain, $this->getDomains())) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
|
||||
}
|
||||
|
||||
if (!isset($this->messages[$domain]['obsolete'])) {
|
||||
$this->processDomain($domain);
|
||||
}
|
||||
|
||||
return $this->messages[$domain]['obsolete'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResult()
|
||||
{
|
||||
foreach ($this->getDomains() as $domain) {
|
||||
if (!isset($this->messages[$domain])) {
|
||||
$this->processDomain($domain);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $domain
|
||||
*/
|
||||
abstract protected function processDomain($domain);
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Catalogue;
|
||||
|
||||
/**
|
||||
* Diff operation between two catalogues.
|
||||
*
|
||||
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||
*/
|
||||
class DiffOperation extends AbstractOperation
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function processDomain($domain)
|
||||
{
|
||||
$this->messages[$domain] = array(
|
||||
'all' => array(),
|
||||
'new' => array(),
|
||||
'obsolete' => array(),
|
||||
);
|
||||
|
||||
foreach ($this->source->all($domain) as $id => $message) {
|
||||
if ($this->target->has($id, $domain)) {
|
||||
$this->messages[$domain]['all'][$id] = $message;
|
||||
$this->result->add(array($id => $message), $domain);
|
||||
if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) {
|
||||
$this->result->setMetadata($id, $keyMetadata, $domain);
|
||||
}
|
||||
} else {
|
||||
$this->messages[$domain]['obsolete'][$id] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->target->all($domain) as $id => $message) {
|
||||
if (!$this->source->has($id, $domain)) {
|
||||
$this->messages[$domain]['all'][$id] = $message;
|
||||
$this->messages[$domain]['new'][$id] = $message;
|
||||
$this->result->add(array($id => $message), $domain);
|
||||
if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) {
|
||||
$this->result->setMetadata($id, $keyMetadata, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Catalogue;
|
||||
|
||||
/**
|
||||
* Merge operation between two catalogues.
|
||||
*
|
||||
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||
*/
|
||||
class MergeOperation extends AbstractOperation
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function processDomain($domain)
|
||||
{
|
||||
$this->messages[$domain] = array(
|
||||
'all' => array(),
|
||||
'new' => array(),
|
||||
'obsolete' => array(),
|
||||
);
|
||||
|
||||
foreach ($this->source->all($domain) as $id => $message) {
|
||||
$this->messages[$domain]['all'][$id] = $message;
|
||||
$this->result->add(array($id => $message), $domain);
|
||||
if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) {
|
||||
$this->result->setMetadata($id, $keyMetadata, $domain);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->target->all($domain) as $id => $message) {
|
||||
if (!$this->source->has($id, $domain)) {
|
||||
$this->messages[$domain]['all'][$id] = $message;
|
||||
$this->messages[$domain]['new'][$id] = $message;
|
||||
$this->result->add(array($id => $message), $domain);
|
||||
if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) {
|
||||
$this->result->setMetadata($id, $keyMetadata, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Catalogue;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
/**
|
||||
* Represents an operation on catalogue(s).
|
||||
*
|
||||
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||
*/
|
||||
interface OperationInterface
|
||||
{
|
||||
/**
|
||||
* Returns domains affected by operation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDomains();
|
||||
|
||||
/**
|
||||
* Returns all valid messages after operation.
|
||||
*
|
||||
* @param string $domain
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMessages($domain);
|
||||
|
||||
/**
|
||||
* Returns new messages after operation.
|
||||
*
|
||||
* @param string $domain
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getNewMessages($domain);
|
||||
|
||||
/**
|
||||
* Returns obsolete messages after operation.
|
||||
*
|
||||
* @param string $domain
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getObsoleteMessages($domain);
|
||||
|
||||
/**
|
||||
* Returns resulting catalogue.
|
||||
*
|
||||
* @return MessageCatalogueInterface
|
||||
*/
|
||||
public function getResult();
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
|
||||
use Symfony\Component\Translation\DataCollectorTranslator;
|
||||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
*/
|
||||
class TranslationDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||
{
|
||||
/**
|
||||
* @var DataCollectorTranslator
|
||||
*/
|
||||
private $translator;
|
||||
|
||||
/**
|
||||
* @param DataCollectorTranslator $translator
|
||||
*/
|
||||
public function __construct(DataCollectorTranslator $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lateCollect()
|
||||
{
|
||||
$messages = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages());
|
||||
|
||||
$this->data = $this->computeCount($messages);
|
||||
$this->data['messages'] = $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function collect(Request $request, Response $response, \Exception $exception = null)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMessages()
|
||||
{
|
||||
return isset($this->data['messages']) ? $this->data['messages'] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCountMissings()
|
||||
{
|
||||
return isset($this->data[DataCollectorTranslator::MESSAGE_MISSING]) ? $this->data[DataCollectorTranslator::MESSAGE_MISSING] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCountFallbacks()
|
||||
{
|
||||
return isset($this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK]) ? $this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCountDefines()
|
||||
{
|
||||
return isset($this->data[DataCollectorTranslator::MESSAGE_DEFINED]) ? $this->data[DataCollectorTranslator::MESSAGE_DEFINED] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'translation';
|
||||
}
|
||||
|
||||
private function sanitizeCollectedMessages($messages)
|
||||
{
|
||||
$result = array();
|
||||
foreach ($messages as $key => $message) {
|
||||
$messageId = $message['locale'].$message['domain'].$message['id'];
|
||||
|
||||
if (!isset($result[$messageId])) {
|
||||
$message['count'] = 1;
|
||||
$messages[$key]['translation'] = $this->sanitizeString($message['translation']);
|
||||
$result[$messageId] = $message;
|
||||
} else {
|
||||
++$result[$messageId]['count'];
|
||||
}
|
||||
|
||||
unset($messages[$key]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function computeCount($messages)
|
||||
{
|
||||
$count = array(
|
||||
DataCollectorTranslator::MESSAGE_DEFINED => 0,
|
||||
DataCollectorTranslator::MESSAGE_MISSING => 0,
|
||||
DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK => 0,
|
||||
);
|
||||
|
||||
foreach ($messages as $message) {
|
||||
++$count[$message['state']];
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
private function sanitizeString($string, $length = 80)
|
||||
{
|
||||
$string = trim(preg_replace('/\s+/', ' ', $string));
|
||||
|
||||
if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($string)) {
|
||||
if (mb_strlen($string, $encoding) > $length) {
|
||||
return mb_substr($string, 0, $length - 3, $encoding).'...';
|
||||
}
|
||||
} elseif (strlen($string) > $length) {
|
||||
return substr($string, 0, $length - 3).'...';
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
*/
|
||||
class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInterface
|
||||
{
|
||||
const MESSAGE_DEFINED = 0;
|
||||
const MESSAGE_MISSING = 1;
|
||||
const MESSAGE_EQUALS_FALLBACK = 2;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface|TranslatorBagInterface
|
||||
*/
|
||||
private $translator;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $messages = array();
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
{
|
||||
if (!$translator instanceof TranslatorBagInterface) {
|
||||
throw new \InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface and TranslatorBagInterface.', get_class($translator)));
|
||||
}
|
||||
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
|
||||
{
|
||||
$trans = $this->translator->trans($id, $parameters, $domain, $locale);
|
||||
$this->collectMessage($locale, $domain, $id, $trans);
|
||||
|
||||
return $trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
|
||||
{
|
||||
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
|
||||
$this->collectMessage($locale, $domain, $id, $trans);
|
||||
|
||||
return $trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setLocale($locale)
|
||||
{
|
||||
$this->translator->setLocale($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getLocale()
|
||||
{
|
||||
return $this->translator->getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue($locale = null)
|
||||
{
|
||||
return $this->translator->getCatalogue($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes through all unknown calls onto the translator object.
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return call_user_func_array(array($this->translator, $method), $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getCollectedMessages()
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $locale
|
||||
* @param string|null $domain
|
||||
* @param string $id
|
||||
* @param string $trans
|
||||
*/
|
||||
private function collectMessage($locale, $domain, $id, $translation)
|
||||
{
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
}
|
||||
|
||||
$id = (string) $id;
|
||||
$catalogue = $this->translator->getCatalogue($locale);
|
||||
$locale = $catalogue->getLocale();
|
||||
if ($catalogue->defines($id, $domain)) {
|
||||
$state = self::MESSAGE_DEFINED;
|
||||
} elseif ($catalogue->has($id, $domain)) {
|
||||
$state = self::MESSAGE_EQUALS_FALLBACK;
|
||||
|
||||
$fallbackCatalogue = $catalogue->getFallBackCatalogue();
|
||||
while ($fallbackCatalogue) {
|
||||
if ($fallbackCatalogue->defines($id, $domain)) {
|
||||
$locale = $fallbackCatalogue->getLocale();
|
||||
break;
|
||||
}
|
||||
|
||||
$fallbackCatalogue = $fallbackCatalogue->getFallBackCatalogue();
|
||||
}
|
||||
} else {
|
||||
$state = self::MESSAGE_MISSING;
|
||||
}
|
||||
|
||||
$this->messages[] = array(
|
||||
'locale' => $locale,
|
||||
'domain' => $domain,
|
||||
'id' => $id,
|
||||
'translation' => $translation,
|
||||
'state' => $state,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* CsvFileDumper generates a csv formatted string representation of a message catalogue.
|
||||
*
|
||||
* @author Stealth35
|
||||
*/
|
||||
class CsvFileDumper extends FileDumper
|
||||
{
|
||||
private $delimiter = ';';
|
||||
private $enclosure = '"';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(MessageCatalogue $messages, $domain = 'messages')
|
||||
{
|
||||
$handle = fopen('php://memory', 'rb+');
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
fputcsv($handle, array($source, $target), $this->delimiter, $this->enclosure);
|
||||
}
|
||||
|
||||
rewind($handle);
|
||||
$output = stream_get_contents($handle);
|
||||
fclose($handle);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delimiter and escape character for CSV.
|
||||
*
|
||||
* @param string $delimiter delimiter character
|
||||
* @param string $enclosure enclosure character
|
||||
*/
|
||||
public function setCsvControl($delimiter = ';', $enclosure = '"')
|
||||
{
|
||||
$this->delimiter = $delimiter;
|
||||
$this->enclosure = $enclosure;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'csv';
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* DumperInterface is the interface implemented by all translation dumpers.
|
||||
* There is no common option.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*/
|
||||
interface DumperInterface
|
||||
{
|
||||
/**
|
||||
* Dumps the message catalogue.
|
||||
*
|
||||
* @param MessageCatalogue $messages The message catalogue
|
||||
* @param array $options Options that are used by the dumper
|
||||
*/
|
||||
public function dump(MessageCatalogue $messages, $options = array());
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* FileDumper is an implementation of DumperInterface that dump a message catalogue to file(s).
|
||||
* Performs backup of already existing files.
|
||||
*
|
||||
* Options:
|
||||
* - path (mandatory): the directory where the files should be saved
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*/
|
||||
abstract class FileDumper implements DumperInterface
|
||||
{
|
||||
/**
|
||||
* A template for the relative paths to files.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $relativePathTemplate = '%domain%.%locale%.%extension%';
|
||||
|
||||
/**
|
||||
* Make file backup before the dump.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $backup = true;
|
||||
|
||||
/**
|
||||
* Sets the template for the relative paths to files.
|
||||
*
|
||||
* @param string $relativePathTemplate A template for the relative paths to files
|
||||
*/
|
||||
public function setRelativePathTemplate($relativePathTemplate)
|
||||
{
|
||||
$this->relativePathTemplate = $relativePathTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets backup flag.
|
||||
*
|
||||
* @param bool
|
||||
*/
|
||||
public function setBackup($backup)
|
||||
{
|
||||
$this->backup = $backup;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dump(MessageCatalogue $messages, $options = array())
|
||||
{
|
||||
if (!array_key_exists('path', $options)) {
|
||||
throw new \InvalidArgumentException('The file dumper needs a path option.');
|
||||
}
|
||||
|
||||
// save a file for each domain
|
||||
foreach ($messages->getDomains() as $domain) {
|
||||
// backup
|
||||
$fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale());
|
||||
if (file_exists($fullpath)) {
|
||||
if ($this->backup) {
|
||||
copy($fullpath, $fullpath.'~');
|
||||
}
|
||||
} else {
|
||||
$directory = dirname($fullpath);
|
||||
if (!file_exists($directory) && !@mkdir($directory, 0777, true)) {
|
||||
throw new \RuntimeException(sprintf('Unable to create directory "%s".', $directory));
|
||||
}
|
||||
}
|
||||
// save file
|
||||
file_put_contents($fullpath, $this->format($messages, $domain));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a domain of a message catalogue to its string representation.
|
||||
*
|
||||
* @param MessageCatalogue $messages
|
||||
* @param string $domain
|
||||
*
|
||||
* @return string representation
|
||||
*/
|
||||
abstract protected function format(MessageCatalogue $messages, $domain);
|
||||
|
||||
/**
|
||||
* Gets the file extension of the dumper.
|
||||
*
|
||||
* @return string file extension
|
||||
*/
|
||||
abstract protected function getExtension();
|
||||
|
||||
/**
|
||||
* Gets the relative file path using the template.
|
||||
*
|
||||
* @param string $domain The domain
|
||||
* @param string $locale The locale
|
||||
*
|
||||
* @return string The relative file path
|
||||
*/
|
||||
private function getRelativePath($domain, $locale)
|
||||
{
|
||||
return strtr($this->relativePathTemplate, array(
|
||||
'%domain%' => $domain,
|
||||
'%locale%' => $locale,
|
||||
'%extension%' => $this->getExtension(),
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue.
|
||||
*
|
||||
* @author Stealth35
|
||||
*/
|
||||
class IcuResFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $relativePathTemplate = '%domain%/%locale%.%extension%';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(MessageCatalogue $messages, $domain = 'messages')
|
||||
{
|
||||
$data = $indexes = $resources = '';
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$indexes .= pack('v', strlen($data) + 28);
|
||||
$data .= $source."\0";
|
||||
}
|
||||
|
||||
$data .= $this->writePadding($data);
|
||||
|
||||
$keyTop = $this->getPosition($data);
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$resources .= pack('V', $this->getPosition($data));
|
||||
|
||||
$data .= pack('V', strlen($target))
|
||||
.mb_convert_encoding($target."\0", 'UTF-16LE', 'UTF-8')
|
||||
.$this->writePadding($data)
|
||||
;
|
||||
}
|
||||
|
||||
$resOffset = $this->getPosition($data);
|
||||
|
||||
$data .= pack('v', count($messages))
|
||||
.$indexes
|
||||
.$this->writePadding($data)
|
||||
.$resources
|
||||
;
|
||||
|
||||
$bundleTop = $this->getPosition($data);
|
||||
|
||||
$root = pack('V7',
|
||||
$resOffset + (2 << 28), // Resource Offset + Resource Type
|
||||
6, // Index length
|
||||
$keyTop, // Index keys top
|
||||
$bundleTop, // Index resources top
|
||||
$bundleTop, // Index bundle top
|
||||
count($messages), // Index max table length
|
||||
0 // Index attributes
|
||||
);
|
||||
|
||||
$header = pack('vC2v4C12@32',
|
||||
32, // Header size
|
||||
0xDA, 0x27, // Magic number 1 and 2
|
||||
20, 0, 0, 2, // Rest of the header, ..., Size of a char
|
||||
0x52, 0x65, 0x73, 0x42, // Data format identifier
|
||||
1, 2, 0, 0, // Data version
|
||||
1, 4, 0, 0 // Unicode version
|
||||
);
|
||||
|
||||
$output = $header
|
||||
.$root
|
||||
.$data;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function writePadding($data)
|
||||
{
|
||||
$padding = strlen($data) % 4;
|
||||
|
||||
if ($padding) {
|
||||
return str_repeat("\xAA", 4 - $padding);
|
||||
}
|
||||
}
|
||||
|
||||
private function getPosition($data)
|
||||
{
|
||||
$position = (strlen($data) + 28) / 4;
|
||||
|
||||
return $position;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'res';
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* IniFileDumper generates an ini formatted string representation of a message catalogue.
|
||||
*
|
||||
* @author Stealth35
|
||||
*/
|
||||
class IniFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(MessageCatalogue $messages, $domain = 'messages')
|
||||
{
|
||||
$output = '';
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$escapeTarget = str_replace('"', '\"', $target);
|
||||
$output .= $source.'="'.$escapeTarget."\"\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'ini';
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* JsonFileDumper generates an json formatted string representation of a message catalogue.
|
||||
*
|
||||
* @author singles
|
||||
*/
|
||||
class JsonFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(MessageCatalogue $messages, $domain = 'messages')
|
||||
{
|
||||
return json_encode($messages->all($domain), defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'json';
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Loader\MoFileLoader;
|
||||
|
||||
/**
|
||||
* MoFileDumper generates a gettext formatted string representation of a message catalogue.
|
||||
*
|
||||
* @author Stealth35
|
||||
*/
|
||||
class MoFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(MessageCatalogue $messages, $domain = 'messages')
|
||||
{
|
||||
$output = $sources = $targets = $sourceOffsets = $targetOffsets = '';
|
||||
$offsets = array();
|
||||
$size = 0;
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$offsets[] = array_map('strlen', array($sources, $source, $targets, $target));
|
||||
$sources .= "\0".$source;
|
||||
$targets .= "\0".$target;
|
||||
++$size;
|
||||
}
|
||||
|
||||
$header = array(
|
||||
'magicNumber' => MoFileLoader::MO_LITTLE_ENDIAN_MAGIC,
|
||||
'formatRevision' => 0,
|
||||
'count' => $size,
|
||||
'offsetId' => MoFileLoader::MO_HEADER_SIZE,
|
||||
'offsetTranslated' => MoFileLoader::MO_HEADER_SIZE + (8 * $size),
|
||||
'sizeHashes' => 0,
|
||||
'offsetHashes' => MoFileLoader::MO_HEADER_SIZE + (16 * $size),
|
||||
);
|
||||
|
||||
$sourcesSize = strlen($sources);
|
||||
$sourcesStart = $header['offsetHashes'] + 1;
|
||||
|
||||
foreach ($offsets as $offset) {
|
||||
$sourceOffsets .= $this->writeLong($offset[1])
|
||||
.$this->writeLong($offset[0] + $sourcesStart);
|
||||
$targetOffsets .= $this->writeLong($offset[3])
|
||||
.$this->writeLong($offset[2] + $sourcesStart + $sourcesSize);
|
||||
}
|
||||
|
||||
$output = implode(array_map(array($this, 'writeLong'), $header))
|
||||
.$sourceOffsets
|
||||
.$targetOffsets
|
||||
.$sources
|
||||
.$targets
|
||||
;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'mo';
|
||||
}
|
||||
|
||||
private function writeLong($str)
|
||||
{
|
||||
return pack('V*', $str);
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* PhpFileDumper generates PHP files from a message catalogue.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*/
|
||||
class PhpFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function format(MessageCatalogue $messages, $domain)
|
||||
{
|
||||
$output = "<?php\n\nreturn ".var_export($messages->all($domain), true).";\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'php';
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* PoFileDumper generates a gettext formatted string representation of a message catalogue.
|
||||
*
|
||||
* @author Stealth35
|
||||
*/
|
||||
class PoFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(MessageCatalogue $messages, $domain = 'messages')
|
||||
{
|
||||
$output = 'msgid ""'."\n";
|
||||
$output .= 'msgstr ""'."\n";
|
||||
$output .= '"Content-Type: text/plain; charset=UTF-8\n"'."\n";
|
||||
$output .= '"Content-Transfer-Encoding: 8bit\n"'."\n";
|
||||
$output .= '"Language: '.$messages->getLocale().'\n"'."\n";
|
||||
$output .= "\n";
|
||||
|
||||
$newLine = false;
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
if ($newLine) {
|
||||
$output .= "\n";
|
||||
} else {
|
||||
$newLine = true;
|
||||
}
|
||||
$output .= sprintf('msgid "%s"'."\n", $this->escape($source));
|
||||
$output .= sprintf('msgstr "%s"', $this->escape($target));
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'po';
|
||||
}
|
||||
|
||||
private function escape($str)
|
||||
{
|
||||
return addcslashes($str, "\0..\37\42\134");
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* QtFileDumper generates ts files from a message catalogue.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class QtFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(MessageCatalogue $messages, $domain)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||
$dom->formatOutput = true;
|
||||
$ts = $dom->appendChild($dom->createElement('TS'));
|
||||
$context = $ts->appendChild($dom->createElement('context'));
|
||||
$context->appendChild($dom->createElement('name', $domain));
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$message = $context->appendChild($dom->createElement('message'));
|
||||
$message->appendChild($dom->createElement('source', $source));
|
||||
$message->appendChild($dom->createElement('translation', $target));
|
||||
}
|
||||
|
||||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'ts';
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* XliffFileDumper generates xliff files from a message catalogue.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*/
|
||||
class XliffFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $defaultLocale;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dump(MessageCatalogue $messages, $options = array())
|
||||
{
|
||||
if (array_key_exists('default_locale', $options)) {
|
||||
$this->defaultLocale = $options['default_locale'];
|
||||
} else {
|
||||
$this->defaultLocale = \Locale::getDefault();
|
||||
}
|
||||
|
||||
parent::dump($messages, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function format(MessageCatalogue $messages, $domain)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||
$dom->formatOutput = true;
|
||||
|
||||
$xliff = $dom->appendChild($dom->createElement('xliff'));
|
||||
$xliff->setAttribute('version', '1.2');
|
||||
$xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2');
|
||||
|
||||
$xliffFile = $xliff->appendChild($dom->createElement('file'));
|
||||
$xliffFile->setAttribute('source-language', str_replace('_', '-', $this->defaultLocale));
|
||||
$xliffFile->setAttribute('target-language', str_replace('_', '-', $messages->getLocale()));
|
||||
$xliffFile->setAttribute('datatype', 'plaintext');
|
||||
$xliffFile->setAttribute('original', 'file.ext');
|
||||
|
||||
$xliffBody = $xliffFile->appendChild($dom->createElement('body'));
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$translation = $dom->createElement('trans-unit');
|
||||
|
||||
$translation->setAttribute('id', md5($source));
|
||||
$translation->setAttribute('resname', $source);
|
||||
|
||||
$s = $translation->appendChild($dom->createElement('source'));
|
||||
$s->appendChild($dom->createTextNode($source));
|
||||
|
||||
// Does the target contain characters requiring a CDATA section?
|
||||
$text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target);
|
||||
|
||||
$t = $translation->appendChild($dom->createElement('target'));
|
||||
$t->appendChild($text);
|
||||
|
||||
$metadata = $messages->getMetadata($source, $domain);
|
||||
if (null !== $metadata && array_key_exists('notes', $metadata) && is_array($metadata['notes'])) {
|
||||
foreach ($metadata['notes'] as $note) {
|
||||
if (!isset($note['content'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$n = $translation->appendChild($dom->createElement('note'));
|
||||
$n->appendChild($dom->createTextNode($note['content']));
|
||||
|
||||
if (isset($note['priority'])) {
|
||||
$n->setAttribute('priority', $note['priority']);
|
||||
}
|
||||
|
||||
if (isset($note['from'])) {
|
||||
$n->setAttribute('from', $note['from']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$xliffBody->appendChild($translation);
|
||||
}
|
||||
|
||||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'xlf';
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* YamlFileDumper generates yaml files from a message catalogue.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*/
|
||||
class YamlFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function format(MessageCatalogue $messages, $domain)
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Yaml\Yaml')) {
|
||||
throw new \LogicException('Dumping translations in the YAML format requires the Symfony Yaml component.');
|
||||
}
|
||||
|
||||
return Yaml::dump($messages->all($domain));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'yml';
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Exception;
|
||||
|
||||
/**
|
||||
* Exception interface for all exceptions thrown by the component.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a resource cannot be loaded.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class InvalidResourceException extends \InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a resource does not exist.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class NotFoundResourceException extends \InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Extractor;
|
||||
|
||||
/**
|
||||
* Base class used by classes that extract translation messages from files.
|
||||
*
|
||||
* @author Marcos D. Sánchez <marcosdsanchez@gmail.com>
|
||||
*/
|
||||
abstract class AbstractFileExtractor
|
||||
{
|
||||
/**
|
||||
* @param string|array $resource files, a file or a directory
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function extractFiles($resource)
|
||||
{
|
||||
if (is_array($resource) || $resource instanceof \Traversable) {
|
||||
$files = array();
|
||||
foreach ($resource as $file) {
|
||||
if ($this->canBeExtracted($file)) {
|
||||
$files[] = $this->toSplFileInfo($file);
|
||||
}
|
||||
}
|
||||
} elseif (is_file($resource)) {
|
||||
$files = $this->canBeExtracted($resource) ? array($this->toSplFileInfo($resource)) : array();
|
||||
} else {
|
||||
$files = $this->extractFromDirectory($resource);
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return \SplFileInfo
|
||||
*/
|
||||
private function toSplFileInfo($file)
|
||||
{
|
||||
return ($file instanceof \SplFileInfo) ? $file : new \SplFileInfo($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isFile($file)
|
||||
{
|
||||
if (!is_file($file)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" file does not exist.', $file));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function canBeExtracted($file);
|
||||
|
||||
/**
|
||||
* @param string|array $resource files, a file or a directory
|
||||
*
|
||||
* @return array files to be extracted
|
||||
*/
|
||||
abstract protected function extractFromDirectory($resource);
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Extractor;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* ChainExtractor extracts translation messages from template files.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*/
|
||||
class ChainExtractor implements ExtractorInterface
|
||||
{
|
||||
/**
|
||||
* The extractors.
|
||||
*
|
||||
* @var ExtractorInterface[]
|
||||
*/
|
||||
private $extractors = array();
|
||||
|
||||
/**
|
||||
* Adds a loader to the translation extractor.
|
||||
*
|
||||
* @param string $format The format of the loader
|
||||
* @param ExtractorInterface $extractor The loader
|
||||
*/
|
||||
public function addExtractor($format, ExtractorInterface $extractor)
|
||||
{
|
||||
$this->extractors[$format] = $extractor;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setPrefix($prefix)
|
||||
{
|
||||
foreach ($this->extractors as $extractor) {
|
||||
$extractor->setPrefix($prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extract($directory, MessageCatalogue $catalogue)
|
||||
{
|
||||
foreach ($this->extractors as $extractor) {
|
||||
$extractor->extract($directory, $catalogue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Extractor;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* Extracts translation messages from a directory or files to the catalogue.
|
||||
* New found messages are injected to the catalogue using the prefix.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*/
|
||||
interface ExtractorInterface
|
||||
{
|
||||
/**
|
||||
* Extracts translation messages from files, a file or a directory to the catalogue.
|
||||
*
|
||||
* @param string|array $resource files, a file or a directory
|
||||
* @param MessageCatalogue $catalogue The catalogue
|
||||
*/
|
||||
public function extract($resource, MessageCatalogue $catalogue);
|
||||
|
||||
/**
|
||||
* Sets the prefix that should be used for new found messages.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
*/
|
||||
public function setPrefix($prefix);
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
/**
|
||||
* IdentityTranslator does not translate anything.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class IdentityTranslator implements TranslatorInterface
|
||||
{
|
||||
private $selector;
|
||||
private $locale;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param MessageSelector|null $selector The message selector for pluralization
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(MessageSelector $selector = null)
|
||||
{
|
||||
$this->selector = $selector ?: new MessageSelector();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setLocale($locale)
|
||||
{
|
||||
$this->locale = $locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getLocale()
|
||||
{
|
||||
return $this->locale ?: \Locale::getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
|
||||
{
|
||||
return strtr((string) $id, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
|
||||
{
|
||||
return strtr($this->selector->choose((string) $id, (int) $number, $locale ?: $this->getLocale()), $parameters);
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
/**
|
||||
* Tests if a given number belongs to a given math interval.
|
||||
*
|
||||
* An interval can represent a finite set of numbers:
|
||||
*
|
||||
* {1,2,3,4}
|
||||
*
|
||||
* An interval can represent numbers between two numbers:
|
||||
*
|
||||
* [1, +Inf]
|
||||
* ]-1,2[
|
||||
*
|
||||
* The left delimiter can be [ (inclusive) or ] (exclusive).
|
||||
* The right delimiter can be [ (exclusive) or ] (inclusive).
|
||||
* Beside numbers, you can use -Inf and +Inf for the infinite.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
|
||||
*/
|
||||
class Interval
|
||||
{
|
||||
/**
|
||||
* Tests if the given number is in the math interval.
|
||||
*
|
||||
* @param int $number A number
|
||||
* @param string $interval An interval
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function test($number, $interval)
|
||||
{
|
||||
$interval = trim($interval);
|
||||
|
||||
if (!preg_match('/^'.self::getIntervalRegexp().'$/x', $interval, $matches)) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s" is not a valid interval.', $interval));
|
||||
}
|
||||
|
||||
if ($matches[1]) {
|
||||
foreach (explode(',', $matches[2]) as $n) {
|
||||
if ($number == $n) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$leftNumber = self::convertNumber($matches['left']);
|
||||
$rightNumber = self::convertNumber($matches['right']);
|
||||
|
||||
return
|
||||
('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
|
||||
&& (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
|
||||
;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Regexp that matches valid intervals.
|
||||
*
|
||||
* @return string A Regexp (without the delimiters)
|
||||
*/
|
||||
public static function getIntervalRegexp()
|
||||
{
|
||||
return <<<EOF
|
||||
({\s*
|
||||
(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
|
||||
\s*})
|
||||
|
||||
|
|
||||
|
||||
(?P<left_delimiter>[\[\]])
|
||||
\s*
|
||||
(?P<left>-Inf|\-?\d+(\.\d+)?)
|
||||
\s*,\s*
|
||||
(?P<right>\+?Inf|\-?\d+(\.\d+)?)
|
||||
\s*
|
||||
(?P<right_delimiter>[\[\]])
|
||||
EOF;
|
||||
}
|
||||
|
||||
private static function convertNumber($number)
|
||||
{
|
||||
if ('-Inf' === $number) {
|
||||
return log(0);
|
||||
} elseif ('+Inf' === $number || 'Inf' === $number) {
|
||||
return -log(0);
|
||||
}
|
||||
|
||||
return (float) $number;
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
/**
|
||||
* ArrayLoader loads translations from a PHP array.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class ArrayLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
$this->flatten($resource);
|
||||
$catalogue = new MessageCatalogue($locale);
|
||||
$catalogue->add($resource, $domain);
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an nested array of translations.
|
||||
*
|
||||
* The scheme used is:
|
||||
* 'key' => array('key2' => array('key3' => 'value'))
|
||||
* Becomes:
|
||||
* 'key.key2.key3' => 'value'
|
||||
*
|
||||
* This function takes an array by reference and will modify it
|
||||
*
|
||||
* @param array &$messages The array that will be flattened
|
||||
* @param array $subnode Current subnode being parsed, used internally for recursive calls
|
||||
* @param string $path Current path being parsed, used internally for recursive calls
|
||||
*/
|
||||
private function flatten(array &$messages, array $subnode = null, $path = null)
|
||||
{
|
||||
if (null === $subnode) {
|
||||
$subnode = &$messages;
|
||||
}
|
||||
foreach ($subnode as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$nodePath = $path ? $path.'.'.$key : $key;
|
||||
$this->flatten($messages, $value, $nodePath);
|
||||
if (null === $path) {
|
||||
unset($messages[$key]);
|
||||
}
|
||||
} elseif (null !== $path) {
|
||||
$messages[$path.'.'.$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* CsvFileLoader loads translations from CSV files.
|
||||
*
|
||||
* @author Saša Stamenković <umpirsky@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class CsvFileLoader extends ArrayLoader
|
||||
{
|
||||
private $delimiter = ';';
|
||||
private $enclosure = '"';
|
||||
private $escape = '\\';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
$messages = array();
|
||||
|
||||
try {
|
||||
$file = new \SplFileObject($resource, 'rb');
|
||||
} catch (\RuntimeException $e) {
|
||||
throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e);
|
||||
}
|
||||
|
||||
$file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY);
|
||||
$file->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
|
||||
|
||||
foreach ($file as $data) {
|
||||
if (substr($data[0], 0, 1) === '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($data[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count($data) == 2) {
|
||||
$messages[$data[0]] = $data[1];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$catalogue = parent::load($messages, $locale, $domain);
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delimiter, enclosure, and escape character for CSV.
|
||||
*
|
||||
* @param string $delimiter delimiter character
|
||||
* @param string $enclosure enclosure character
|
||||
* @param string $escape escape character
|
||||
*/
|
||||
public function setCsvControl($delimiter = ';', $enclosure = '"', $escape = '\\')
|
||||
{
|
||||
$this->delimiter = $delimiter;
|
||||
$this->enclosure = $enclosure;
|
||||
$this->escape = $escape;
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* IcuResFileLoader loads translations from a resource bundle.
|
||||
*
|
||||
* @author stealth35
|
||||
*/
|
||||
class IcuDatFileLoader extends IcuResFileLoader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource.'.dat')) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource.'.dat')) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
try {
|
||||
$rb = new \ResourceBundle($locale, $resource);
|
||||
} catch (\Exception $e) {
|
||||
// HHVM compatibility: constructor throws on invalid resource
|
||||
$rb = null;
|
||||
}
|
||||
|
||||
if (!$rb) {
|
||||
throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
|
||||
} elseif (intl_is_failure($rb->getErrorCode())) {
|
||||
throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
|
||||
}
|
||||
|
||||
$messages = $this->flatten($rb);
|
||||
$catalogue = new MessageCatalogue($locale);
|
||||
$catalogue->add($messages, $domain);
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource.'.dat'));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
|
||||
/**
|
||||
* IcuResFileLoader loads translations from a resource bundle.
|
||||
*
|
||||
* @author stealth35
|
||||
*/
|
||||
class IcuResFileLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!is_dir($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
try {
|
||||
$rb = new \ResourceBundle($locale, $resource);
|
||||
} catch (\Exception $e) {
|
||||
// HHVM compatibility: constructor throws on invalid resource
|
||||
$rb = null;
|
||||
}
|
||||
|
||||
if (!$rb) {
|
||||
throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
|
||||
} elseif (intl_is_failure($rb->getErrorCode())) {
|
||||
throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
|
||||
}
|
||||
|
||||
$messages = $this->flatten($rb);
|
||||
$catalogue = new MessageCatalogue($locale);
|
||||
$catalogue->add($messages, $domain);
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\DirectoryResource')) {
|
||||
$catalogue->addResource(new DirectoryResource($resource));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an ResourceBundle.
|
||||
*
|
||||
* The scheme used is:
|
||||
* key { key2 { key3 { "value" } } }
|
||||
* Becomes:
|
||||
* 'key.key2.key3' => 'value'
|
||||
*
|
||||
* This function takes an array by reference and will modify it
|
||||
*
|
||||
* @param \ResourceBundle $rb the ResourceBundle that will be flattened
|
||||
* @param array $messages used internally for recursive calls
|
||||
* @param string $path current path being parsed, used internally for recursive calls
|
||||
*
|
||||
* @return array the flattened ResourceBundle
|
||||
*/
|
||||
protected function flatten(\ResourceBundle $rb, array &$messages = array(), $path = null)
|
||||
{
|
||||
foreach ($rb as $key => $value) {
|
||||
$nodePath = $path ? $path.'.'.$key : $key;
|
||||
if ($value instanceof \ResourceBundle) {
|
||||
$this->flatten($value, $messages, $nodePath);
|
||||
} else {
|
||||
$messages[$nodePath] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* IniFileLoader loads translations from an ini file.
|
||||
*
|
||||
* @author stealth35
|
||||
*/
|
||||
class IniFileLoader extends ArrayLoader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
$messages = parse_ini_file($resource, true);
|
||||
|
||||
$catalogue = parent::load($messages, $locale, $domain);
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* JsonFileLoader loads translations from an json file.
|
||||
*
|
||||
* @author singles
|
||||
*/
|
||||
class JsonFileLoader extends ArrayLoader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
$messages = array();
|
||||
if ($data = file_get_contents($resource)) {
|
||||
$messages = json_decode($data, true);
|
||||
|
||||
if (0 < $errorCode = json_last_error()) {
|
||||
throw new InvalidResourceException(sprintf('Error parsing JSON - %s', $this->getJSONErrorMessage($errorCode)));
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $messages) {
|
||||
$messages = array();
|
||||
}
|
||||
|
||||
$catalogue = parent::load($messages, $locale, $domain);
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates JSON_ERROR_* constant into meaningful message.
|
||||
*
|
||||
* @param int $errorCode Error code returned by json_last_error() call
|
||||
*
|
||||
* @return string Message string
|
||||
*/
|
||||
private function getJSONErrorMessage($errorCode)
|
||||
{
|
||||
switch ($errorCode) {
|
||||
case JSON_ERROR_DEPTH:
|
||||
return 'Maximum stack depth exceeded';
|
||||
case JSON_ERROR_STATE_MISMATCH:
|
||||
return 'Underflow or the modes mismatch';
|
||||
case JSON_ERROR_CTRL_CHAR:
|
||||
return 'Unexpected control character found';
|
||||
case JSON_ERROR_SYNTAX:
|
||||
return 'Syntax error, malformed JSON';
|
||||
case JSON_ERROR_UTF8:
|
||||
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||
default:
|
||||
return 'Unknown error';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
|
||||
/**
|
||||
* LoaderInterface is the interface implemented by all translation loaders.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface LoaderInterface
|
||||
{
|
||||
/**
|
||||
* Loads a locale.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $locale A locale
|
||||
* @param string $domain The domain
|
||||
*
|
||||
* @return MessageCatalogue A MessageCatalogue instance
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @throws NotFoundResourceException when the resource cannot be found
|
||||
* @throws InvalidResourceException when the resource cannot be loaded
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages');
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
|
||||
*/
|
||||
class MoFileLoader extends ArrayLoader
|
||||
{
|
||||
/**
|
||||
* Magic used for validating the format of a MO file as well as
|
||||
* detecting if the machine used to create that file was little endian.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
const MO_LITTLE_ENDIAN_MAGIC = 0x950412de;
|
||||
|
||||
/**
|
||||
* Magic used for validating the format of a MO file as well as
|
||||
* detecting if the machine used to create that file was big endian.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
const MO_BIG_ENDIAN_MAGIC = 0xde120495;
|
||||
|
||||
/**
|
||||
* The size of the header of a MO file in bytes.
|
||||
*
|
||||
* @var int Number of bytes.
|
||||
*/
|
||||
const MO_HEADER_SIZE = 28;
|
||||
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
$messages = $this->parse($resource);
|
||||
|
||||
// empty file
|
||||
if (null === $messages) {
|
||||
$messages = array();
|
||||
}
|
||||
|
||||
// not an array
|
||||
if (!is_array($messages)) {
|
||||
throw new InvalidResourceException(sprintf('The file "%s" must contain a valid mo file.', $resource));
|
||||
}
|
||||
|
||||
$catalogue = parent::load($messages, $locale, $domain);
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses machine object (MO) format, independent of the machine's endian it
|
||||
* was created on. Both 32bit and 64bit systems are supported.
|
||||
*
|
||||
* @param resource $resource
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws InvalidResourceException If stream content has an invalid format.
|
||||
*/
|
||||
private function parse($resource)
|
||||
{
|
||||
$stream = fopen($resource, 'r');
|
||||
|
||||
$stat = fstat($stream);
|
||||
|
||||
if ($stat['size'] < self::MO_HEADER_SIZE) {
|
||||
throw new InvalidResourceException('MO stream content has an invalid format.');
|
||||
}
|
||||
$magic = unpack('V1', fread($stream, 4));
|
||||
$magic = hexdec(substr(dechex(current($magic)), -8));
|
||||
|
||||
if ($magic == self::MO_LITTLE_ENDIAN_MAGIC) {
|
||||
$isBigEndian = false;
|
||||
} elseif ($magic == self::MO_BIG_ENDIAN_MAGIC) {
|
||||
$isBigEndian = true;
|
||||
} else {
|
||||
throw new InvalidResourceException('MO stream content has an invalid format.');
|
||||
}
|
||||
|
||||
// formatRevision
|
||||
$this->readLong($stream, $isBigEndian);
|
||||
$count = $this->readLong($stream, $isBigEndian);
|
||||
$offsetId = $this->readLong($stream, $isBigEndian);
|
||||
$offsetTranslated = $this->readLong($stream, $isBigEndian);
|
||||
// sizeHashes
|
||||
$this->readLong($stream, $isBigEndian);
|
||||
// offsetHashes
|
||||
$this->readLong($stream, $isBigEndian);
|
||||
|
||||
$messages = array();
|
||||
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$singularId = $pluralId = null;
|
||||
$translated = null;
|
||||
|
||||
fseek($stream, $offsetId + $i * 8);
|
||||
|
||||
$length = $this->readLong($stream, $isBigEndian);
|
||||
$offset = $this->readLong($stream, $isBigEndian);
|
||||
|
||||
if ($length < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fseek($stream, $offset);
|
||||
$singularId = fread($stream, $length);
|
||||
|
||||
if (strpos($singularId, "\000") !== false) {
|
||||
list($singularId, $pluralId) = explode("\000", $singularId);
|
||||
}
|
||||
|
||||
fseek($stream, $offsetTranslated + $i * 8);
|
||||
$length = $this->readLong($stream, $isBigEndian);
|
||||
$offset = $this->readLong($stream, $isBigEndian);
|
||||
|
||||
if ($length < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fseek($stream, $offset);
|
||||
$translated = fread($stream, $length);
|
||||
|
||||
if (strpos($translated, "\000") !== false) {
|
||||
$translated = explode("\000", $translated);
|
||||
}
|
||||
|
||||
$ids = array('singular' => $singularId, 'plural' => $pluralId);
|
||||
$item = compact('ids', 'translated');
|
||||
|
||||
if (is_array($item['translated'])) {
|
||||
$messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
|
||||
if (isset($item['ids']['plural'])) {
|
||||
$plurals = array();
|
||||
foreach ($item['translated'] as $plural => $translated) {
|
||||
$plurals[] = sprintf('{%d} %s', $plural, $translated);
|
||||
}
|
||||
$messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
|
||||
}
|
||||
} elseif (!empty($item['ids']['singular'])) {
|
||||
$messages[$item['ids']['singular']] = stripcslashes($item['translated']);
|
||||
}
|
||||
}
|
||||
|
||||
fclose($stream);
|
||||
|
||||
return array_filter($messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned long from stream respecting endianess.
|
||||
*
|
||||
* @param resource $stream
|
||||
* @param bool $isBigEndian
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function readLong($stream, $isBigEndian)
|
||||
{
|
||||
$result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
|
||||
$result = current($result);
|
||||
|
||||
return (int) substr($result, -8);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* PhpFileLoader loads translations from PHP files returning an array of translations.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class PhpFileLoader extends ArrayLoader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
$messages = require $resource;
|
||||
|
||||
$catalogue = parent::load($messages, $locale, $domain);
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
|
||||
* @copyright Copyright (c) 2012, Clemens Tolboom
|
||||
*/
|
||||
class PoFileLoader extends ArrayLoader
|
||||
{
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
$messages = $this->parse($resource);
|
||||
|
||||
// empty file
|
||||
if (null === $messages) {
|
||||
$messages = array();
|
||||
}
|
||||
|
||||
// not an array
|
||||
if (!is_array($messages)) {
|
||||
throw new InvalidResourceException(sprintf('The file "%s" must contain a valid po file.', $resource));
|
||||
}
|
||||
|
||||
$catalogue = parent::load($messages, $locale, $domain);
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses portable object (PO) format.
|
||||
*
|
||||
* From http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
|
||||
* we should be able to parse files having:
|
||||
*
|
||||
* white-space
|
||||
* # translator-comments
|
||||
* #. extracted-comments
|
||||
* #: reference...
|
||||
* #, flag...
|
||||
* #| msgid previous-untranslated-string
|
||||
* msgid untranslated-string
|
||||
* msgstr translated-string
|
||||
*
|
||||
* extra or different lines are:
|
||||
*
|
||||
* #| msgctxt previous-context
|
||||
* #| msgid previous-untranslated-string
|
||||
* msgctxt context
|
||||
*
|
||||
* #| msgid previous-untranslated-string-singular
|
||||
* #| msgid_plural previous-untranslated-string-plural
|
||||
* msgid untranslated-string-singular
|
||||
* msgid_plural untranslated-string-plural
|
||||
* msgstr[0] translated-string-case-0
|
||||
* ...
|
||||
* msgstr[N] translated-string-case-n
|
||||
*
|
||||
* The definition states:
|
||||
* - white-space and comments are optional.
|
||||
* - msgid "" that an empty singleline defines a header.
|
||||
*
|
||||
* This parser sacrifices some features of the reference implementation the
|
||||
* differences to that implementation are as follows.
|
||||
* - No support for comments spanning multiple lines.
|
||||
* - Translator and extracted comments are treated as being the same type.
|
||||
* - Message IDs are allowed to have other encodings as just US-ASCII.
|
||||
*
|
||||
* Items with an empty id are ignored.
|
||||
*
|
||||
* @param resource $resource
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parse($resource)
|
||||
{
|
||||
$stream = fopen($resource, 'r');
|
||||
|
||||
$defaults = array(
|
||||
'ids' => array(),
|
||||
'translated' => null,
|
||||
);
|
||||
|
||||
$messages = array();
|
||||
$item = $defaults;
|
||||
|
||||
while ($line = fgets($stream)) {
|
||||
$line = trim($line);
|
||||
|
||||
if ($line === '') {
|
||||
// Whitespace indicated current item is done
|
||||
$this->addMessage($messages, $item);
|
||||
$item = $defaults;
|
||||
} elseif (substr($line, 0, 7) === 'msgid "') {
|
||||
// We start a new msg so save previous
|
||||
// TODO: this fails when comments or contexts are added
|
||||
$this->addMessage($messages, $item);
|
||||
$item = $defaults;
|
||||
$item['ids']['singular'] = substr($line, 7, -1);
|
||||
} elseif (substr($line, 0, 8) === 'msgstr "') {
|
||||
$item['translated'] = substr($line, 8, -1);
|
||||
} elseif ($line[0] === '"') {
|
||||
$continues = isset($item['translated']) ? 'translated' : 'ids';
|
||||
|
||||
if (is_array($item[$continues])) {
|
||||
end($item[$continues]);
|
||||
$item[$continues][key($item[$continues])] .= substr($line, 1, -1);
|
||||
} else {
|
||||
$item[$continues] .= substr($line, 1, -1);
|
||||
}
|
||||
} elseif (substr($line, 0, 14) === 'msgid_plural "') {
|
||||
$item['ids']['plural'] = substr($line, 14, -1);
|
||||
} elseif (substr($line, 0, 7) === 'msgstr[') {
|
||||
$size = strpos($line, ']');
|
||||
$item['translated'][(int) substr($line, 7, 1)] = substr($line, $size + 3, -1);
|
||||
}
|
||||
}
|
||||
// save last item
|
||||
$this->addMessage($messages, $item);
|
||||
fclose($stream);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a translation item to the messages.
|
||||
*
|
||||
* A .po file could contain by error missing plural indexes. We need to
|
||||
* fix these before saving them.
|
||||
*
|
||||
* @param array $messages
|
||||
* @param array $item
|
||||
*/
|
||||
private function addMessage(array &$messages, array $item)
|
||||
{
|
||||
if (is_array($item['translated'])) {
|
||||
$messages[stripcslashes($item['ids']['singular'])] = stripcslashes($item['translated'][0]);
|
||||
if (isset($item['ids']['plural'])) {
|
||||
$plurals = $item['translated'];
|
||||
// PO are by definition indexed so sort by index.
|
||||
ksort($plurals);
|
||||
// Make sure every index is filled.
|
||||
end($plurals);
|
||||
$count = key($plurals);
|
||||
// Fill missing spots with '-'.
|
||||
$empties = array_fill(0, $count + 1, '-');
|
||||
$plurals += $empties;
|
||||
ksort($plurals);
|
||||
$messages[stripcslashes($item['ids']['plural'])] = stripcslashes(implode('|', $plurals));
|
||||
}
|
||||
} elseif (!empty($item['ids']['singular'])) {
|
||||
$messages[stripcslashes($item['ids']['singular'])] = stripcslashes($item['translated']);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Config\Util\XmlUtils;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* QtFileLoader loads translations from QT Translations XML files.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class QtFileLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
try {
|
||||
$dom = XmlUtils::loadFile($resource);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new InvalidResourceException(sprintf('Unable to load "%s".', $resource), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$internalErrors = libxml_use_internal_errors(true);
|
||||
libxml_clear_errors();
|
||||
|
||||
$xpath = new \DOMXPath($dom);
|
||||
$nodes = $xpath->evaluate('//TS/context/name[text()="'.$domain.'"]');
|
||||
|
||||
$catalogue = new MessageCatalogue($locale);
|
||||
if ($nodes->length == 1) {
|
||||
$translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message');
|
||||
foreach ($translations as $translation) {
|
||||
$translationValue = (string) $translation->getElementsByTagName('translation')->item(0)->nodeValue;
|
||||
|
||||
if (!empty($translationValue)) {
|
||||
$catalogue->set(
|
||||
(string) $translation->getElementsByTagName('source')->item(0)->nodeValue,
|
||||
$translationValue,
|
||||
$domain
|
||||
);
|
||||
}
|
||||
$translation = $translation->nextSibling;
|
||||
}
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
}
|
||||
}
|
||||
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Config\Util\XmlUtils;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* XliffFileLoader loads translations from XLIFF files.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class XliffFileLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
list($xml, $encoding) = $this->parseFile($resource);
|
||||
$xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
|
||||
|
||||
$catalogue = new MessageCatalogue($locale);
|
||||
foreach ($xml->xpath('//xliff:trans-unit') as $translation) {
|
||||
$attributes = $translation->attributes();
|
||||
|
||||
if (!(isset($attributes['resname']) || isset($translation->source))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;
|
||||
// If the xlf file has another encoding specified, try to convert it because
|
||||
// simple_xml will always return utf-8 encoded values
|
||||
$target = $this->utf8ToCharset((string) (isset($translation->target) ? $translation->target : $source), $encoding);
|
||||
|
||||
$catalogue->set((string) $source, $target, $domain);
|
||||
|
||||
if (isset($translation->note)) {
|
||||
$notes = array();
|
||||
foreach ($translation->note as $xmlNote) {
|
||||
$noteAttributes = $xmlNote->attributes();
|
||||
$note = array('content' => $this->utf8ToCharset((string) $xmlNote, $encoding));
|
||||
if (isset($noteAttributes['priority'])) {
|
||||
$note['priority'] = (int) $noteAttributes['priority'];
|
||||
}
|
||||
|
||||
if (isset($noteAttributes['from'])) {
|
||||
$note['from'] = (string) $noteAttributes['from'];
|
||||
}
|
||||
|
||||
$notes[] = $note;
|
||||
}
|
||||
|
||||
$catalogue->setMetadata((string) $source, array('notes' => $notes), $domain);
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a UTF8 string to the specified encoding.
|
||||
*
|
||||
* @param string $content String to decode
|
||||
* @param string $encoding Target encoding
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function utf8ToCharset($content, $encoding = null)
|
||||
{
|
||||
if ('UTF-8' !== $encoding && !empty($encoding)) {
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding($content, $encoding, 'UTF-8');
|
||||
}
|
||||
|
||||
if (function_exists('iconv')) {
|
||||
return iconv('UTF-8', $encoding, $content);
|
||||
}
|
||||
|
||||
throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and parses the given file into a SimpleXMLElement.
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return \SimpleXMLElement
|
||||
*
|
||||
* @throws InvalidResourceException
|
||||
*/
|
||||
private function parseFile($file)
|
||||
{
|
||||
try {
|
||||
$dom = XmlUtils::loadFile($file);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new InvalidResourceException(sprintf('Unable to load "%s": %s', $file, $e->getMessage()), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$internalErrors = libxml_use_internal_errors(true);
|
||||
|
||||
$location = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
|
||||
$parts = explode('/', $location);
|
||||
if (0 === stripos($location, 'phar://')) {
|
||||
$tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
|
||||
if ($tmpfile) {
|
||||
copy($location, $tmpfile);
|
||||
$parts = explode('/', str_replace('\\', '/', $tmpfile));
|
||||
}
|
||||
}
|
||||
$drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
|
||||
$location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
|
||||
|
||||
$source = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-1.2-strict.xsd');
|
||||
$source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source);
|
||||
|
||||
if (!@$dom->schemaValidateSource($source)) {
|
||||
throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: %s', $file, implode("\n", $this->getXmlErrors($internalErrors))));
|
||||
}
|
||||
|
||||
$dom->normalizeDocument();
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
|
||||
return array(simplexml_import_dom($dom), strtoupper($dom->encoding));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XML errors of the internal XML parser.
|
||||
*
|
||||
* @param bool $internalErrors
|
||||
*
|
||||
* @return array An array of errors
|
||||
*/
|
||||
private function getXmlErrors($internalErrors)
|
||||
{
|
||||
$errors = array();
|
||||
foreach (libxml_get_errors() as $error) {
|
||||
$errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
|
||||
LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
|
||||
$error->code,
|
||||
trim($error->message),
|
||||
$error->file ?: 'n/a',
|
||||
$error->line,
|
||||
$error->column
|
||||
);
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Yaml\Parser as YamlParser;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
|
||||
/**
|
||||
* YamlFileLoader loads translations from Yaml files.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class YamlFileLoader extends ArrayLoader
|
||||
{
|
||||
private $yamlParser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
|
||||
}
|
||||
|
||||
if (!file_exists($resource)) {
|
||||
throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
|
||||
}
|
||||
|
||||
if (!class_exists('Symfony\Component\Yaml\Parser')) {
|
||||
throw new \LogicException('Loading translations from the YAML format requires the Symfony Yaml component.');
|
||||
}
|
||||
|
||||
if (null === $this->yamlParser) {
|
||||
$this->yamlParser = new YamlParser();
|
||||
}
|
||||
|
||||
try {
|
||||
$messages = $this->yamlParser->parse(file_get_contents($resource));
|
||||
} catch (ParseException $e) {
|
||||
throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $resource), 0, $e);
|
||||
}
|
||||
|
||||
// empty file
|
||||
if (null === $messages) {
|
||||
$messages = array();
|
||||
}
|
||||
|
||||
// not an array
|
||||
if (!is_array($messages)) {
|
||||
throw new InvalidResourceException(sprintf('The file "%s" must contain a YAML array.', $resource));
|
||||
}
|
||||
|
||||
$catalogue = parent::load($messages, $locale, $domain);
|
||||
|
||||
if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$catalogue->addResource(new FileResource($resource));
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,309 +0,0 @@
|
|||
<?xml version='1.0'?>
|
||||
<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
|
||||
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns ="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en">
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
<h1>About the XML namespace</h1>
|
||||
|
||||
<div class="bodytext">
|
||||
<p>
|
||||
|
||||
This schema document describes the XML namespace, in a form
|
||||
suitable for import by other schema documents.
|
||||
</p>
|
||||
<p>
|
||||
See <a href="http://www.w3.org/XML/1998/namespace.html">
|
||||
http://www.w3.org/XML/1998/namespace.html</a> and
|
||||
<a href="http://www.w3.org/TR/REC-xml">
|
||||
http://www.w3.org/TR/REC-xml</a> for information
|
||||
about this namespace.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that local names in this namespace are intended to be
|
||||
defined only by the World Wide Web Consortium or its subgroups.
|
||||
The names currently defined in this namespace are listed below.
|
||||
They should not be used with conflicting semantics by any Working
|
||||
Group, specification, or document instance.
|
||||
</p>
|
||||
<p>
|
||||
See further below in this document for more information about <a
|
||||
href="#usage">how to refer to this schema document from your own
|
||||
XSD schema documents</a> and about <a href="#nsversioning">the
|
||||
namespace-versioning policy governing this schema document</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:attribute name="lang">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
|
||||
<h3>lang (as an attribute name)</h3>
|
||||
<p>
|
||||
|
||||
denotes an attribute whose value
|
||||
is a language code for the natural language of the content of
|
||||
any element; its value is inherited. This name is reserved
|
||||
by virtue of its definition in the XML specification.</p>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<h4>Notes</h4>
|
||||
<p>
|
||||
Attempting to install the relevant ISO 2- and 3-letter
|
||||
codes as the enumerated possible values is probably never
|
||||
going to be a realistic possibility.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
|
||||
http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
|
||||
and the IANA language subtag registry at
|
||||
<a href="http://www.iana.org/assignments/language-subtag-registry">
|
||||
http://www.iana.org/assignments/language-subtag-registry</a>
|
||||
for further information.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The union allows for the 'un-declaration' of xml:lang with
|
||||
the empty string.
|
||||
</p>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:union memberTypes="xs:language">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value=""/>
|
||||
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:union>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attribute name="space">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
|
||||
<div>
|
||||
|
||||
<h3>space (as an attribute name)</h3>
|
||||
<p>
|
||||
denotes an attribute whose
|
||||
value is a keyword indicating what whitespace processing
|
||||
discipline is intended for the content of the element; its
|
||||
value is inherited. This name is reserved by virtue of its
|
||||
definition in the XML specification.</p>
|
||||
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
|
||||
<xs:restriction base="xs:NCName">
|
||||
<xs:enumeration value="default"/>
|
||||
<xs:enumeration value="preserve"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
|
||||
<xs:documentation>
|
||||
|
||||
<div>
|
||||
|
||||
<h3>base (as an attribute name)</h3>
|
||||
<p>
|
||||
denotes an attribute whose value
|
||||
provides a URI to be used as the base for interpreting any
|
||||
relative URIs in the scope of the element on which it
|
||||
appears; its value is inherited. This name is reserved
|
||||
by virtue of its definition in the XML Base specification.</p>
|
||||
|
||||
<p>
|
||||
See <a
|
||||
href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
|
||||
for information about this attribute.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attribute name="id" type="xs:ID">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
|
||||
<h3>id (as an attribute name)</h3>
|
||||
<p>
|
||||
|
||||
denotes an attribute whose value
|
||||
should be interpreted as if declared to be of type ID.
|
||||
This name is reserved by virtue of its definition in the
|
||||
xml:id specification.</p>
|
||||
|
||||
<p>
|
||||
See <a
|
||||
href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
|
||||
for information about this attribute.
|
||||
</p>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attributeGroup name="specialAttrs">
|
||||
<xs:attribute ref="xml:base"/>
|
||||
<xs:attribute ref="xml:lang"/>
|
||||
<xs:attribute ref="xml:space"/>
|
||||
<xs:attribute ref="xml:id"/>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:annotation>
|
||||
|
||||
<xs:documentation>
|
||||
<div>
|
||||
|
||||
<h3>Father (in any context at all)</h3>
|
||||
|
||||
<div class="bodytext">
|
||||
<p>
|
||||
denotes Jon Bosak, the chair of
|
||||
the original XML Working Group. This name is reserved by
|
||||
the following decision of the W3C XML Plenary and
|
||||
XML Coordination groups:
|
||||
</p>
|
||||
<blockquote>
|
||||
<p>
|
||||
|
||||
In appreciation for his vision, leadership and
|
||||
dedication the W3C XML Plenary on this 10th day of
|
||||
February, 2000, reserves for Jon Bosak in perpetuity
|
||||
the XML name "xml:Father".
|
||||
</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
|
||||
<div xml:id="usage" id="usage">
|
||||
<h2><a name="usage">About this schema document</a></h2>
|
||||
|
||||
<div class="bodytext">
|
||||
<p>
|
||||
This schema defines attributes and an attribute group suitable
|
||||
for use by schemas wishing to allow <code>xml:base</code>,
|
||||
<code>xml:lang</code>, <code>xml:space</code> or
|
||||
<code>xml:id</code> attributes on elements they define.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To enable this, such a schema must import this schema for
|
||||
the XML namespace, e.g. as follows:
|
||||
</p>
|
||||
<pre>
|
||||
<schema.. .>
|
||||
.. .
|
||||
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
|
||||
</pre>
|
||||
<p>
|
||||
or
|
||||
</p>
|
||||
<pre>
|
||||
|
||||
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||
schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
|
||||
</pre>
|
||||
<p>
|
||||
Subsequently, qualified reference to any of the attributes or the
|
||||
group defined below will have the desired effect, e.g.
|
||||
</p>
|
||||
<pre>
|
||||
<type.. .>
|
||||
.. .
|
||||
<attributeGroup ref="xml:specialAttrs"/>
|
||||
</pre>
|
||||
<p>
|
||||
will define a type which will schema-validate an instance element
|
||||
with any of those attributes.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div id="nsversioning" xml:id="nsversioning">
|
||||
<h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
|
||||
|
||||
<div class="bodytext">
|
||||
<p>
|
||||
In keeping with the XML Schema WG's standard versioning
|
||||
policy, this schema document will persist at
|
||||
<a href="http://www.w3.org/2009/01/xml.xsd">
|
||||
http://www.w3.org/2009/01/xml.xsd</a>.
|
||||
</p>
|
||||
<p>
|
||||
At the date of issue it can also be found at
|
||||
<a href="http://www.w3.org/2001/xml.xsd">
|
||||
http://www.w3.org/2001/xml.xsd</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The schema document at that URI may however change in the future,
|
||||
in order to remain compatible with the latest version of XML
|
||||
Schema itself, or with the XML namespace itself. In other words,
|
||||
if the XML Schema or XML namespaces change, the version of this
|
||||
document at <a href="http://www.w3.org/2001/xml.xsd">
|
||||
http://www.w3.org/2001/xml.xsd
|
||||
</a>
|
||||
will change accordingly; the version at
|
||||
<a href="http://www.w3.org/2009/01/xml.xsd">
|
||||
http://www.w3.org/2009/01/xml.xsd
|
||||
</a>
|
||||
will not change.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
Previous dated (and unchanging) versions of this schema
|
||||
document are at:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="http://www.w3.org/2009/01/xml.xsd">
|
||||
http://www.w3.org/2009/01/xml.xsd</a></li>
|
||||
<li><a href="http://www.w3.org/2007/08/xml.xsd">
|
||||
http://www.w3.org/2007/08/xml.xsd</a></li>
|
||||
<li><a href="http://www.w3.org/2004/10/xml.xsd">
|
||||
|
||||
http://www.w3.org/2004/10/xml.xsd</a></li>
|
||||
<li><a href="http://www.w3.org/2001/03/xml.xsd">
|
||||
http://www.w3.org/2001/03/xml.xsd</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
</xs:schema>
|
|
@ -1,128 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
*/
|
||||
class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
||||
{
|
||||
/**
|
||||
* @var TranslatorInterface|TranslatorBagInterface
|
||||
*/
|
||||
private $translator;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator, LoggerInterface $logger)
|
||||
{
|
||||
if (!$translator instanceof TranslatorBagInterface) {
|
||||
throw new \InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface and TranslatorBagInterface.', get_class($translator)));
|
||||
}
|
||||
|
||||
$this->translator = $translator;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
|
||||
{
|
||||
$trans = $this->translator->trans($id, $parameters, $domain, $locale);
|
||||
$this->log($id, $domain, $locale);
|
||||
|
||||
return $trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
|
||||
{
|
||||
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
|
||||
$this->log($id, $domain, $locale);
|
||||
|
||||
return $trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setLocale($locale)
|
||||
{
|
||||
$this->translator->setLocale($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getLocale()
|
||||
{
|
||||
return $this->translator->getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue($locale = null)
|
||||
{
|
||||
return $this->translator->getCatalogue($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes through all unknown calls onto the translator object.
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return call_user_func_array(array($this->translator, $method), $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs for missing translations.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string|null $domain
|
||||
* @param string|null $locale
|
||||
*/
|
||||
private function log($id, $domain, $locale)
|
||||
{
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
}
|
||||
|
||||
$id = (string) $id;
|
||||
$catalogue = $this->translator->getCatalogue($locale);
|
||||
if ($catalogue->defines($id, $domain)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($catalogue->has($id, $domain)) {
|
||||
$this->logger->debug('Translation use fallback catalogue.', array('id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()));
|
||||
} else {
|
||||
$this->logger->warning('Translation not found.', array('id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,300 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* MessageCatalogue.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface
|
||||
{
|
||||
private $messages = array();
|
||||
private $metadata = array();
|
||||
private $resources = array();
|
||||
private $locale;
|
||||
private $fallbackCatalogue;
|
||||
private $parent;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $locale The locale
|
||||
* @param array $messages An array of messages classified by domain
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($locale, array $messages = array())
|
||||
{
|
||||
$this->locale = $locale;
|
||||
$this->messages = $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getLocale()
|
||||
{
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getDomains()
|
||||
{
|
||||
return array_keys($this->messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function all($domain = null)
|
||||
{
|
||||
if (null === $domain) {
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
return isset($this->messages[$domain]) ? $this->messages[$domain] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function set($id, $translation, $domain = 'messages')
|
||||
{
|
||||
$this->add(array($id => $translation), $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function has($id, $domain = 'messages')
|
||||
{
|
||||
if (isset($this->messages[$domain][$id])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (null !== $this->fallbackCatalogue) {
|
||||
return $this->fallbackCatalogue->has($id, $domain);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defines($id, $domain = 'messages')
|
||||
{
|
||||
return isset($this->messages[$domain][$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function get($id, $domain = 'messages')
|
||||
{
|
||||
if (isset($this->messages[$domain][$id])) {
|
||||
return $this->messages[$domain][$id];
|
||||
}
|
||||
|
||||
if (null !== $this->fallbackCatalogue) {
|
||||
return $this->fallbackCatalogue->get($id, $domain);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function replace($messages, $domain = 'messages')
|
||||
{
|
||||
$this->messages[$domain] = array();
|
||||
|
||||
$this->add($messages, $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function add($messages, $domain = 'messages')
|
||||
{
|
||||
if (!isset($this->messages[$domain])) {
|
||||
$this->messages[$domain] = $messages;
|
||||
} else {
|
||||
$this->messages[$domain] = array_replace($this->messages[$domain], $messages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addCatalogue(MessageCatalogueInterface $catalogue)
|
||||
{
|
||||
if ($catalogue->getLocale() !== $this->locale) {
|
||||
throw new \LogicException(sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s"', $catalogue->getLocale(), $this->locale));
|
||||
}
|
||||
|
||||
foreach ($catalogue->all() as $domain => $messages) {
|
||||
$this->add($messages, $domain);
|
||||
}
|
||||
|
||||
foreach ($catalogue->getResources() as $resource) {
|
||||
$this->addResource($resource);
|
||||
}
|
||||
|
||||
if ($catalogue instanceof MetadataAwareInterface) {
|
||||
$metadata = $catalogue->getMetadata('', '');
|
||||
$this->addMetadata($metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addFallbackCatalogue(MessageCatalogueInterface $catalogue)
|
||||
{
|
||||
// detect circular references
|
||||
$c = $catalogue;
|
||||
while ($c = $c->getFallbackCatalogue()) {
|
||||
if ($c->getLocale() === $this->getLocale()) {
|
||||
throw new \LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
|
||||
}
|
||||
}
|
||||
|
||||
$c = $this;
|
||||
do {
|
||||
if ($c->getLocale() === $catalogue->getLocale()) {
|
||||
throw new \LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
|
||||
}
|
||||
} while ($c = $c->parent);
|
||||
|
||||
$catalogue->parent = $this;
|
||||
$this->fallbackCatalogue = $catalogue;
|
||||
|
||||
foreach ($catalogue->getResources() as $resource) {
|
||||
$this->addResource($resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFallbackCatalogue()
|
||||
{
|
||||
return $this->fallbackCatalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getResources()
|
||||
{
|
||||
return array_values($this->resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addResource(ResourceInterface $resource)
|
||||
{
|
||||
$this->resources[$resource->__toString()] = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata($key = '', $domain = 'messages')
|
||||
{
|
||||
if ('' == $domain) {
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
if (isset($this->metadata[$domain])) {
|
||||
if ('' == $key) {
|
||||
return $this->metadata[$domain];
|
||||
}
|
||||
|
||||
if (isset($this->metadata[$domain][$key])) {
|
||||
return $this->metadata[$domain][$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMetadata($key, $value, $domain = 'messages')
|
||||
{
|
||||
$this->metadata[$domain][$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteMetadata($key = '', $domain = 'messages')
|
||||
{
|
||||
if ('' == $domain) {
|
||||
$this->metadata = array();
|
||||
} elseif ('' == $key) {
|
||||
unset($this->metadata[$domain]);
|
||||
} else {
|
||||
unset($this->metadata[$domain][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds current values with the new values.
|
||||
*
|
||||
* @param array $values Values to add
|
||||
*/
|
||||
private function addMetadata(array $values)
|
||||
{
|
||||
foreach ($values as $domain => $keys) {
|
||||
foreach ($keys as $key => $value) {
|
||||
$this->setMetadata($key, $value, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* MessageCatalogueInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface MessageCatalogueInterface
|
||||
{
|
||||
/**
|
||||
* Gets the catalogue locale.
|
||||
*
|
||||
* @return string The locale
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getLocale();
|
||||
|
||||
/**
|
||||
* Gets the domains.
|
||||
*
|
||||
* @return array An array of domains
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getDomains();
|
||||
|
||||
/**
|
||||
* Gets the messages within a given domain.
|
||||
*
|
||||
* If $domain is null, it returns all messages.
|
||||
*
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return array An array of messages
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function all($domain = null);
|
||||
|
||||
/**
|
||||
* Sets a message translation.
|
||||
*
|
||||
* @param string $id The message id
|
||||
* @param string $translation The messages translation
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function set($id, $translation, $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Checks if a message has a translation.
|
||||
*
|
||||
* @param string $id The message id
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return bool true if the message has a translation, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function has($id, $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Checks if a message has a translation (it does not take into account the fallback mechanism).
|
||||
*
|
||||
* @param string $id The message id
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return bool true if the message has a translation, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function defines($id, $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Gets a message translation.
|
||||
*
|
||||
* @param string $id The message id
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return string The message translation
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function get($id, $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Sets translations for a given domain.
|
||||
*
|
||||
* @param array $messages An array of translations
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function replace($messages, $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Adds translations for a given domain.
|
||||
*
|
||||
* @param array $messages An array of translations
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function add($messages, $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Merges translations from the given Catalogue into the current one.
|
||||
*
|
||||
* The two catalogues must have the same locale.
|
||||
*
|
||||
* @param MessageCatalogueInterface $catalogue A MessageCatalogueInterface instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addCatalogue(MessageCatalogueInterface $catalogue);
|
||||
|
||||
/**
|
||||
* Merges translations from the given Catalogue into the current one
|
||||
* only when the translation does not exist.
|
||||
*
|
||||
* This is used to provide default translations when they do not exist for the current locale.
|
||||
*
|
||||
* @param MessageCatalogueInterface $catalogue A MessageCatalogueInterface instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addFallbackCatalogue(MessageCatalogueInterface $catalogue);
|
||||
|
||||
/**
|
||||
* Gets the fallback catalogue.
|
||||
*
|
||||
* @return MessageCatalogueInterface|null A MessageCatalogueInterface instance or null when no fallback has been set
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFallbackCatalogue();
|
||||
|
||||
/**
|
||||
* Returns an array of resources loaded to build this collection.
|
||||
*
|
||||
* @return ResourceInterface[] An array of resources
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getResources();
|
||||
|
||||
/**
|
||||
* Adds a resource for this collection.
|
||||
*
|
||||
* @param ResourceInterface $resource A resource instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addResource(ResourceInterface $resource);
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
/**
|
||||
* MessageSelector.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class MessageSelector
|
||||
{
|
||||
/**
|
||||
* Given a message with different plural translations separated by a
|
||||
* pipe (|), this method returns the correct portion of the message based
|
||||
* on the given number, locale and the pluralization rules in the message
|
||||
* itself.
|
||||
*
|
||||
* The message supports two different types of pluralization rules:
|
||||
*
|
||||
* interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples
|
||||
* indexed: There is one apple|There are %count% apples
|
||||
*
|
||||
* The indexed solution can also contain labels (e.g. one: There is one apple).
|
||||
* This is purely for making the translations more clear - it does not
|
||||
* affect the functionality.
|
||||
*
|
||||
* The two methods can also be mixed:
|
||||
* {0} There are no apples|one: There is one apple|more: There are %count% apples
|
||||
*
|
||||
* @param string $message The message being translated
|
||||
* @param int $number The number of items represented for the message
|
||||
* @param string $locale The locale to use for choosing
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function choose($message, $number, $locale)
|
||||
{
|
||||
$parts = explode('|', $message);
|
||||
$explicitRules = array();
|
||||
$standardRules = array();
|
||||
foreach ($parts as $part) {
|
||||
$part = trim($part);
|
||||
|
||||
if (preg_match('/^(?P<interval>'.Interval::getIntervalRegexp().')\s*(?P<message>.*?)$/xs', $part, $matches)) {
|
||||
$explicitRules[$matches['interval']] = $matches['message'];
|
||||
} elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
|
||||
$standardRules[] = $matches[1];
|
||||
} else {
|
||||
$standardRules[] = $part;
|
||||
}
|
||||
}
|
||||
|
||||
// try to match an explicit rule, then fallback to the standard ones
|
||||
foreach ($explicitRules as $interval => $m) {
|
||||
if (Interval::test($number, $interval)) {
|
||||
return $m;
|
||||
}
|
||||
}
|
||||
|
||||
$position = PluralizationRules::get($number, $locale);
|
||||
|
||||
if (!isset($standardRules[$position])) {
|
||||
// when there's exactly one rule given, and that rule is a standard
|
||||
// rule, use this rule
|
||||
if (1 === count($parts) && isset($standardRules[0])) {
|
||||
return $standardRules[0];
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $message, $locale, $number));
|
||||
}
|
||||
|
||||
return $standardRules[$position];
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
/**
|
||||
* MetadataAwareInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface MetadataAwareInterface
|
||||
{
|
||||
/**
|
||||
* Gets metadata for the given domain and key.
|
||||
*
|
||||
* Passing an empty domain will return an array with all metadata indexed by
|
||||
* domain and then by key. Passing an empty key will return an array with all
|
||||
* metadata for the given domain.
|
||||
*
|
||||
* @param string $key The key
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return mixed The value that was set or an array with the domains/keys or null
|
||||
*/
|
||||
public function getMetadata($key = '', $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Adds metadata to a message domain.
|
||||
*
|
||||
* @param string $key The key
|
||||
* @param mixed $value The value
|
||||
* @param string $domain The domain name
|
||||
*/
|
||||
public function setMetadata($key, $value, $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Deletes metadata for the given key and domain.
|
||||
*
|
||||
* Passing an empty domain will delete all metadata. Passing an empty key will
|
||||
* delete all metadata for the given domain.
|
||||
*
|
||||
* @param string $key The key
|
||||
* @param string $domain The domain name
|
||||
*/
|
||||
public function deleteMetadata($key = '', $domain = 'messages');
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
/**
|
||||
* Returns the plural rules for a given locale.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class PluralizationRules
|
||||
{
|
||||
private static $rules = array();
|
||||
|
||||
/**
|
||||
* Returns the plural position to use for the given locale and number.
|
||||
*
|
||||
* @param int $number The number
|
||||
* @param string $locale The locale
|
||||
*
|
||||
* @return int The plural position
|
||||
*/
|
||||
public static function get($number, $locale)
|
||||
{
|
||||
if ('pt_BR' === $locale) {
|
||||
// temporary set a locale for brazilian
|
||||
$locale = 'xbr';
|
||||
}
|
||||
|
||||
if (strlen($locale) > 3) {
|
||||
$locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
|
||||
}
|
||||
|
||||
if (isset(self::$rules[$locale])) {
|
||||
$return = call_user_func(self::$rules[$locale], $number);
|
||||
|
||||
if (!is_int($return) || $return < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The plural rules are derived from code of the Zend Framework (2010-09-25),
|
||||
* which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
|
||||
* Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
*/
|
||||
switch ($locale) {
|
||||
case 'az':
|
||||
case 'bo':
|
||||
case 'dz':
|
||||
case 'id':
|
||||
case 'ja':
|
||||
case 'jv':
|
||||
case 'ka':
|
||||
case 'km':
|
||||
case 'kn':
|
||||
case 'ko':
|
||||
case 'ms':
|
||||
case 'th':
|
||||
case 'tr':
|
||||
case 'vi':
|
||||
case 'zh':
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'af':
|
||||
case 'bn':
|
||||
case 'bg':
|
||||
case 'ca':
|
||||
case 'da':
|
||||
case 'de':
|
||||
case 'el':
|
||||
case 'en':
|
||||
case 'eo':
|
||||
case 'es':
|
||||
case 'et':
|
||||
case 'eu':
|
||||
case 'fa':
|
||||
case 'fi':
|
||||
case 'fo':
|
||||
case 'fur':
|
||||
case 'fy':
|
||||
case 'gl':
|
||||
case 'gu':
|
||||
case 'ha':
|
||||
case 'he':
|
||||
case 'hu':
|
||||
case 'is':
|
||||
case 'it':
|
||||
case 'ku':
|
||||
case 'lb':
|
||||
case 'ml':
|
||||
case 'mn':
|
||||
case 'mr':
|
||||
case 'nah':
|
||||
case 'nb':
|
||||
case 'ne':
|
||||
case 'nl':
|
||||
case 'nn':
|
||||
case 'no':
|
||||
case 'om':
|
||||
case 'or':
|
||||
case 'pa':
|
||||
case 'pap':
|
||||
case 'ps':
|
||||
case 'pt':
|
||||
case 'so':
|
||||
case 'sq':
|
||||
case 'sv':
|
||||
case 'sw':
|
||||
case 'ta':
|
||||
case 'te':
|
||||
case 'tk':
|
||||
case 'ur':
|
||||
case 'zu':
|
||||
return ($number == 1) ? 0 : 1;
|
||||
|
||||
case 'am':
|
||||
case 'bh':
|
||||
case 'fil':
|
||||
case 'fr':
|
||||
case 'gun':
|
||||
case 'hi':
|
||||
case 'ln':
|
||||
case 'mg':
|
||||
case 'nso':
|
||||
case 'xbr':
|
||||
case 'ti':
|
||||
case 'wa':
|
||||
return (($number == 0) || ($number == 1)) ? 0 : 1;
|
||||
|
||||
case 'be':
|
||||
case 'bs':
|
||||
case 'hr':
|
||||
case 'ru':
|
||||
case 'sr':
|
||||
case 'uk':
|
||||
return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
|
||||
|
||||
case 'cs':
|
||||
case 'sk':
|
||||
return ($number == 1) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2);
|
||||
|
||||
case 'ga':
|
||||
return ($number == 1) ? 0 : (($number == 2) ? 1 : 2);
|
||||
|
||||
case 'lt':
|
||||
return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
|
||||
|
||||
case 'sl':
|
||||
return ($number % 100 == 1) ? 0 : (($number % 100 == 2) ? 1 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 2 : 3));
|
||||
|
||||
case 'mk':
|
||||
return ($number % 10 == 1) ? 0 : 1;
|
||||
|
||||
case 'mt':
|
||||
return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3));
|
||||
|
||||
case 'lv':
|
||||
return ($number == 0) ? 0 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2);
|
||||
|
||||
case 'pl':
|
||||
return ($number == 1) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2);
|
||||
|
||||
case 'cy':
|
||||
return ($number == 1) ? 0 : (($number == 2) ? 1 : ((($number == 8) || ($number == 11)) ? 2 : 3));
|
||||
|
||||
case 'ro':
|
||||
return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2);
|
||||
|
||||
case 'ar':
|
||||
return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5))));
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default plural rule for a given locale.
|
||||
*
|
||||
* @param string $rule A PHP callable
|
||||
* @param string $locale The locale
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public static function set($rule, $locale)
|
||||
{
|
||||
if ('pt_BR' === $locale) {
|
||||
// temporary set a locale for brazilian
|
||||
$locale = 'xbr';
|
||||
}
|
||||
|
||||
if (strlen($locale) > 3) {
|
||||
$locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
|
||||
}
|
||||
|
||||
if (!is_callable($rule)) {
|
||||
throw new \LogicException('The given rule can not be called');
|
||||
}
|
||||
|
||||
self::$rules[$locale] = $rule;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
Translation Component
|
||||
=====================
|
||||
|
||||
Translation provides tools for loading translation files and generating
|
||||
translated strings from these including support for pluralization.
|
||||
|
||||
```php
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Component\Translation\MessageSelector;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
|
||||
$translator = new Translator('fr_FR', new MessageSelector());
|
||||
$translator->setFallbackLocales(array('fr'));
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array(
|
||||
'Hello World!' => 'Bonjour',
|
||||
), 'fr');
|
||||
|
||||
echo $translator->trans('Hello World!')."\n";
|
||||
```
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
Silex integration:
|
||||
|
||||
https://github.com/silexphp/Silex/blob/master/src/Silex/Provider/TranslationServiceProvider.php
|
||||
|
||||
Documentation:
|
||||
|
||||
https://symfony.com/doc/2.7/book/translation.html
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
$ cd path/to/Symfony/Component/Translation/
|
||||
$ composer install
|
||||
$ phpunit
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Catalogue;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
abstract class AbstractOperationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testGetEmptyDomains()
|
||||
{
|
||||
$this->assertEquals(
|
||||
array(),
|
||||
$this->createOperation(
|
||||
new MessageCatalogue('en'),
|
||||
new MessageCatalogue('en')
|
||||
)->getDomains()
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetMergedDomains()
|
||||
{
|
||||
$this->assertEquals(
|
||||
array('a', 'b', 'c'),
|
||||
$this->createOperation(
|
||||
new MessageCatalogue('en', array('a' => array(), 'b' => array())),
|
||||
new MessageCatalogue('en', array('b' => array(), 'c' => array()))
|
||||
)->getDomains()
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetMessagesFromUnknownDomain()
|
||||
{
|
||||
$this->setExpectedException('InvalidArgumentException');
|
||||
$this->createOperation(
|
||||
new MessageCatalogue('en'),
|
||||
new MessageCatalogue('en')
|
||||
)->getMessages('domain');
|
||||
}
|
||||
|
||||
public function testGetEmptyMessages()
|
||||
{
|
||||
$this->assertEquals(
|
||||
array(),
|
||||
$this->createOperation(
|
||||
new MessageCatalogue('en', array('a' => array())),
|
||||
new MessageCatalogue('en')
|
||||
)->getMessages('a')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetEmptyResult()
|
||||
{
|
||||
$this->assertEquals(
|
||||
new MessageCatalogue('en'),
|
||||
$this->createOperation(
|
||||
new MessageCatalogue('en'),
|
||||
new MessageCatalogue('en')
|
||||
)->getResult()
|
||||
);
|
||||
}
|
||||
|
||||
abstract protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target);
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Catalogue;
|
||||
|
||||
use Symfony\Component\Translation\Catalogue\DiffOperation;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
class DiffOperationTest extends AbstractOperationTest
|
||||
{
|
||||
public function testGetMessagesFromSingleDomain()
|
||||
{
|
||||
$operation = $this->createOperation(
|
||||
new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
|
||||
new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('a' => 'old_a', 'c' => 'new_c'),
|
||||
$operation->getMessages('messages')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('c' => 'new_c'),
|
||||
$operation->getNewMessages('messages')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('b' => 'old_b'),
|
||||
$operation->getObsoleteMessages('messages')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetResultFromSingleDomain()
|
||||
{
|
||||
$this->assertEquals(
|
||||
new MessageCatalogue('en', array(
|
||||
'messages' => array('a' => 'old_a', 'c' => 'new_c'),
|
||||
)),
|
||||
$this->createOperation(
|
||||
new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
|
||||
new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
|
||||
)->getResult()
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetResultWithMetadata()
|
||||
{
|
||||
$leftCatalogue = new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b')));
|
||||
$leftCatalogue->setMetadata('a', 'foo', 'messages');
|
||||
$leftCatalogue->setMetadata('b', 'bar', 'messages');
|
||||
$rightCatalogue = new MessageCatalogue('en', array('messages' => array('b' => 'new_b', 'c' => 'new_c')));
|
||||
$rightCatalogue->setMetadata('b', 'baz', 'messages');
|
||||
$rightCatalogue->setMetadata('c', 'qux', 'messages');
|
||||
|
||||
$diffCatalogue = new MessageCatalogue('en', array('messages' => array('b' => 'old_b', 'c' => 'new_c')));
|
||||
$diffCatalogue->setMetadata('b', 'bar', 'messages');
|
||||
$diffCatalogue->setMetadata('c', 'qux', 'messages');
|
||||
|
||||
$this->assertEquals(
|
||||
$diffCatalogue,
|
||||
$this->createOperation(
|
||||
$leftCatalogue,
|
||||
$rightCatalogue
|
||||
)->getResult()
|
||||
);
|
||||
}
|
||||
|
||||
protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
|
||||
{
|
||||
return new DiffOperation($source, $target);
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Catalogue;
|
||||
|
||||
use Symfony\Component\Translation\Catalogue\MergeOperation;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
class MergeOperationTest extends AbstractOperationTest
|
||||
{
|
||||
public function testGetMessagesFromSingleDomain()
|
||||
{
|
||||
$operation = $this->createOperation(
|
||||
new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
|
||||
new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'),
|
||||
$operation->getMessages('messages')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('c' => 'new_c'),
|
||||
$operation->getNewMessages('messages')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(),
|
||||
$operation->getObsoleteMessages('messages')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetResultFromSingleDomain()
|
||||
{
|
||||
$this->assertEquals(
|
||||
new MessageCatalogue('en', array(
|
||||
'messages' => array('a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'),
|
||||
)),
|
||||
$this->createOperation(
|
||||
new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b'))),
|
||||
new MessageCatalogue('en', array('messages' => array('a' => 'new_a', 'c' => 'new_c')))
|
||||
)->getResult()
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetResultWithMetadata()
|
||||
{
|
||||
$leftCatalogue = new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b')));
|
||||
$leftCatalogue->setMetadata('a', 'foo', 'messages');
|
||||
$leftCatalogue->setMetadata('b', 'bar', 'messages');
|
||||
$rightCatalogue = new MessageCatalogue('en', array('messages' => array('b' => 'new_b', 'c' => 'new_c')));
|
||||
$rightCatalogue->setMetadata('b', 'baz', 'messages');
|
||||
$rightCatalogue->setMetadata('c', 'qux', 'messages');
|
||||
|
||||
$mergedCatalogue = new MessageCatalogue('en', array('messages' => array('a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c')));
|
||||
$mergedCatalogue->setMetadata('a', 'foo', 'messages');
|
||||
$mergedCatalogue->setMetadata('b', 'bar', 'messages');
|
||||
$mergedCatalogue->setMetadata('c', 'qux', 'messages');
|
||||
|
||||
$this->assertEquals(
|
||||
$mergedCatalogue,
|
||||
$this->createOperation(
|
||||
$leftCatalogue,
|
||||
$rightCatalogue
|
||||
)->getResult()
|
||||
);
|
||||
}
|
||||
|
||||
protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
|
||||
{
|
||||
return new MergeOperation($source, $target);
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\DataCollector;
|
||||
|
||||
use Symfony\Component\Translation\DataCollectorTranslator;
|
||||
use Symfony\Component\Translation\DataCollector\TranslationDataCollector;
|
||||
|
||||
class TranslationDataCollectorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\HttpKernel\DataCollector\DataCollector')) {
|
||||
$this->markTestSkipped('The "DataCollector" is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public function testCollectEmptyMessages()
|
||||
{
|
||||
$translator = $this->getTranslator();
|
||||
$translator->expects($this->any())->method('getCollectedMessages')->will($this->returnValue(array()));
|
||||
|
||||
$dataCollector = new TranslationDataCollector($translator);
|
||||
$dataCollector->lateCollect();
|
||||
|
||||
$this->assertEquals(0, $dataCollector->getCountMissings());
|
||||
$this->assertEquals(0, $dataCollector->getCountFallbacks());
|
||||
$this->assertEquals(0, $dataCollector->getCountDefines());
|
||||
$this->assertEquals(array(), $dataCollector->getMessages());
|
||||
}
|
||||
|
||||
public function testCollect()
|
||||
{
|
||||
$collectedMessages = array(
|
||||
array(
|
||||
'id' => 'foo',
|
||||
'translation' => 'foo (en)',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_DEFINED,
|
||||
),
|
||||
array(
|
||||
'id' => 'bar',
|
||||
'translation' => 'bar (fr)',
|
||||
'locale' => 'fr',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
),
|
||||
array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
),
|
||||
array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
),
|
||||
);
|
||||
$expectedMessages = array(
|
||||
array(
|
||||
'id' => 'foo',
|
||||
'translation' => 'foo (en)',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_DEFINED,
|
||||
'count' => 1,
|
||||
),
|
||||
array(
|
||||
'id' => 'bar',
|
||||
'translation' => 'bar (fr)',
|
||||
'locale' => 'fr',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
'count' => 1,
|
||||
),
|
||||
array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
'count' => 2,
|
||||
),
|
||||
);
|
||||
|
||||
$translator = $this->getTranslator();
|
||||
$translator->expects($this->any())->method('getCollectedMessages')->will($this->returnValue($collectedMessages));
|
||||
|
||||
$dataCollector = new TranslationDataCollector($translator);
|
||||
$dataCollector->lateCollect();
|
||||
|
||||
$this->assertEquals(1, $dataCollector->getCountMissings());
|
||||
$this->assertEquals(1, $dataCollector->getCountFallbacks());
|
||||
$this->assertEquals(1, $dataCollector->getCountDefines());
|
||||
$this->assertEquals($expectedMessages, array_values($dataCollector->getMessages()));
|
||||
}
|
||||
|
||||
private function getTranslator()
|
||||
{
|
||||
$translator = $this
|
||||
->getMockBuilder('Symfony\Component\Translation\DataCollectorTranslator')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
;
|
||||
|
||||
return $translator;
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Component\Translation\DataCollectorTranslator;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
|
||||
class DataCollectorTranslatorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\HttpKernel\DataCollector\DataCollector')) {
|
||||
$this->markTestSkipped('The "DataCollector" is not available');
|
||||
}
|
||||
}
|
||||
public function testCollectMessages()
|
||||
{
|
||||
$collector = $this->createCollector();
|
||||
$collector->setFallbackLocales(array('fr', 'ru'));
|
||||
|
||||
$collector->trans('foo');
|
||||
$collector->trans('bar');
|
||||
$collector->transChoice('choice', 0);
|
||||
$collector->trans('bar_ru');
|
||||
|
||||
$expectedMessages = array();
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'foo',
|
||||
'translation' => 'foo (en)',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_DEFINED,
|
||||
);
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'bar',
|
||||
'translation' => 'bar (fr)',
|
||||
'locale' => 'fr',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
);
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
);
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'bar_ru',
|
||||
'translation' => 'bar (ru)',
|
||||
'locale' => 'ru',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
);
|
||||
|
||||
$this->assertEquals($expectedMessages, $collector->getCollectedMessages());
|
||||
}
|
||||
|
||||
private function createCollector()
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (en)'), 'en');
|
||||
$translator->addResource('array', array('bar' => 'bar (fr)'), 'fr');
|
||||
$translator->addResource('array', array('bar_ru' => 'bar (ru)'), 'ru');
|
||||
|
||||
$collector = new DataCollectorTranslator($translator);
|
||||
|
||||
return $collector;
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\CsvFileDumper;
|
||||
|
||||
class CsvFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar', 'bar' => 'foo
|
||||
foo', 'foo;foo' => 'bar'));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new CsvFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/valid.csv'), file_get_contents($tempDir.'/messages.en.csv'));
|
||||
|
||||
unlink($tempDir.'/messages.en.csv');
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\FileDumper;
|
||||
|
||||
class FileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDumpBackupsFileIfExisting()
|
||||
{
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$file = $tempDir.'/messages.en.concrete';
|
||||
$backupFile = $file.'~';
|
||||
|
||||
@touch($file);
|
||||
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new ConcreteFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertTrue(file_exists($backupFile));
|
||||
|
||||
@unlink($file);
|
||||
@unlink($backupFile);
|
||||
}
|
||||
|
||||
public function testDumpCreatesNestedDirectoriesAndFile()
|
||||
{
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$translationsDir = $tempDir.'/test/translations';
|
||||
$file = $translationsDir.'/messages.en.concrete';
|
||||
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new ConcreteFileDumper();
|
||||
$dumper->setRelativePathTemplate('test/translations/%domain%.%locale%.%extension%');
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertTrue(file_exists($file));
|
||||
|
||||
@unlink($file);
|
||||
@rmdir($translationsDir);
|
||||
}
|
||||
}
|
||||
|
||||
class ConcreteFileDumper extends FileDumper
|
||||
{
|
||||
protected function format(MessageCatalogue $messages, $domain)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'concrete';
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\IcuResFileDumper;
|
||||
|
||||
class IcuResFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
if (!function_exists('mb_convert_encoding')) {
|
||||
$this->markTestSkipped('This test requires mbstring to work.');
|
||||
}
|
||||
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$tempDir = sys_get_temp_dir().'/IcuResFileDumperTest';
|
||||
$dumper = new IcuResFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resourcebundle/res/en.res'), file_get_contents($tempDir.'/messages/en.res'));
|
||||
|
||||
@unlink($tempDir.'/messages/en.res');
|
||||
@rmdir($tempDir.'/messages');
|
||||
@rmdir($tempDir);
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\IniFileDumper;
|
||||
|
||||
class IniFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new IniFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.ini'), file_get_contents($tempDir.'/messages.en.ini'));
|
||||
|
||||
unlink($tempDir.'/messages.en.ini');
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\JsonFileDumper;
|
||||
|
||||
class JsonFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
if (PHP_VERSION_ID < 50400) {
|
||||
$this->markTestIncomplete('PHP below 5.4 doesn\'t support JSON pretty printing');
|
||||
}
|
||||
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new JsonFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.json'), file_get_contents($tempDir.'/messages.en.json'));
|
||||
|
||||
unlink($tempDir.'/messages.en.json');
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\MoFileDumper;
|
||||
|
||||
class MoFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new MoFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.mo'), file_get_contents($tempDir.'/messages.en.mo'));
|
||||
|
||||
unlink($tempDir.'/messages.en.mo');
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\PhpFileDumper;
|
||||
|
||||
class PhpFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new PhpFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.php'), file_get_contents($tempDir.'/messages.en.php'));
|
||||
|
||||
unlink($tempDir.'/messages.en.php');
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\PoFileDumper;
|
||||
|
||||
class PoFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new PoFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.po'), file_get_contents($tempDir.'/messages.en.po'));
|
||||
|
||||
unlink($tempDir.'/messages.en.po');
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\QtFileDumper;
|
||||
|
||||
class QtFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'), 'resources');
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new QtFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.ts'), file_get_contents($tempDir.'/resources.en.ts'));
|
||||
|
||||
unlink($tempDir.'/resources.en.ts');
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\XliffFileDumper;
|
||||
|
||||
class XliffFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en_US');
|
||||
$catalogue->add(array(
|
||||
'foo' => 'bar',
|
||||
'key' => '',
|
||||
'key.with.cdata' => '<source> & <target>',
|
||||
));
|
||||
$catalogue->setMetadata('foo', array('notes' => array(array('priority' => 1, 'from' => 'bar', 'content' => 'baz'))));
|
||||
$catalogue->setMetadata('key', array('notes' => array(array('content' => 'baz'), array('content' => 'qux'))));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new XliffFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir, 'default_locale' => 'fr_FR'));
|
||||
|
||||
$this->assertEquals(
|
||||
file_get_contents(__DIR__.'/../fixtures/resources-clean.xlf'),
|
||||
file_get_contents($tempDir.'/messages.en_US.xlf')
|
||||
);
|
||||
|
||||
unlink($tempDir.'/messages.en_US.xlf');
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Dumper\YamlFileDumper;
|
||||
|
||||
class YamlFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$dumper = new YamlFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/../fixtures/resources.yml'), file_get_contents($tempDir.'/messages.en.yml'));
|
||||
|
||||
unlink($tempDir.'/messages.en.yml');
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Intl\Util\IntlTestHelper;
|
||||
use Symfony\Component\Translation\IdentityTranslator;
|
||||
|
||||
class IdentityTranslatorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getTransTests
|
||||
*/
|
||||
public function testTrans($expected, $id, $parameters)
|
||||
{
|
||||
$translator = new IdentityTranslator();
|
||||
|
||||
$this->assertEquals($expected, $translator->trans($id, $parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTransChoiceTests
|
||||
*/
|
||||
public function testTransChoiceWithExplicitLocale($expected, $id, $number, $parameters)
|
||||
{
|
||||
$translator = new IdentityTranslator();
|
||||
$translator->setLocale('en');
|
||||
|
||||
$this->assertEquals($expected, $translator->transChoice($id, $number, $parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTransChoiceTests
|
||||
*/
|
||||
public function testTransChoiceWithDefaultLocale($expected, $id, $number, $parameters)
|
||||
{
|
||||
\Locale::setDefault('en');
|
||||
|
||||
$translator = new IdentityTranslator();
|
||||
|
||||
$this->assertEquals($expected, $translator->transChoice($id, $number, $parameters));
|
||||
}
|
||||
|
||||
public function testGetSetLocale()
|
||||
{
|
||||
$translator = new IdentityTranslator();
|
||||
$translator->setLocale('en');
|
||||
|
||||
$this->assertEquals('en', $translator->getLocale());
|
||||
}
|
||||
|
||||
public function testGetLocaleReturnsDefaultLocaleIfNotSet()
|
||||
{
|
||||
// in order to test with "pt_BR"
|
||||
IntlTestHelper::requireFullIntl($this);
|
||||
|
||||
$translator = new IdentityTranslator();
|
||||
|
||||
\Locale::setDefault('en');
|
||||
$this->assertEquals('en', $translator->getLocale());
|
||||
|
||||
\Locale::setDefault('pt_BR');
|
||||
$this->assertEquals('pt_BR', $translator->getLocale());
|
||||
}
|
||||
|
||||
public function getTransTests()
|
||||
{
|
||||
return array(
|
||||
array('Symfony is great!', 'Symfony is great!', array()),
|
||||
array('Symfony is awesome!', 'Symfony is %what%!', array('%what%' => 'awesome')),
|
||||
);
|
||||
}
|
||||
|
||||
public function getTransChoiceTests()
|
||||
{
|
||||
return array(
|
||||
array('There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0, array('%count%' => 0)),
|
||||
array('There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1, array('%count%' => 1)),
|
||||
array('There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10, array('%count%' => 10)),
|
||||
array('There are 0 apples', 'There is 1 apple|There are %count% apples', 0, array('%count%' => 0)),
|
||||
array('There is 1 apple', 'There is 1 apple|There are %count% apples', 1, array('%count%' => 1)),
|
||||
array('There are 10 apples', 'There is 1 apple|There are %count% apples', 10, array('%count%' => 10)),
|
||||
// custom validation messages may be coded with a fixed value
|
||||
array('There are 2 apples', 'There are 2 apples', 2, array('%count%' => 2)),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Translation\Interval;
|
||||
|
||||
class IntervalTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getTests
|
||||
*/
|
||||
public function testTest($expected, $number, $interval)
|
||||
{
|
||||
$this->assertEquals($expected, Interval::test($number, $interval));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testTestException()
|
||||
{
|
||||
Interval::test(1, 'foobar');
|
||||
}
|
||||
|
||||
public function getTests()
|
||||
{
|
||||
return array(
|
||||
array(true, 3, '{1,2, 3 ,4}'),
|
||||
array(false, 10, '{1,2, 3 ,4}'),
|
||||
array(false, 3, '[1,2]'),
|
||||
array(true, 1, '[1,2]'),
|
||||
array(true, 2, '[1,2]'),
|
||||
array(false, 1, ']1,2['),
|
||||
array(false, 2, ']1,2['),
|
||||
array(true, log(0), '[-Inf,2['),
|
||||
array(true, -log(0), '[-2,+Inf]'),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\CsvFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class CsvFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new CsvFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.csv';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testLoadDoesNothingIfEmpty()
|
||||
{
|
||||
$loader = new CsvFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty.csv';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array(), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new CsvFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/not-exists.csv';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadNonLocalResource()
|
||||
{
|
||||
$loader = new CsvFileLoader();
|
||||
$resource = 'http://example.com/resources.csv';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\IcuDatFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class IcuDatFileLoaderTest extends LocalizedTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!extension_loaded('intl')) {
|
||||
$this->markTestSkipped('This test requires intl extension to work.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadInvalidResource()
|
||||
{
|
||||
$loader = new IcuDatFileLoader();
|
||||
$loader->load(__DIR__.'/../fixtures/resourcebundle/corrupted/resources', 'es', 'domain2');
|
||||
}
|
||||
|
||||
public function testDatEnglishLoad()
|
||||
{
|
||||
// bundled resource is build using pkgdata command which at least in ICU 4.2 comes in extremely! buggy form
|
||||
// you must specify an temporary build directory which is not the same as current directory and
|
||||
// MUST reside on the same partition. pkgdata -p resources -T /srv -d.packagelist.txt
|
||||
$loader = new IcuDatFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resourcebundle/dat/resources';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('symfony' => 'Symfony 2 is great'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource.'.dat')), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testDatFrenchLoad()
|
||||
{
|
||||
$loader = new IcuDatFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resourcebundle/dat/resources';
|
||||
$catalogue = $loader->load($resource, 'fr', 'domain1');
|
||||
|
||||
$this->assertEquals(array('symfony' => 'Symfony 2 est génial'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('fr', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource.'.dat')), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new IcuDatFileLoader();
|
||||
$loader->load(__DIR__.'/../fixtures/non-existing.txt', 'en', 'domain1');
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\IcuResFileLoader;
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
|
||||
class IcuResFileLoaderTest extends LocalizedTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!extension_loaded('intl')) {
|
||||
$this->markTestSkipped('This test requires intl extension to work.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testLoad()
|
||||
{
|
||||
// resource is build using genrb command
|
||||
$loader = new IcuResFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resourcebundle/res';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new DirectoryResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new IcuResFileLoader();
|
||||
$loader->load(__DIR__.'/../fixtures/non-existing.txt', 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadInvalidResource()
|
||||
{
|
||||
$loader = new IcuResFileLoader();
|
||||
$loader->load(__DIR__.'/../fixtures/resourcebundle/corrupted', 'en', 'domain1');
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\IniFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class IniFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new IniFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.ini';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testLoadDoesNothingIfEmpty()
|
||||
{
|
||||
$loader = new IniFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty.ini';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array(), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new IniFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-existing.ini';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\JsonFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class JsonFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new JsonFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.json';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testLoadDoesNothingIfEmpty()
|
||||
{
|
||||
$loader = new JsonFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty.json';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array(), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new JsonFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-existing.json';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
* @expectedExceptionMessage Error parsing JSON - Syntax error, malformed JSON
|
||||
*/
|
||||
public function testParseException()
|
||||
{
|
||||
$loader = new JsonFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/malformed.json';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
abstract class LocalizedTestCase extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!extension_loaded('intl')) {
|
||||
$this->markTestSkipped('The "intl" extension is not available');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\MoFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class MoFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new MoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.mo';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testLoadPlurals()
|
||||
{
|
||||
$loader = new MoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/plurals.mo';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar', 'foos' => '{0} bar|{1} bars'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new MoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-existing.mo';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadInvalidResource()
|
||||
{
|
||||
$loader = new MoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty.mo';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
public function testLoadEmptyTranslation()
|
||||
{
|
||||
$loader = new MoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty-translation.mo';
|
||||
$catalogue = $loader->load($resource, 'en', 'message');
|
||||
|
||||
$this->assertEquals(array(), $catalogue->all('message'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\PhpFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class PhpFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new PhpFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.php';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new PhpFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-existing.php';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadThrowsAnExceptionIfFileNotLocal()
|
||||
{
|
||||
$loader = new PhpFileLoader();
|
||||
$resource = 'http://example.com/resources.php';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\PoFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class PoFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.po';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testLoadPlurals()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/plurals.po';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar', 'foos' => 'bar|bars'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testLoadDoesNothingIfEmpty()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty.po';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array(), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-existing.po';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
public function testLoadEmptyTranslation()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty-translation.po';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => ''), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testEscapedId()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/escaped-id.po';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$messages = $catalogue->all('domain1');
|
||||
$this->assertArrayHasKey('escaped "foo"', $messages);
|
||||
$this->assertEquals('escaped "bar"', $messages['escaped "foo"']);
|
||||
}
|
||||
|
||||
public function testEscapedIdPlurals()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/escaped-id-plurals.po';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$messages = $catalogue->all('domain1');
|
||||
$this->assertArrayHasKey('escaped "foo"', $messages);
|
||||
$this->assertArrayHasKey('escaped "foos"', $messages);
|
||||
$this->assertEquals('escaped "bar"', $messages['escaped "foo"']);
|
||||
$this->assertEquals('escaped "bar"|escaped "bars"', $messages['escaped "foos"']);
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\QtFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class QtFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new QtFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.ts';
|
||||
$catalogue = $loader->load($resource, 'en', 'resources');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('resources'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new QtFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-existing.ts';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadNonLocalResource()
|
||||
{
|
||||
$loader = new QtFileLoader();
|
||||
$resource = 'http://domain1.com/resources.ts';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadInvalidResource()
|
||||
{
|
||||
$loader = new QtFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/invalid-xml-resources.xlf';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
public function testLoadEmptyResource()
|
||||
{
|
||||
$loader = new QtFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty.xlf';
|
||||
$this->setExpectedException('Symfony\Component\Translation\Exception\InvalidResourceException', sprintf('Unable to load "%s".', $resource));
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\XliffFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.xlf';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
$this->assertSame(array(), libxml_get_errors());
|
||||
$this->assertContainsOnly('string', $catalogue->all('domain1'));
|
||||
}
|
||||
|
||||
public function testLoadWithInternalErrorsEnabled()
|
||||
{
|
||||
libxml_use_internal_errors(true);
|
||||
|
||||
$this->assertSame(array(), libxml_get_errors());
|
||||
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.xlf';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
$this->assertSame(array(), libxml_get_errors());
|
||||
}
|
||||
|
||||
public function testLoadWithResname()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$catalogue = $loader->load(__DIR__.'/../fixtures/resname.xlf', 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo'), $catalogue->all('domain1'));
|
||||
}
|
||||
|
||||
public function testIncompleteResource()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$catalogue = $loader->load(__DIR__.'/../fixtures/resources.xlf', 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar', 'extra' => 'extra', 'key' => '', 'test' => 'with'), $catalogue->all('domain1'));
|
||||
}
|
||||
|
||||
public function testEncoding()
|
||||
{
|
||||
if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
|
||||
$this->markTestSkipped('The iconv and mbstring extensions are not available.');
|
||||
}
|
||||
|
||||
$loader = new XliffFileLoader();
|
||||
$catalogue = $loader->load(__DIR__.'/../fixtures/encoding.xlf', 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(utf8_decode('föö'), $catalogue->get('bar', 'domain1'));
|
||||
$this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1'));
|
||||
$this->assertEquals(array('notes' => array(array('content' => utf8_decode('bäz')))), $catalogue->getMetadata('foo', 'domain1'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadInvalidResource()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$loader->load(__DIR__.'/../fixtures/resources.php', 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadResourceDoesNotValidate()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$loader->load(__DIR__.'/../fixtures/non-valid.xlf', 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-existing.xlf';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadThrowsAnExceptionIfFileNotLocal()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = 'http://example.com/resources.xlf';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
* @expectedExceptionMessage Document types are not allowed.
|
||||
*/
|
||||
public function testDocTypeIsNotAllowed()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$loader->load(__DIR__.'/../fixtures/withdoctype.xlf', 'en', 'domain1');
|
||||
}
|
||||
|
||||
public function testParseEmptyFile()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty.xlf';
|
||||
$this->setExpectedException('Symfony\Component\Translation\Exception\InvalidResourceException', sprintf('Unable to load "%s":', $resource));
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
public function testLoadNotes()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$catalogue = $loader->load(__DIR__.'/../fixtures/withnote.xlf', 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('notes' => array(array('priority' => 1, 'content' => 'foo'))), $catalogue->getMetadata('foo', 'domain1'));
|
||||
// message without target
|
||||
$this->assertEquals(array('notes' => array(array('content' => 'bar', 'from' => 'foo'))), $catalogue->getMetadata('extra', 'domain1'));
|
||||
// message with empty target
|
||||
$this->assertEquals(array('notes' => array(array('content' => 'baz'), array('priority' => 2, 'from' => 'bar', 'content' => 'qux'))), $catalogue->getMetadata('key', 'domain1'));
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Translation\Loader\YamlFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLoad()
|
||||
{
|
||||
$loader = new YamlFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.yml';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array('foo' => 'bar'), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testLoadDoesNothingIfEmpty()
|
||||
{
|
||||
$loader = new YamlFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/empty.yml';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(array(), $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testLoadNonExistingResource()
|
||||
{
|
||||
$loader = new YamlFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-existing.yml';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadThrowsAnExceptionIfFileNotLocal()
|
||||
{
|
||||
$loader = new YamlFileLoader();
|
||||
$resource = 'http://example.com/resources.yml';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException
|
||||
*/
|
||||
public function testLoadThrowsAnExceptionIfNotAnArray()
|
||||
{
|
||||
$loader = new YamlFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/non-valid.yml';
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Component\Translation\LoggingTranslator;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
|
||||
class LoggingTranslatorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!interface_exists('Psr\Log\LoggerInterface')) {
|
||||
$this->markTestSkipped('The "LoggerInterface" is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public function testTransWithNoTranslationIsLogged()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger->expects($this->exactly(2))
|
||||
->method('warning')
|
||||
->with('Translation not found.')
|
||||
;
|
||||
|
||||
$translator = new Translator('ar');
|
||||
$loggableTranslator = new LoggingTranslator($translator, $logger);
|
||||
$loggableTranslator->transChoice('some_message2', 10, array('%count%' => 10));
|
||||
$loggableTranslator->trans('bar');
|
||||
}
|
||||
|
||||
public function testTransChoiceFallbackIsLogged()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
$logger->expects($this->once())
|
||||
->method('debug')
|
||||
->with('Translation use fallback catalogue.')
|
||||
;
|
||||
|
||||
$translator = new Translator('ar');
|
||||
$translator->setFallbackLocales(array('en'));
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en');
|
||||
$loggableTranslator = new LoggingTranslator($translator, $logger);
|
||||
$loggableTranslator->transChoice('some_message2', 10, array('%count%' => 10));
|
||||
}
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class MessageCatalogueTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testGetLocale()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
}
|
||||
|
||||
public function testGetDomains()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en', array('domain1' => array(), 'domain2' => array()));
|
||||
|
||||
$this->assertEquals(array('domain1', 'domain2'), $catalogue->getDomains());
|
||||
}
|
||||
|
||||
public function testAll()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en', $messages = array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
|
||||
|
||||
$this->assertEquals(array('foo' => 'foo'), $catalogue->all('domain1'));
|
||||
$this->assertEquals(array(), $catalogue->all('domain88'));
|
||||
$this->assertEquals($messages, $catalogue->all());
|
||||
}
|
||||
|
||||
public function testHas()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
|
||||
|
||||
$this->assertTrue($catalogue->has('foo', 'domain1'));
|
||||
$this->assertFalse($catalogue->has('bar', 'domain1'));
|
||||
$this->assertFalse($catalogue->has('foo', 'domain88'));
|
||||
}
|
||||
|
||||
public function testGetSet()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
|
||||
$catalogue->set('foo1', 'foo1', 'domain1');
|
||||
|
||||
$this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
|
||||
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
|
||||
}
|
||||
|
||||
public function testAdd()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
|
||||
$catalogue->add(array('foo1' => 'foo1'), 'domain1');
|
||||
|
||||
$this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
|
||||
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
|
||||
|
||||
$catalogue->add(array('foo' => 'bar'), 'domain1');
|
||||
$this->assertEquals('bar', $catalogue->get('foo', 'domain1'));
|
||||
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
|
||||
|
||||
$catalogue->add(array('foo' => 'bar'), 'domain88');
|
||||
$this->assertEquals('bar', $catalogue->get('foo', 'domain88'));
|
||||
}
|
||||
|
||||
public function testReplace()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
|
||||
$catalogue->replace($messages = array('foo1' => 'foo1'), 'domain1');
|
||||
|
||||
$this->assertEquals($messages, $catalogue->all('domain1'));
|
||||
}
|
||||
|
||||
public function testAddCatalogue()
|
||||
{
|
||||
$r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
|
||||
$r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
|
||||
|
||||
$r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
|
||||
$r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
|
||||
|
||||
$catalogue = new MessageCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
|
||||
$catalogue->addResource($r);
|
||||
|
||||
$catalogue1 = new MessageCatalogue('en', array('domain1' => array('foo1' => 'foo1')));
|
||||
$catalogue1->addResource($r1);
|
||||
|
||||
$catalogue->addCatalogue($catalogue1);
|
||||
|
||||
$this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
|
||||
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
|
||||
|
||||
$this->assertEquals(array($r, $r1), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testAddFallbackCatalogue()
|
||||
{
|
||||
$r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
|
||||
$r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
|
||||
|
||||
$r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
|
||||
$r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
|
||||
|
||||
$catalogue = new MessageCatalogue('en_US', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
|
||||
$catalogue->addResource($r);
|
||||
|
||||
$catalogue1 = new MessageCatalogue('en', array('domain1' => array('foo' => 'bar', 'foo1' => 'foo1')));
|
||||
$catalogue1->addResource($r1);
|
||||
|
||||
$catalogue->addFallbackCatalogue($catalogue1);
|
||||
|
||||
$this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
|
||||
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
|
||||
|
||||
$this->assertEquals(array($r, $r1), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testAddFallbackCatalogueWithParentCircularReference()
|
||||
{
|
||||
$main = new MessageCatalogue('en_US');
|
||||
$fallback = new MessageCatalogue('fr_FR');
|
||||
|
||||
$fallback->addFallbackCatalogue($main);
|
||||
$main->addFallbackCatalogue($fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testAddFallbackCatalogueWithFallbackCircularReference()
|
||||
{
|
||||
$fr = new MessageCatalogue('fr');
|
||||
$en = new MessageCatalogue('en');
|
||||
$es = new MessageCatalogue('es');
|
||||
|
||||
$fr->addFallbackCatalogue($en);
|
||||
$es->addFallbackCatalogue($en);
|
||||
$en->addFallbackCatalogue($fr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testAddCatalogueWhenLocaleIsNotTheSameAsTheCurrentOne()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->addCatalogue(new MessageCatalogue('fr', array()));
|
||||
}
|
||||
|
||||
public function testGetAddResource()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$r = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
|
||||
$r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
|
||||
$catalogue->addResource($r);
|
||||
$catalogue->addResource($r);
|
||||
$r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
|
||||
$r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
|
||||
$catalogue->addResource($r1);
|
||||
|
||||
$this->assertEquals(array($r, $r1), $catalogue->getResources());
|
||||
}
|
||||
|
||||
public function testMetadataDelete()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$this->assertEquals(array(), $catalogue->getMetadata('', ''), 'Metadata is empty');
|
||||
$catalogue->deleteMetadata('key', 'messages');
|
||||
$catalogue->deleteMetadata('', 'messages');
|
||||
$catalogue->deleteMetadata();
|
||||
}
|
||||
|
||||
public function testMetadataSetGetDelete()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->setMetadata('key', 'value');
|
||||
$this->assertEquals('value', $catalogue->getMetadata('key', 'messages'), "Metadata 'key' = 'value'");
|
||||
|
||||
$catalogue->setMetadata('key2', array());
|
||||
$this->assertEquals(array(), $catalogue->getMetadata('key2', 'messages'), 'Metadata key2 is array');
|
||||
|
||||
$catalogue->deleteMetadata('key2', 'messages');
|
||||
$this->assertNull($catalogue->getMetadata('key2', 'messages'), 'Metadata key2 should is deleted.');
|
||||
|
||||
$catalogue->deleteMetadata('key2', 'domain');
|
||||
$this->assertNull($catalogue->getMetadata('key2', 'domain'), 'Metadata key2 should is deleted.');
|
||||
}
|
||||
|
||||
public function testMetadataMerge()
|
||||
{
|
||||
$cat1 = new MessageCatalogue('en');
|
||||
$cat1->setMetadata('a', 'b');
|
||||
$this->assertEquals(array('messages' => array('a' => 'b')), $cat1->getMetadata('', ''), 'Cat1 contains messages metadata.');
|
||||
|
||||
$cat2 = new MessageCatalogue('en');
|
||||
$cat2->setMetadata('b', 'c', 'domain');
|
||||
$this->assertEquals(array('domain' => array('b' => 'c')), $cat2->getMetadata('', ''), 'Cat2 contains domain metadata.');
|
||||
|
||||
$cat1->addCatalogue($cat2);
|
||||
$this->assertEquals(array('messages' => array('a' => 'b'), 'domain' => array('b' => 'c')), $cat1->getMetadata('', ''), 'Cat1 contains merged metadata.');
|
||||
}
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Translation\MessageSelector;
|
||||
|
||||
class MessageSelectorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getChooseTests
|
||||
*/
|
||||
public function testChoose($expected, $id, $number)
|
||||
{
|
||||
$selector = new MessageSelector();
|
||||
|
||||
$this->assertEquals($expected, $selector->choose($id, $number, 'en'));
|
||||
}
|
||||
|
||||
public function testReturnMessageIfExactlyOneStandardRuleIsGiven()
|
||||
{
|
||||
$selector = new MessageSelector();
|
||||
|
||||
$this->assertEquals('There are two apples', $selector->choose('There are two apples', 2, 'en'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getNonMatchingMessages
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number)
|
||||
{
|
||||
$selector = new MessageSelector();
|
||||
|
||||
$selector->choose($id, $number, 'en');
|
||||
}
|
||||
|
||||
public function getNonMatchingMessages()
|
||||
{
|
||||
return array(
|
||||
array('{0} There are no apples|{1} There is one apple', 2),
|
||||
array('{1} There is one apple|]1,Inf] There are %count% apples', 0),
|
||||
array('{1} There is one apple|]2,Inf] There are %count% apples', 2),
|
||||
array('{0} There are no apples|There is one apple', 2),
|
||||
);
|
||||
}
|
||||
|
||||
public function getChooseTests()
|
||||
{
|
||||
return array(
|
||||
array('There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0),
|
||||
array('There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0),
|
||||
array('There are no apples', '{0}There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0),
|
||||
|
||||
array('There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1),
|
||||
|
||||
array('There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10),
|
||||
array('There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf]There are %count% apples', 10),
|
||||
array('There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10),
|
||||
|
||||
array('There are %count% apples', 'There is one apple|There are %count% apples', 0),
|
||||
array('There is one apple', 'There is one apple|There are %count% apples', 1),
|
||||
array('There are %count% apples', 'There is one apple|There are %count% apples', 10),
|
||||
|
||||
array('There are %count% apples', 'one: There is one apple|more: There are %count% apples', 0),
|
||||
array('There is one apple', 'one: There is one apple|more: There are %count% apples', 1),
|
||||
array('There are %count% apples', 'one: There is one apple|more: There are %count% apples', 10),
|
||||
|
||||
array('There are no apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 0),
|
||||
array('There is one apple', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 1),
|
||||
array('There are %count% apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 10),
|
||||
|
||||
array('', '{0}|{1} There is one apple|]1,Inf] There are %count% apples', 0),
|
||||
array('', '{0} There are no apples|{1}|]1,Inf] There are %count% apples', 1),
|
||||
|
||||
// Indexed only tests which are Gettext PoFile* compatible strings.
|
||||
array('There are %count% apples', 'There is one apple|There are %count% apples', 0),
|
||||
array('There is one apple', 'There is one apple|There are %count% apples', 1),
|
||||
array('There are %count% apples', 'There is one apple|There are %count% apples', 2),
|
||||
|
||||
// Tests for float numbers
|
||||
array('There is almost one apple', '{0} There are no apples|]0,1[ There is almost one apple|{1} There is one apple|[1,Inf] There is more than one apple', 0.7),
|
||||
array('There is one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1),
|
||||
array('There is more than one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1.7),
|
||||
array('There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0),
|
||||
array('There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0.0),
|
||||
array('There are no apples', '{0.0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0),
|
||||
|
||||
// Test texts with new-lines
|
||||
// with double-quotes and \n in id & double-quotes and actual newlines in text
|
||||
array("This is a text with a\n new-line in it. Selector = 0.", '{0}This is a text with a
|
||||
new-line in it. Selector = 0.|{1}This is a text with a
|
||||
new-line in it. Selector = 1.|[1,Inf]This is a text with a
|
||||
new-line in it. Selector > 1.', 0),
|
||||
// with double-quotes and \n in id and single-quotes and actual newlines in text
|
||||
array("This is a text with a\n new-line in it. Selector = 1.", '{0}This is a text with a
|
||||
new-line in it. Selector = 0.|{1}This is a text with a
|
||||
new-line in it. Selector = 1.|[1,Inf]This is a text with a
|
||||
new-line in it. Selector > 1.', 1),
|
||||
array("This is a text with a\n new-line in it. Selector > 1.", '{0}This is a text with a
|
||||
new-line in it. Selector = 0.|{1}This is a text with a
|
||||
new-line in it. Selector = 1.|[1,Inf]This is a text with a
|
||||
new-line in it. Selector > 1.', 5),
|
||||
// with double-quotes and id split accros lines
|
||||
array('This is a text with a
|
||||
new-line in it. Selector = 1.', '{0}This is a text with a
|
||||
new-line in it. Selector = 0.|{1}This is a text with a
|
||||
new-line in it. Selector = 1.|[1,Inf]This is a text with a
|
||||
new-line in it. Selector > 1.', 1),
|
||||
// with single-quotes and id split accros lines
|
||||
array('This is a text with a
|
||||
new-line in it. Selector > 1.', '{0}This is a text with a
|
||||
new-line in it. Selector = 0.|{1}This is a text with a
|
||||
new-line in it. Selector = 1.|[1,Inf]This is a text with a
|
||||
new-line in it. Selector > 1.', 5),
|
||||
// with single-quotes and \n in text
|
||||
array('This is a text with a\nnew-line in it. Selector = 0.', '{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.', 0),
|
||||
// with double-quotes and id split accros lines
|
||||
array("This is a text with a\nnew-line in it. Selector = 1.", "{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.", 1),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Translation\PluralizationRules;
|
||||
|
||||
/**
|
||||
* Test should cover all languages mentioned on http://translate.sourceforge.net/wiki/l10n/pluralforms
|
||||
* and Plural forms mentioned on http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms.
|
||||
*
|
||||
* See also https://developer.mozilla.org/en/Localization_and_Plurals which mentions 15 rules having a maximum of 6 forms.
|
||||
* The mozilla code is also interesting to check for.
|
||||
*
|
||||
* As mentioned by chx http://drupal.org/node/1273968 we can cover all by testing number from 0 to 199
|
||||
*
|
||||
* The goal to cover all languages is to far fetched so this test case is smaller.
|
||||
*
|
||||
* @author Clemens Tolboom clemens@build2be.nl
|
||||
*/
|
||||
class PluralizationRulesTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* We test failed langcode here.
|
||||
*
|
||||
* TODO: The languages mentioned in the data provide need to get fixed somehow within PluralizationRules.
|
||||
*
|
||||
* @dataProvider failingLangcodes
|
||||
*/
|
||||
public function testFailedLangcodes($nplural, $langCodes)
|
||||
{
|
||||
$matrix = $this->generateTestData($nplural, $langCodes);
|
||||
$this->validateMatrix($nplural, $matrix, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider successLangcodes
|
||||
*/
|
||||
public function testLangcodes($nplural, $langCodes)
|
||||
{
|
||||
$matrix = $this->generateTestData($nplural, $langCodes);
|
||||
$this->validateMatrix($nplural, $matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* This array should contain all currently known langcodes.
|
||||
*
|
||||
* As it is impossible to have this ever complete we should try as hard as possible to have it almost complete.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function successLangcodes()
|
||||
{
|
||||
return array(
|
||||
array('1', array('ay','bo', 'cgg','dz','id', 'ja', 'jbo', 'ka','kk','km','ko','ky')),
|
||||
array('2', array('nl', 'fr', 'en', 'de', 'de_GE')),
|
||||
array('3', array('be','bs','cs','hr')),
|
||||
array('4', array('cy','mt', 'sl')),
|
||||
array('5', array()),
|
||||
array('6', array('ar')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This array should be at least empty within the near future.
|
||||
*
|
||||
* This both depends on a complete list trying to add above as understanding
|
||||
* the plural rules of the current failing languages.
|
||||
*
|
||||
* @return array with nplural together with langcodes
|
||||
*/
|
||||
public function failingLangcodes()
|
||||
{
|
||||
return array(
|
||||
array('1', array('fa')),
|
||||
array('2', array('jbo')),
|
||||
array('3', array('cbs')),
|
||||
array('4', array('gd','kw')),
|
||||
array('5', array('ga')),
|
||||
array('6', array()),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* We validate only on the plural coverage. Thus the real rules is not tested.
|
||||
*
|
||||
* @param string $nplural plural expected
|
||||
* @param array $matrix containing langcodes and their plural index values.
|
||||
* @param bool $expectSuccess
|
||||
*/
|
||||
protected function validateMatrix($nplural, $matrix, $expectSuccess = true)
|
||||
{
|
||||
foreach ($matrix as $langCode => $data) {
|
||||
$indexes = array_flip($data);
|
||||
if ($expectSuccess) {
|
||||
$this->assertEquals($nplural, count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
|
||||
} else {
|
||||
$this->assertNotEquals((int) $nplural, count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateTestData($plural, $langCodes)
|
||||
{
|
||||
$matrix = array();
|
||||
foreach ($langCodes as $langCode) {
|
||||
for ($count = 0; $count < 200; ++$count) {
|
||||
$plural = PluralizationRules::get($count, $langCode);
|
||||
$matrix[$langCode][$count] = $plural;
|
||||
}
|
||||
}
|
||||
|
||||
return $matrix;
|
||||
}
|
||||
}
|
|
@ -1,299 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
use Symfony\Component\Translation\Loader\LoaderInterface;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class TranslatorCacheTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $tmpDir;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->tmpDir = sys_get_temp_dir().'/sf2_translation';
|
||||
$this->deleteTmpDir();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$this->deleteTmpDir();
|
||||
}
|
||||
|
||||
protected function deleteTmpDir()
|
||||
{
|
||||
if (!file_exists($dir = $this->tmpDir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->tmpDir), \RecursiveIteratorIterator::CHILD_FIRST);
|
||||
foreach ($iterator as $path) {
|
||||
if (preg_match('#[/\\\\]\.\.?$#', $path->__toString())) {
|
||||
continue;
|
||||
}
|
||||
if ($path->isDir()) {
|
||||
rmdir($path->__toString());
|
||||
} else {
|
||||
unlink($path->__toString());
|
||||
}
|
||||
}
|
||||
rmdir($this->tmpDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider runForDebugAndProduction
|
||||
*/
|
||||
public function testThatACacheIsUsed($debug)
|
||||
{
|
||||
$locale = 'any_locale';
|
||||
$format = 'some_format';
|
||||
$msgid = 'test';
|
||||
|
||||
// Prime the cache
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, new ArrayLoader());
|
||||
$translator->addResource($format, array($msgid => 'OK'), $locale);
|
||||
$translator->trans($msgid);
|
||||
|
||||
// Try again and see we get a valid result whilst no loader can be used
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, $this->createFailingLoader());
|
||||
$translator->addResource($format, array($msgid => 'OK'), $locale);
|
||||
$this->assertEquals('OK', $translator->trans($msgid), '-> caching does not work in '.($debug ? 'debug' : 'production'));
|
||||
}
|
||||
|
||||
public function testCatalogueIsReloadedWhenResourcesAreNoLongerFresh()
|
||||
{
|
||||
/*
|
||||
* The testThatACacheIsUsed() test showed that we don't need the loader as long as the cache
|
||||
* is fresh.
|
||||
*
|
||||
* Now we add a Resource that is never fresh and make sure that the
|
||||
* cache is discarded (the loader is called twice).
|
||||
*
|
||||
* We need to run this for debug=true only because in production the cache
|
||||
* will never be revalidated.
|
||||
*/
|
||||
|
||||
$locale = 'any_locale';
|
||||
$format = 'some_format';
|
||||
$msgid = 'test';
|
||||
|
||||
$catalogue = new MessageCatalogue($locale, array());
|
||||
$catalogue->addResource(new StaleResource()); // better use a helper class than a mock, because it gets serialized in the cache and re-loaded
|
||||
|
||||
/** @var LoaderInterface|\PHPUnit_Framework_MockObject_MockObject $loader */
|
||||
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
|
||||
$loader
|
||||
->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->will($this->returnValue($catalogue))
|
||||
;
|
||||
|
||||
// 1st pass
|
||||
$translator = new Translator($locale, null, $this->tmpDir, true);
|
||||
$translator->addLoader($format, $loader);
|
||||
$translator->addResource($format, null, $locale);
|
||||
$translator->trans($msgid);
|
||||
|
||||
// 2nd pass
|
||||
$translator = new Translator($locale, null, $this->tmpDir, true);
|
||||
$translator->addLoader($format, $loader);
|
||||
$translator->addResource($format, null, $locale);
|
||||
$translator->trans($msgid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider runForDebugAndProduction
|
||||
*/
|
||||
public function testDifferentTranslatorsForSameLocaleDoNotOverwriteEachOthersCache($debug)
|
||||
{
|
||||
/*
|
||||
* Similar to the previous test. After we used the second translator, make
|
||||
* sure there's still a useable cache for the first one.
|
||||
*/
|
||||
|
||||
$locale = 'any_locale';
|
||||
$format = 'some_format';
|
||||
$msgid = 'test';
|
||||
|
||||
// Create a Translator and prime its cache
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, new ArrayLoader());
|
||||
$translator->addResource($format, array($msgid => 'OK'), $locale);
|
||||
$translator->trans($msgid);
|
||||
|
||||
// Create another Translator with a different catalogue for the same locale
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, new ArrayLoader());
|
||||
$translator->addResource($format, array($msgid => 'FAIL'), $locale);
|
||||
$translator->trans($msgid);
|
||||
|
||||
// Now the first translator must still have a useable cache.
|
||||
$translator = new Translator($locale, null, $this->tmpDir, $debug);
|
||||
$translator->addLoader($format, $this->createFailingLoader());
|
||||
$translator->addResource($format, array($msgid => 'OK'), $locale);
|
||||
$this->assertEquals('OK', $translator->trans($msgid), '-> the cache was overwritten by another translator instance in '.($debug ? 'debug' : 'production'));
|
||||
}
|
||||
|
||||
public function testDifferentCacheFilesAreUsedForDifferentSetsOfFallbackLocales()
|
||||
{
|
||||
/*
|
||||
* Because the cache file contains a catalogue including all of its fallback
|
||||
* catalogues, we must take the set of fallback locales into consideration when
|
||||
* loading a catalogue from the cache.
|
||||
*/
|
||||
$translator = new Translator('a', null, $this->tmpDir);
|
||||
$translator->setFallbackLocales(array('b'));
|
||||
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (a)'), 'a');
|
||||
$translator->addResource('array', array('bar' => 'bar (b)'), 'b');
|
||||
|
||||
$this->assertEquals('bar (b)', $translator->trans('bar'));
|
||||
|
||||
// Remove fallback locale
|
||||
$translator->setFallbackLocales(array());
|
||||
$this->assertEquals('bar', $translator->trans('bar'));
|
||||
|
||||
// Use a fresh translator with no fallback locales, result should be the same
|
||||
$translator = new Translator('a', null, $this->tmpDir);
|
||||
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (a)'), 'a');
|
||||
$translator->addResource('array', array('bar' => 'bar (b)'), 'b');
|
||||
|
||||
$this->assertEquals('bar', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
public function testPrimaryAndFallbackCataloguesContainTheSameMessagesRegardlessOfCaching()
|
||||
{
|
||||
/*
|
||||
* As a safeguard against potential BC breaks, make sure that primary and fallback
|
||||
* catalogues (reachable via getFallbackCatalogue()) always contain the full set of
|
||||
* messages provided by the loader. This must also be the case when these catalogues
|
||||
* are (internally) read from a cache.
|
||||
*
|
||||
* Optimizations inside the translator must not change this behaviour.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create a translator that loads two catalogues for two different locales.
|
||||
* The catalogues contain distinct sets of messages.
|
||||
*/
|
||||
$translator = new Translator('a', null, $this->tmpDir);
|
||||
$translator->setFallbackLocales(array('b'));
|
||||
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (a)'), 'a');
|
||||
$translator->addResource('array', array('foo' => 'foo (b)'), 'b');
|
||||
$translator->addResource('array', array('bar' => 'bar (b)'), 'b');
|
||||
|
||||
$catalogue = $translator->getCatalogue('a');
|
||||
$this->assertFalse($catalogue->defines('bar')); // Sure, the "a" catalogue does not contain that message.
|
||||
|
||||
$fallback = $catalogue->getFallbackCatalogue();
|
||||
$this->assertTrue($fallback->defines('foo')); // "foo" is present in "a" and "b"
|
||||
|
||||
/*
|
||||
* Now, repeat the same test.
|
||||
* Behind the scenes, the cache is used. But that should not matter, right?
|
||||
*/
|
||||
$translator = new Translator('a', null, $this->tmpDir);
|
||||
$translator->setFallbackLocales(array('b'));
|
||||
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (a)'), 'a');
|
||||
$translator->addResource('array', array('foo' => 'foo (b)'), 'b');
|
||||
$translator->addResource('array', array('bar' => 'bar (b)'), 'b');
|
||||
|
||||
$catalogue = $translator->getCatalogue('a');
|
||||
$this->assertFalse($catalogue->defines('bar'));
|
||||
|
||||
$fallback = $catalogue->getFallbackCatalogue();
|
||||
$this->assertTrue($fallback->defines('foo'));
|
||||
}
|
||||
|
||||
public function testRefreshCacheWhenResourcesAreNoLongerFresh()
|
||||
{
|
||||
$resource = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface');
|
||||
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
|
||||
$resource->method('isFresh')->will($this->returnValue(false));
|
||||
$loader
|
||||
->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->will($this->returnValue($this->getCatalogue('fr', array(), array($resource))));
|
||||
|
||||
// prime the cache
|
||||
$translator = new Translator('fr', null, $this->tmpDir, true);
|
||||
$translator->addLoader('loader', $loader);
|
||||
$translator->addResource('loader', 'foo', 'fr');
|
||||
$translator->trans('foo');
|
||||
|
||||
// prime the cache second time
|
||||
$translator = new Translator('fr', null, $this->tmpDir, true);
|
||||
$translator->addLoader('loader', $loader);
|
||||
$translator->addResource('loader', 'foo', 'fr');
|
||||
$translator->trans('foo');
|
||||
}
|
||||
|
||||
protected function getCatalogue($locale, $messages, $resources = array())
|
||||
{
|
||||
$catalogue = new MessageCatalogue($locale);
|
||||
foreach ($messages as $key => $translation) {
|
||||
$catalogue->set($key, $translation);
|
||||
}
|
||||
foreach ($resources as $resource) {
|
||||
$catalogue->addResource($resource);
|
||||
}
|
||||
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
public function runForDebugAndProduction()
|
||||
{
|
||||
return array(array(true), array(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LoaderInterface
|
||||
*/
|
||||
private function createFailingLoader()
|
||||
{
|
||||
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
|
||||
$loader
|
||||
->expects($this->never())
|
||||
->method('load');
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
class StaleResource implements ResourceInterface
|
||||
{
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getResource()
|
||||
{
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
|
@ -1,627 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Translation\Tests;
|
||||
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Component\Translation\MessageSelector;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class TranslatorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getInvalidLocalesTests
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorInvalidLocale($locale)
|
||||
{
|
||||
$translator = new Translator($locale, new MessageSelector());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testConstructorValidLocale($locale)
|
||||
{
|
||||
$translator = new Translator($locale, new MessageSelector());
|
||||
|
||||
$this->assertEquals($locale, $translator->getLocale());
|
||||
}
|
||||
|
||||
public function testConstructorWithoutLocale()
|
||||
{
|
||||
$translator = new Translator(null, new MessageSelector());
|
||||
|
||||
$this->assertNull($translator->getLocale());
|
||||
}
|
||||
|
||||
public function testSetGetLocale()
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
|
||||
$this->assertEquals('en', $translator->getLocale());
|
||||
|
||||
$translator->setLocale('fr');
|
||||
$this->assertEquals('fr', $translator->getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidLocalesTests
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testSetInvalidLocale($locale)
|
||||
{
|
||||
$translator = new Translator('fr', new MessageSelector());
|
||||
$translator->setLocale($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testSetValidLocale($locale)
|
||||
{
|
||||
$translator = new Translator($locale, new MessageSelector());
|
||||
$translator->setLocale($locale);
|
||||
|
||||
$this->assertEquals($locale, $translator->getLocale());
|
||||
}
|
||||
|
||||
public function testGetCatalogue()
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
|
||||
$this->assertEquals(new MessageCatalogue('en'), $translator->getCatalogue());
|
||||
|
||||
$translator->setLocale('fr');
|
||||
$this->assertEquals(new MessageCatalogue('fr'), $translator->getCatalogue('fr'));
|
||||
}
|
||||
|
||||
public function testGetCatalogueReturnsConsolidatedCatalogue()
|
||||
{
|
||||
/*
|
||||
* This will be useful once we refactor so that different domains will be loaded lazily (on-demand).
|
||||
* In that case, getCatalogue() will probably have to load all missing domains in order to return
|
||||
* one complete catalogue.
|
||||
*/
|
||||
|
||||
$locale = 'whatever';
|
||||
$translator = new Translator($locale);
|
||||
$translator->addLoader('loader-a', new ArrayLoader());
|
||||
$translator->addLoader('loader-b', new ArrayLoader());
|
||||
$translator->addResource('loader-a', array('foo' => 'foofoo'), $locale, 'domain-a');
|
||||
$translator->addResource('loader-b', array('bar' => 'foobar'), $locale, 'domain-b');
|
||||
|
||||
/*
|
||||
* Test that we get a single catalogue comprising messages
|
||||
* from different loaders and different domains
|
||||
*/
|
||||
$catalogue = $translator->getCatalogue($locale);
|
||||
$this->assertTrue($catalogue->defines('foo', 'domain-a'));
|
||||
$this->assertTrue($catalogue->defines('bar', 'domain-b'));
|
||||
}
|
||||
|
||||
public function testSetFallbackLocales()
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
|
||||
$translator->addResource('array', array('bar' => 'foobar'), 'fr');
|
||||
|
||||
// force catalogue loading
|
||||
$translator->trans('bar');
|
||||
|
||||
$translator->setFallbackLocales(array('fr'));
|
||||
$this->assertEquals('foobar', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
public function testSetFallbackLocalesMultiple()
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (en)'), 'en');
|
||||
$translator->addResource('array', array('bar' => 'bar (fr)'), 'fr');
|
||||
|
||||
// force catalogue loading
|
||||
$translator->trans('bar');
|
||||
|
||||
$translator->setFallbackLocales(array('fr_FR', 'fr'));
|
||||
$this->assertEquals('bar (fr)', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidLocalesTests
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testSetFallbackInvalidLocales($locale)
|
||||
{
|
||||
$translator = new Translator('fr', new MessageSelector());
|
||||
$translator->setFallbackLocales(array('fr', $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testSetFallbackValidLocales($locale)
|
||||
{
|
||||
$translator = new Translator($locale, new MessageSelector());
|
||||
$translator->setFallbackLocales(array('fr', $locale));
|
||||
// no assertion. this method just asserts that no exception is thrown
|
||||
}
|
||||
|
||||
public function testTransWithFallbackLocale()
|
||||
{
|
||||
$translator = new Translator('fr_FR');
|
||||
$translator->setFallbackLocales(array('en'));
|
||||
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('bar' => 'foobar'), 'en');
|
||||
|
||||
$this->assertEquals('foobar', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidLocalesTests
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testAddResourceInvalidLocales($locale)
|
||||
{
|
||||
$translator = new Translator('fr', new MessageSelector());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testAddResourceValidLocales($locale)
|
||||
{
|
||||
$translator = new Translator('fr', new MessageSelector());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), $locale);
|
||||
// no assertion. this method just asserts that no exception is thrown
|
||||
}
|
||||
|
||||
public function testAddResourceAfterTrans()
|
||||
{
|
||||
$translator = new Translator('fr');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
|
||||
$translator->setFallbackLocales(array('en'));
|
||||
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
|
||||
$this->assertEquals('foofoo', $translator->trans('foo'));
|
||||
|
||||
$translator->addResource('array', array('bar' => 'foobar'), 'en');
|
||||
$this->assertEquals('foobar', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTransFileTests
|
||||
* @expectedException \Symfony\Component\Translation\Exception\NotFoundResourceException
|
||||
*/
|
||||
public function testTransWithoutFallbackLocaleFile($format, $loader)
|
||||
{
|
||||
$loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
|
||||
$translator = new Translator('en');
|
||||
$translator->addLoader($format, new $loaderClass());
|
||||
$translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en');
|
||||
$translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en');
|
||||
|
||||
// force catalogue loading
|
||||
$translator->trans('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTransFileTests
|
||||
*/
|
||||
public function testTransWithFallbackLocaleFile($format, $loader)
|
||||
{
|
||||
$loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader;
|
||||
$translator = new Translator('en_GB');
|
||||
$translator->addLoader($format, new $loaderClass());
|
||||
$translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en_GB');
|
||||
$translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en', 'resources');
|
||||
|
||||
$this->assertEquals('bar', $translator->trans('foo', array(), 'resources'));
|
||||
}
|
||||
|
||||
public function testTransWithFallbackLocaleBis()
|
||||
{
|
||||
$translator = new Translator('en_US');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en_US');
|
||||
$translator->addResource('array', array('bar' => 'foobar'), 'en');
|
||||
$this->assertEquals('foobar', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
public function testTransWithFallbackLocaleTer()
|
||||
{
|
||||
$translator = new Translator('fr_FR');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foo (en_US)'), 'en_US');
|
||||
$translator->addResource('array', array('bar' => 'bar (en)'), 'en');
|
||||
|
||||
$translator->setFallbackLocales(array('en_US', 'en'));
|
||||
|
||||
$this->assertEquals('foo (en_US)', $translator->trans('foo'));
|
||||
$this->assertEquals('bar (en)', $translator->trans('bar'));
|
||||
}
|
||||
|
||||
public function testTransNonExistentWithFallback()
|
||||
{
|
||||
$translator = new Translator('fr');
|
||||
$translator->setFallbackLocales(array('en'));
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$this->assertEquals('non-existent', $translator->trans('non-existent'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testWhenAResourceHasNoRegisteredLoader()
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
|
||||
|
||||
$translator->trans('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTransTests
|
||||
*/
|
||||
public function testTrans($expected, $id, $translation, $parameters, $locale, $domain)
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array((string) $id => $translation), $locale, $domain);
|
||||
|
||||
$this->assertEquals($expected, $translator->trans($id, $parameters, $domain, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidLocalesTests
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testTransInvalidLocale($locale)
|
||||
{
|
||||
$translator = new Translator('en', new MessageSelector());
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
|
||||
|
||||
$translator->trans('foo', array(), '', $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testTransValidLocale($locale)
|
||||
{
|
||||
$translator = new Translator($locale, new MessageSelector());
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('test' => 'OK'), $locale);
|
||||
|
||||
$this->assertEquals('OK', $translator->trans('test'));
|
||||
$this->assertEquals('OK', $translator->trans('test', array(), null, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getFlattenedTransTests
|
||||
*/
|
||||
public function testFlattenedTrans($expected, $messages, $id)
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', $messages, 'fr', '');
|
||||
|
||||
$this->assertEquals($expected, $translator->trans($id, array(), '', 'fr'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTransChoiceTests
|
||||
*/
|
||||
public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain)
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array((string) $id => $translation), $locale, $domain);
|
||||
|
||||
$this->assertEquals($expected, $translator->transChoice($id, $number, $parameters, $domain, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidLocalesTests
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testTransChoiceInvalidLocale($locale)
|
||||
{
|
||||
$translator = new Translator('en', new MessageSelector());
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
|
||||
|
||||
$translator->transChoice('foo', 1, array(), '', $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testTransChoiceValidLocale($locale)
|
||||
{
|
||||
$translator = new Translator('en', new MessageSelector());
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
|
||||
|
||||
$translator->transChoice('foo', 1, array(), '', $locale);
|
||||
// no assertion. this method just asserts that no exception is thrown
|
||||
}
|
||||
|
||||
public function getTransFileTests()
|
||||
{
|
||||
return array(
|
||||
array('csv', 'CsvFileLoader'),
|
||||
array('ini', 'IniFileLoader'),
|
||||
array('mo', 'MoFileLoader'),
|
||||
array('po', 'PoFileLoader'),
|
||||
array('php', 'PhpFileLoader'),
|
||||
array('ts', 'QtFileLoader'),
|
||||
array('xlf', 'XliffFileLoader'),
|
||||
array('yml', 'YamlFileLoader'),
|
||||
array('json', 'JsonFileLoader'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getTransTests()
|
||||
{
|
||||
return array(
|
||||
array('Symfony est super !', 'Symfony is great!', 'Symfony est super !', array(), 'fr', ''),
|
||||
array('Symfony est awesome !', 'Symfony is %what%!', 'Symfony est %what% !', array('%what%' => 'awesome'), 'fr', ''),
|
||||
array('Symfony est super !', new StringClass('Symfony is great!'), 'Symfony est super !', array(), 'fr', ''),
|
||||
);
|
||||
}
|
||||
|
||||
public function getFlattenedTransTests()
|
||||
{
|
||||
$messages = array(
|
||||
'symfony' => array(
|
||||
'is' => array(
|
||||
'great' => 'Symfony est super!',
|
||||
),
|
||||
),
|
||||
'foo' => array(
|
||||
'bar' => array(
|
||||
'baz' => 'Foo Bar Baz',
|
||||
),
|
||||
'baz' => 'Foo Baz',
|
||||
),
|
||||
);
|
||||
|
||||
return array(
|
||||
array('Symfony est super!', $messages, 'symfony.is.great'),
|
||||
array('Foo Bar Baz', $messages, 'foo.bar.baz'),
|
||||
array('Foo Baz', $messages, 'foo.baz'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getTransChoiceTests()
|
||||
{
|
||||
return array(
|
||||
array('Il y a 0 pomme', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
|
||||
array('Il y a 1 pomme', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
|
||||
array('Il y a 10 pommes', '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
|
||||
|
||||
array('Il y a 0 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
|
||||
array('Il y a 1 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
|
||||
array('Il y a 10 pommes', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
|
||||
|
||||
array('Il y a 0 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
|
||||
array('Il y a 1 pomme', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
|
||||
array('Il y a 10 pommes', 'one: There is one apple|more: There is %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
|
||||
|
||||
array('Il n\'y a aucune pomme', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
|
||||
array('Il y a 1 pomme', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1), 'fr', ''),
|
||||
array('Il y a 10 pommes', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10), 'fr', ''),
|
||||
|
||||
array('Il y a 0 pomme', new StringClass('{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples'), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0), 'fr', ''),
|
||||
);
|
||||
}
|
||||
|
||||
public function getInvalidLocalesTests()
|
||||
{
|
||||
return array(
|
||||
array('fr FR'),
|
||||
array('français'),
|
||||
array('fr+en'),
|
||||
array('utf#8'),
|
||||
array('fr&en'),
|
||||
array('fr~FR'),
|
||||
array(' fr'),
|
||||
array('fr '),
|
||||
array('fr*'),
|
||||
array('fr/FR'),
|
||||
array('fr\\FR'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getValidLocalesTests()
|
||||
{
|
||||
return array(
|
||||
array(''),
|
||||
array(null),
|
||||
array('fr'),
|
||||
array('francais'),
|
||||
array('FR'),
|
||||
array('frFR'),
|
||||
array('fr-FR'),
|
||||
array('fr_FR'),
|
||||
array('fr.FR'),
|
||||
array('fr-FR.UTF8'),
|
||||
array('sr@latin'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testTransChoiceFallback()
|
||||
{
|
||||
$translator = new Translator('ru');
|
||||
$translator->setFallbackLocales(array('en'));
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en');
|
||||
|
||||
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
|
||||
}
|
||||
|
||||
public function testTransChoiceFallbackBis()
|
||||
{
|
||||
$translator = new Translator('ru');
|
||||
$translator->setFallbackLocales(array('en_US', 'en'));
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
$translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en_US');
|
||||
|
||||
$this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
|
||||
}
|
||||
|
||||
public function testTransChoiceFallbackWithNoTranslation()
|
||||
{
|
||||
$translator = new Translator('ru');
|
||||
$translator->setFallbackLocales(array('en'));
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
|
||||
// consistent behavior with Translator::trans(), which returns the string
|
||||
// unchanged if it can't be found
|
||||
$this->assertEquals('some_message2', $translator->transChoice('some_message2', 10, array('%count%' => 10)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProviderGetMessages
|
||||
*/
|
||||
public function testGetMessages($resources, $locale, $expected)
|
||||
{
|
||||
$locales = array_keys($resources);
|
||||
$_locale = null !== $locale ? $locale : reset($locales);
|
||||
$locales = array_slice($locales, 0, array_search($_locale, $locales));
|
||||
|
||||
$translator = new Translator($_locale, new MessageSelector());
|
||||
$translator->setFallbackLocales(array_reverse($locales));
|
||||
$translator->addLoader('array', new ArrayLoader());
|
||||
foreach ($resources as $_locale => $domainMessages) {
|
||||
foreach ($domainMessages as $domain => $messages) {
|
||||
$translator->addResource('array', $messages, $_locale, $domain);
|
||||
}
|
||||
}
|
||||
$result = $translator->getMessages($locale);
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
public function dataProviderGetMessages()
|
||||
{
|
||||
$resources = array(
|
||||
'en' => array(
|
||||
'jsmessages' => array(
|
||||
'foo' => 'foo (EN)',
|
||||
'bar' => 'bar (EN)',
|
||||
),
|
||||
'messages' => array(
|
||||
'foo' => 'foo messages (EN)',
|
||||
),
|
||||
'validators' => array(
|
||||
'int' => 'integer (EN)',
|
||||
),
|
||||
),
|
||||
'pt-PT' => array(
|
||||
'messages' => array(
|
||||
'foo' => 'foo messages (PT)',
|
||||
),
|
||||
'validators' => array(
|
||||
'str' => 'integer (PT)',
|
||||
),
|
||||
),
|
||||
'pt_BR' => array(
|
||||
'validators' => array(
|
||||
'int' => 'integer (BR)',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return array(
|
||||
array($resources, null,
|
||||
array(
|
||||
'jsmessages' => array(
|
||||
'foo' => 'foo (EN)',
|
||||
'bar' => 'bar (EN)',
|
||||
),
|
||||
'messages' => array(
|
||||
'foo' => 'foo messages (EN)',
|
||||
),
|
||||
'validators' => array(
|
||||
'int' => 'integer (EN)',
|
||||
),
|
||||
),
|
||||
),
|
||||
array($resources, 'en',
|
||||
array(
|
||||
'jsmessages' => array(
|
||||
'foo' => 'foo (EN)',
|
||||
'bar' => 'bar (EN)',
|
||||
),
|
||||
'messages' => array(
|
||||
'foo' => 'foo messages (EN)',
|
||||
),
|
||||
'validators' => array(
|
||||
'int' => 'integer (EN)',
|
||||
),
|
||||
),
|
||||
),
|
||||
array($resources, 'pt-PT',
|
||||
array(
|
||||
'jsmessages' => array(
|
||||
'foo' => 'foo (EN)',
|
||||
'bar' => 'bar (EN)',
|
||||
),
|
||||
'messages' => array(
|
||||
'foo' => 'foo messages (PT)',
|
||||
),
|
||||
'validators' => array(
|
||||
'int' => 'integer (EN)',
|
||||
'str' => 'integer (PT)',
|
||||
),
|
||||
),
|
||||
),
|
||||
array($resources, 'pt_BR',
|
||||
array(
|
||||
'jsmessages' => array(
|
||||
'foo' => 'foo (EN)',
|
||||
'bar' => 'bar (EN)',
|
||||
),
|
||||
'messages' => array(
|
||||
'foo' => 'foo messages (PT)',
|
||||
),
|
||||
'validators' => array(
|
||||
'int' => 'integer (BR)',
|
||||
'str' => 'integer (PT)',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StringClass
|
||||
{
|
||||
protected $str;
|
||||
|
||||
public function __construct($str)
|
||||
{
|
||||
$this->str = $str;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->str;
|
||||
}
|
||||
}
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue