updated backend
This commit is contained in:
parent
1fea0f4fe7
commit
11521c2339
3459 changed files with 72735 additions and 168535 deletions
|
|
@ -1,3 +0,0 @@
|
|||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
39
pfosten/vendor/symfony/translation/CHANGELOG.md
vendored
39
pfosten/vendor/symfony/translation/CHANGELOG.md
vendored
|
|
@ -1,6 +1,45 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* deprecated support for using `null` as the locale in `Translator`
|
||||
* deprecated accepting STDIN implicitly when using the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit.
|
||||
* Marked the `TranslationDataCollector` class as `@final`.
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
* Improved Xliff 1.2 loader to load the original file's metadata
|
||||
* Added `TranslatorPathsPass`
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* Started using ICU parent locales as fallback locales.
|
||||
* allow using the ICU message format using domains with the "+intl-icu" suffix
|
||||
* deprecated `Translator::transChoice()` in favor of using `Translator::trans()` with a `%count%` parameter
|
||||
* deprecated `TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`
|
||||
* deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead
|
||||
* Added `IntlFormatter` and `IntlFormatterInterface`
|
||||
* added support for multiple files and directories in `XliffLintCommand`
|
||||
* Marked `Translator::getFallbackLocales()` and `TranslationDataCollector::getFallbackLocales()` as internal
|
||||
|
||||
4.1.0
|
||||
-----
|
||||
|
||||
* The `FileDumper::setBackup()` method is deprecated.
|
||||
* The `TranslationWriter::disableBackup()` method is deprecated.
|
||||
* The `XliffFileDumper` will write "name" on the "unit" node when dumping XLIFF 2.0.
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* removed the backup feature of the `FileDumper` class
|
||||
* removed `TranslationWriter::writeTranslations()` method
|
||||
* removed support for passing `MessageSelector` instances to the constructor of the `Translator` class
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ abstract class AbstractOperation implements OperationInterface
|
|||
protected $result;
|
||||
|
||||
/**
|
||||
* @var null|array The domains affected by this operation
|
||||
* @var array|null The domains affected by this operation
|
||||
*/
|
||||
private $domains;
|
||||
|
||||
|
|
@ -39,21 +39,20 @@ abstract class AbstractOperation implements OperationInterface
|
|||
* This array stores 'all', 'new' and 'obsolete' messages for all valid domains.
|
||||
*
|
||||
* The data structure of this array is as follows:
|
||||
* ```php
|
||||
* array(
|
||||
* 'domain 1' => array(
|
||||
* 'all' => array(...),
|
||||
* 'new' => array(...),
|
||||
* 'obsolete' => array(...)
|
||||
* ),
|
||||
* 'domain 2' => array(
|
||||
* 'all' => array(...),
|
||||
* 'new' => array(...),
|
||||
* 'obsolete' => array(...)
|
||||
* ),
|
||||
* ...
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* [
|
||||
* 'domain 1' => [
|
||||
* 'all' => [...],
|
||||
* 'new' => [...],
|
||||
* 'obsolete' => [...]
|
||||
* ],
|
||||
* 'domain 2' => [
|
||||
* 'all' => [...],
|
||||
* 'new' => [...],
|
||||
* 'obsolete' => [...]
|
||||
* ],
|
||||
* ...
|
||||
* ]
|
||||
*
|
||||
* @var array The array that stores 'all', 'new' and 'obsolete' messages
|
||||
*/
|
||||
|
|
@ -71,7 +70,7 @@ abstract class AbstractOperation implements OperationInterface
|
|||
$this->source = $source;
|
||||
$this->target = $target;
|
||||
$this->result = new MessageCatalogue($source->getLocale());
|
||||
$this->messages = array();
|
||||
$this->messages = [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Symfony\Component\Translation\Catalogue;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
/**
|
||||
* Merge operation between two catalogues as follows:
|
||||
* all = source ∪ target = {x: x ∈ source ∨ x ∈ target}
|
||||
|
|
@ -27,15 +29,16 @@ class MergeOperation extends AbstractOperation
|
|||
*/
|
||||
protected function processDomain($domain)
|
||||
{
|
||||
$this->messages[$domain] = array(
|
||||
'all' => array(),
|
||||
'new' => array(),
|
||||
'obsolete' => array(),
|
||||
);
|
||||
$this->messages[$domain] = [
|
||||
'all' => [],
|
||||
'new' => [],
|
||||
'obsolete' => [],
|
||||
];
|
||||
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||
|
||||
foreach ($this->source->all($domain) as $id => $message) {
|
||||
$this->messages[$domain]['all'][$id] = $message;
|
||||
$this->result->add(array($id => $message), $domain);
|
||||
$this->result->add([$id => $message], $this->source->defines($id, $intlDomain) ? $intlDomain : $domain);
|
||||
if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) {
|
||||
$this->result->setMetadata($id, $keyMetadata, $domain);
|
||||
}
|
||||
|
|
@ -45,7 +48,7 @@ class MergeOperation extends AbstractOperation
|
|||
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);
|
||||
$this->result->add([$id => $message], $this->target->defines($id, $intlDomain) ? $intlDomain : $domain);
|
||||
if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) {
|
||||
$this->result->setMetadata($id, $keyMetadata, $domain);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Symfony\Component\Translation\Catalogue;
|
||||
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
/**
|
||||
* Target operation between two catalogues:
|
||||
* intersection = source ∩ target = {x: x ∈ source ∧ x ∈ target}
|
||||
|
|
@ -28,25 +30,26 @@ class TargetOperation extends AbstractOperation
|
|||
*/
|
||||
protected function processDomain($domain)
|
||||
{
|
||||
$this->messages[$domain] = array(
|
||||
'all' => array(),
|
||||
'new' => array(),
|
||||
'obsolete' => array(),
|
||||
);
|
||||
$this->messages[$domain] = [
|
||||
'all' => [],
|
||||
'new' => [],
|
||||
'obsolete' => [],
|
||||
];
|
||||
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||
|
||||
// For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``,
|
||||
// because doing so will drop messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}
|
||||
//
|
||||
// For 'new' messages, the code can't be simplied as ``array_diff_assoc($this->target->all($domain), $this->source->all($domain));``
|
||||
// For 'new' messages, the code can't be simplified as ``array_diff_assoc($this->target->all($domain), $this->source->all($domain));``
|
||||
// because doing so will not exclude messages like {x: x ∈ target ∧ x ∉ source.all ∧ x ∈ source.fallback}
|
||||
//
|
||||
// For 'obsolete' messages, the code can't be simplifed as ``array_diff_assoc($this->source->all($domain), $this->target->all($domain))``
|
||||
// For 'obsolete' messages, the code can't be simplified as ``array_diff_assoc($this->source->all($domain), $this->target->all($domain))``
|
||||
// because doing so will not exclude messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}
|
||||
|
||||
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);
|
||||
$this->result->add([$id => $message], $this->target->defines($id, $intlDomain) ? $intlDomain : $domain);
|
||||
if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) {
|
||||
$this->result->setMetadata($id, $keyMetadata, $domain);
|
||||
}
|
||||
|
|
@ -59,7 +62,7 @@ class TargetOperation extends AbstractOperation
|
|||
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);
|
||||
$this->result->add([$id => $message], $this->target->defines($id, $intlDomain) ? $intlDomain : $domain);
|
||||
if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) {
|
||||
$this->result->setMetadata($id, $keyMetadata, $domain);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ namespace Symfony\Component\Translation\Command;
|
|||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Translation\Util\XliffUtils;
|
||||
|
||||
/**
|
||||
* Validates XLIFF files syntax and outputs encountered errors.
|
||||
|
|
@ -33,13 +35,15 @@ class XliffLintCommand extends Command
|
|||
private $displayCorrectFiles;
|
||||
private $directoryIteratorProvider;
|
||||
private $isReadableProvider;
|
||||
private $requireStrictFileNames;
|
||||
|
||||
public function __construct($name = null, $directoryIteratorProvider = null, $isReadableProvider = null)
|
||||
public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null, bool $requireStrictFileNames = true)
|
||||
{
|
||||
parent::__construct($name);
|
||||
|
||||
$this->directoryIteratorProvider = $directoryIteratorProvider;
|
||||
$this->isReadableProvider = $isReadableProvider;
|
||||
$this->requireStrictFileNames = $requireStrictFileNames;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -49,7 +53,7 @@ class XliffLintCommand extends Command
|
|||
{
|
||||
$this
|
||||
->setDescription('Lints a XLIFF file and outputs encountered errors')
|
||||
->addArgument('filename', null, 'A file or a directory or STDIN')
|
||||
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
|
||||
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command lints a XLIFF file and outputs to STDOUT
|
||||
|
|
@ -57,7 +61,7 @@ the first encountered syntax error.
|
|||
|
||||
You can validates XLIFF contents passed from STDIN:
|
||||
|
||||
<info>cat filename | php %command.full_name%</info>
|
||||
<info>cat filename | php %command.full_name% -</info>
|
||||
|
||||
You can also validate the syntax of a file:
|
||||
|
||||
|
|
@ -76,57 +80,82 @@ EOF
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$filename = $input->getArgument('filename');
|
||||
$filenames = (array) $input->getArgument('filename');
|
||||
$this->format = $input->getOption('format');
|
||||
$this->displayCorrectFiles = $output->isVerbose();
|
||||
|
||||
if (!$filename) {
|
||||
if (!$stdin = $this->getStdin()) {
|
||||
if (['-'] === $filenames) {
|
||||
return $this->display($io, [$this->validate(file_get_contents('php://stdin'))]);
|
||||
}
|
||||
|
||||
// @deprecated to be removed in 5.0
|
||||
if (!$filenames) {
|
||||
if (0 !== ftell(STDIN)) {
|
||||
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
|
||||
}
|
||||
|
||||
return $this->display($io, array($this->validate($stdin)));
|
||||
@trigger_error('Piping content from STDIN to the "lint:xliff" command without passing the dash symbol "-" as argument is deprecated since Symfony 4.4.', E_USER_DEPRECATED);
|
||||
|
||||
return $this->display($io, [$this->validate(file_get_contents('php://stdin'))]);
|
||||
}
|
||||
|
||||
if (!$this->isReadable($filename)) {
|
||||
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
|
||||
}
|
||||
$filesInfo = [];
|
||||
foreach ($filenames as $filename) {
|
||||
if (!$this->isReadable($filename)) {
|
||||
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
|
||||
}
|
||||
|
||||
$filesInfo = array();
|
||||
foreach ($this->getFiles($filename) as $file) {
|
||||
$filesInfo[] = $this->validate(file_get_contents($file), $file);
|
||||
foreach ($this->getFiles($filename) as $file) {
|
||||
$filesInfo[] = $this->validate(file_get_contents($file), $file);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->display($io, $filesInfo);
|
||||
}
|
||||
|
||||
private function validate($content, $file = null)
|
||||
private function validate(string $content, string $file = null): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
// Avoid: Warning DOMDocument::loadXML(): Empty string supplied as input
|
||||
if ('' === trim($content)) {
|
||||
return array('file' => $file, 'valid' => true);
|
||||
return ['file' => $file, 'valid' => true];
|
||||
}
|
||||
|
||||
libxml_use_internal_errors(true);
|
||||
$internal = libxml_use_internal_errors(true);
|
||||
|
||||
$document = new \DOMDocument();
|
||||
$document->loadXML($content);
|
||||
if ($document->schemaValidate(__DIR__.'/../Resources/schemas/xliff-core-1.2-strict.xsd')) {
|
||||
return array('file' => $file, 'valid' => true);
|
||||
|
||||
if (null !== $targetLanguage = $this->getTargetLanguageFromFile($document)) {
|
||||
$normalizedLocale = preg_quote(str_replace('-', '_', $targetLanguage), '/');
|
||||
// strict file names require translation files to be named '____.locale.xlf'
|
||||
// otherwise, both '____.locale.xlf' and 'locale.____.xlf' are allowed
|
||||
// also, the regexp matching must be case-insensitive, as defined for 'target-language' values
|
||||
// http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#target-language
|
||||
$expectedFilenamePattern = $this->requireStrictFileNames ? sprintf('/^.*\.(?i:%s)\.(?:xlf|xliff)/', $normalizedLocale) : sprintf('/^(?:.*\.(?i:%s)|(?i:%s)\..*)\.(?:xlf|xliff)/', $normalizedLocale, $normalizedLocale);
|
||||
|
||||
if (0 === preg_match($expectedFilenamePattern, basename($file))) {
|
||||
$errors[] = [
|
||||
'line' => -1,
|
||||
'column' => -1,
|
||||
'message' => sprintf('There is a mismatch between the language included in the file name ("%s") and the "%s" value used in the "target-language" attribute of the file.', basename($file), $targetLanguage),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$errorMessages = array_map(function ($error) {
|
||||
return array(
|
||||
'line' => $error->line,
|
||||
'column' => $error->column,
|
||||
'message' => trim($error->message),
|
||||
);
|
||||
}, libxml_get_errors());
|
||||
foreach (XliffUtils::validateSchema($document) as $xmlError) {
|
||||
$errors[] = [
|
||||
'line' => $xmlError['line'],
|
||||
'column' => $xmlError['column'],
|
||||
'message' => $xmlError['message'],
|
||||
];
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors(false);
|
||||
libxml_use_internal_errors($internal);
|
||||
|
||||
return array('file' => $file, 'valid' => false, 'messages' => $errorMessages);
|
||||
return ['file' => $file, 'valid' => 0 === \count($errors), 'messages' => $errors];
|
||||
}
|
||||
|
||||
private function display(SymfonyStyle $io, array $files)
|
||||
|
|
@ -184,7 +213,7 @@ EOF
|
|||
return min($errors, 1);
|
||||
}
|
||||
|
||||
private function getFiles($fileOrDirectory)
|
||||
private function getFiles(string $fileOrDirectory)
|
||||
{
|
||||
if (is_file($fileOrDirectory)) {
|
||||
yield new \SplFileInfo($fileOrDirectory);
|
||||
|
|
@ -193,7 +222,7 @@ EOF
|
|||
}
|
||||
|
||||
foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {
|
||||
if (!\in_array($file->getExtension(), array('xlf', 'xliff'))) {
|
||||
if (!\in_array($file->getExtension(), ['xlf', 'xliff'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -201,21 +230,7 @@ EOF
|
|||
}
|
||||
}
|
||||
|
||||
private function getStdin()
|
||||
{
|
||||
if (0 !== ftell(STDIN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$inputs = '';
|
||||
while (!feof(STDIN)) {
|
||||
$inputs .= fread(STDIN, 1024);
|
||||
}
|
||||
|
||||
return $inputs;
|
||||
}
|
||||
|
||||
private function getDirectoryIterator($directory)
|
||||
private function getDirectoryIterator(string $directory)
|
||||
{
|
||||
$default = function ($directory) {
|
||||
return new \RecursiveIteratorIterator(
|
||||
|
|
@ -225,22 +240,33 @@ EOF
|
|||
};
|
||||
|
||||
if (null !== $this->directoryIteratorProvider) {
|
||||
return \call_user_func($this->directoryIteratorProvider, $directory, $default);
|
||||
return ($this->directoryIteratorProvider)($directory, $default);
|
||||
}
|
||||
|
||||
return $default($directory);
|
||||
}
|
||||
|
||||
private function isReadable($fileOrDirectory)
|
||||
private function isReadable(string $fileOrDirectory)
|
||||
{
|
||||
$default = function ($fileOrDirectory) {
|
||||
return is_readable($fileOrDirectory);
|
||||
};
|
||||
|
||||
if (null !== $this->isReadableProvider) {
|
||||
return \call_user_func($this->isReadableProvider, $fileOrDirectory, $default);
|
||||
return ($this->isReadableProvider)($fileOrDirectory, $default);
|
||||
}
|
||||
|
||||
return $default($fileOrDirectory);
|
||||
}
|
||||
|
||||
private function getTargetLanguageFromFile(\DOMDocument $xliffContents): ?string
|
||||
{
|
||||
foreach ($xliffContents->getElementsByTagName('file')[0]->attributes ?? [] as $attribute) {
|
||||
if ('target-language' === $attribute->nodeName) {
|
||||
return $attribute->nodeValue;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ use Symfony\Component\Translation\DataCollectorTranslator;
|
|||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
*
|
||||
* @final since Symfony 4.4
|
||||
*/
|
||||
class TranslationDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||
{
|
||||
|
|
@ -36,20 +38,21 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
|||
{
|
||||
$messages = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages());
|
||||
|
||||
$this->data = $this->computeCount($messages);
|
||||
$this->data += $this->computeCount($messages);
|
||||
$this->data['messages'] = $messages;
|
||||
|
||||
$this->data['locale'] = $this->translator->getLocale();
|
||||
$this->data['fallback_locales'] = $this->translator->getFallbackLocales();
|
||||
|
||||
$this->data = $this->cloneVar($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param \Throwable|null $exception
|
||||
*/
|
||||
public function collect(Request $request, Response $response, \Exception $exception = null)
|
||||
public function collect(Request $request, Response $response/*, \Throwable $exception = null*/)
|
||||
{
|
||||
$this->data['locale'] = $this->translator->getLocale();
|
||||
$this->data['fallback_locales'] = $this->translator->getFallbackLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -57,15 +60,15 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
|||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->data = array();
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @return array|Data
|
||||
*/
|
||||
public function getMessages()
|
||||
{
|
||||
return isset($this->data['messages']) ? $this->data['messages'] : array();
|
||||
return isset($this->data['messages']) ? $this->data['messages'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -97,9 +100,12 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
|||
return !empty($this->data['locale']) ? $this->data['locale'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal since Symfony 4.2
|
||||
*/
|
||||
public function getFallbackLocales()
|
||||
{
|
||||
return (isset($this->data['fallback_locales']) && \count($this->data['fallback_locales']) > 0) ? $this->data['fallback_locales'] : array();
|
||||
return (isset($this->data['fallback_locales']) && \count($this->data['fallback_locales']) > 0) ? $this->data['fallback_locales'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -110,15 +116,15 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
|||
return 'translation';
|
||||
}
|
||||
|
||||
private function sanitizeCollectedMessages($messages)
|
||||
private function sanitizeCollectedMessages(array $messages)
|
||||
{
|
||||
$result = array();
|
||||
$result = [];
|
||||
foreach ($messages as $key => $message) {
|
||||
$messageId = $message['locale'].$message['domain'].$message['id'];
|
||||
|
||||
if (!isset($result[$messageId])) {
|
||||
$message['count'] = 1;
|
||||
$message['parameters'] = !empty($message['parameters']) ? array($message['parameters']) : array();
|
||||
$message['parameters'] = !empty($message['parameters']) ? [$message['parameters']] : [];
|
||||
$messages[$key]['translation'] = $this->sanitizeString($message['translation']);
|
||||
$result[$messageId] = $message;
|
||||
} else {
|
||||
|
|
@ -135,13 +141,13 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
|||
return $result;
|
||||
}
|
||||
|
||||
private function computeCount($messages)
|
||||
private function computeCount(array $messages)
|
||||
{
|
||||
$count = array(
|
||||
$count = [
|
||||
DataCollectorTranslator::MESSAGE_DEFINED => 0,
|
||||
DataCollectorTranslator::MESSAGE_MISSING => 0,
|
||||
DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK => 0,
|
||||
);
|
||||
];
|
||||
|
||||
foreach ($messages as $message) {
|
||||
++$count[$message['state']];
|
||||
|
|
@ -150,7 +156,7 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
|||
return $count;
|
||||
}
|
||||
|
||||
private function sanitizeString($string, $length = 80)
|
||||
private function sanitizeString(string $string, int $length = 80)
|
||||
{
|
||||
$string = trim(preg_replace('/\s+/', ' ', $string));
|
||||
|
||||
|
|
|
|||
|
|
@ -11,12 +11,16 @@
|
|||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
|
||||
use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
|
||||
use Symfony\Contracts\Translation\LocaleAwareInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
*/
|
||||
class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInterface
|
||||
class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorInterface, TranslatorBagInterface, WarmableInterface
|
||||
{
|
||||
const MESSAGE_DEFINED = 0;
|
||||
const MESSAGE_MISSING = 1;
|
||||
|
|
@ -27,15 +31,18 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
*/
|
||||
private $translator;
|
||||
|
||||
private $messages = array();
|
||||
private $messages = [];
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
public function __construct($translator)
|
||||
{
|
||||
if (!$translator instanceof TranslatorBagInterface) {
|
||||
throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface and TranslatorBagInterface.', \get_class($translator)));
|
||||
if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
|
||||
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
|
||||
}
|
||||
if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) {
|
||||
throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', \get_class($translator)));
|
||||
}
|
||||
|
||||
$this->translator = $translator;
|
||||
|
|
@ -44,7 +51,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
|
||||
public function trans($id, array $parameters = [], $domain = null, $locale = null)
|
||||
{
|
||||
$trans = $this->translator->trans($id, $parameters, $domain, $locale);
|
||||
$this->collectMessage($locale, $domain, $id, $trans, $parameters);
|
||||
|
|
@ -54,11 +61,18 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
|
||||
*/
|
||||
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
|
||||
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
|
||||
{
|
||||
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
|
||||
$this->collectMessage($locale, $domain, $id, $trans, $parameters, $number);
|
||||
if ($this->translator instanceof TranslatorInterface) {
|
||||
$trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
|
||||
} else {
|
||||
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
|
||||
}
|
||||
|
||||
$this->collectMessage($locale, $domain, $id, $trans, ['%count%' => $number] + $parameters);
|
||||
|
||||
return $trans;
|
||||
}
|
||||
|
|
@ -87,10 +101,20 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
return $this->translator->getCatalogue($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function warmUp($cacheDir)
|
||||
{
|
||||
if ($this->translator instanceof WarmableInterface) {
|
||||
$this->translator->warmUp($cacheDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fallback locales.
|
||||
*
|
||||
* @return array $locales The fallback locales
|
||||
* @return array The fallback locales
|
||||
*/
|
||||
public function getFallbackLocales()
|
||||
{
|
||||
|
|
@ -98,7 +122,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
return $this->translator->getFallbackLocales();
|
||||
}
|
||||
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,7 +130,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return \call_user_func_array(array($this->translator, $method), $args);
|
||||
return $this->translator->{$method}(...$args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -117,15 +141,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $locale
|
||||
* @param string|null $domain
|
||||
* @param string $id
|
||||
* @param string $translation
|
||||
* @param array|null $parameters
|
||||
* @param int|null $number
|
||||
*/
|
||||
private function collectMessage($locale, $domain, $id, $translation, $parameters = array(), $number = null)
|
||||
private function collectMessage(?string $locale, ?string $domain, ?string $id, string $translation, ?array $parameters = [])
|
||||
{
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
|
|
@ -134,6 +150,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
$id = (string) $id;
|
||||
$catalogue = $this->translator->getCatalogue($locale);
|
||||
$locale = $catalogue->getLocale();
|
||||
$fallbackLocale = null;
|
||||
if ($catalogue->defines($id, $domain)) {
|
||||
$state = self::MESSAGE_DEFINED;
|
||||
} elseif ($catalogue->has($id, $domain)) {
|
||||
|
|
@ -142,24 +159,24 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
|||
$fallbackCatalogue = $catalogue->getFallbackCatalogue();
|
||||
while ($fallbackCatalogue) {
|
||||
if ($fallbackCatalogue->defines($id, $domain)) {
|
||||
$locale = $fallbackCatalogue->getLocale();
|
||||
$fallbackLocale = $fallbackCatalogue->getLocale();
|
||||
break;
|
||||
}
|
||||
|
||||
$fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();
|
||||
}
|
||||
} else {
|
||||
$state = self::MESSAGE_MISSING;
|
||||
}
|
||||
|
||||
$this->messages[] = array(
|
||||
$this->messages[] = [
|
||||
'locale' => $locale,
|
||||
'fallbackLocale' => $fallbackLocale,
|
||||
'domain' => $domain,
|
||||
'id' => $id,
|
||||
'translation' => $translation,
|
||||
'parameters' => $parameters,
|
||||
'transChoiceNumber' => $number,
|
||||
'state' => $state,
|
||||
);
|
||||
'transChoiceNumber' => isset($parameters['%count%']) && is_numeric($parameters['%count%']) ? $parameters['%count%'] : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ class CsvFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
$handle = fopen('php://memory', 'rb+');
|
||||
$handle = fopen('php://memory', 'r+b');
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
fputcsv($handle, array($source, $target), $this->delimiter, $this->enclosure);
|
||||
fputcsv($handle, [$source, $target], $this->delimiter, $this->enclosure);
|
||||
}
|
||||
|
||||
rewind($handle);
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ interface DumperInterface
|
|||
/**
|
||||
* Dumps the message catalogue.
|
||||
*
|
||||
* @param MessageCatalogue $messages The message catalogue
|
||||
* @param array $options Options that are used by the dumper
|
||||
* @param array $options Options that are used by the dumper
|
||||
*/
|
||||
public function dump(MessageCatalogue $messages, $options = array());
|
||||
public function dump(MessageCatalogue $messages, $options = []);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ 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
|
||||
|
|
@ -33,13 +32,6 @@ abstract class FileDumper implements DumperInterface
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
@ -53,52 +45,70 @@ abstract class FileDumper implements DumperInterface
|
|||
/**
|
||||
* Sets backup flag.
|
||||
*
|
||||
* @param bool
|
||||
* @param bool $backup
|
||||
*
|
||||
* @deprecated since Symfony 4.1
|
||||
*/
|
||||
public function setBackup($backup)
|
||||
{
|
||||
$this->backup = $backup;
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
if (false !== $backup) {
|
||||
throw new \LogicException('The backup feature is no longer supported.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dump(MessageCatalogue $messages, $options = array())
|
||||
public function dump(MessageCatalogue $messages, $options = [])
|
||||
{
|
||||
if (!array_key_exists('path', $options)) {
|
||||
if (!\array_key_exists('path', $options)) {
|
||||
throw new InvalidArgumentException('The file dumper needs a path option.');
|
||||
}
|
||||
|
||||
$hasMessageFormatter = class_exists(\MessageFormatter::class);
|
||||
|
||||
// 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) {
|
||||
@trigger_error('Creating a backup while dumping a message catalogue is deprecated since Symfony 3.1 and will be removed in 4.0. Use TranslationWriter::disableBackup() to disable the backup.', E_USER_DEPRECATED);
|
||||
copy($fullpath, $fullpath.'~');
|
||||
}
|
||||
if ($hasMessageFormatter) {
|
||||
$defaultDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX;
|
||||
$altDomain = $domain;
|
||||
} else {
|
||||
$directory = \dirname($fullpath);
|
||||
$defaultDomain = $domain;
|
||||
$altDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX;
|
||||
}
|
||||
$defaultPath = $options['path'].'/'.$this->getRelativePath($defaultDomain, $messages->getLocale());
|
||||
$altPath = $options['path'].'/'.$this->getRelativePath($altDomain, $messages->getLocale());
|
||||
|
||||
if (!file_exists($defaultPath) && file_exists($altPath)) {
|
||||
[$defaultPath, $altPath] = [$altPath, $defaultPath];
|
||||
}
|
||||
|
||||
if (!file_exists($defaultPath)) {
|
||||
$directory = \dirname($defaultPath);
|
||||
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->formatCatalogue($messages, $domain, $options));
|
||||
|
||||
if (file_exists($altPath)) {
|
||||
// clear alternative translation file
|
||||
file_put_contents($altPath, $this->formatCatalogue(new MessageCatalogue($messages->getLocale()), $altDomain, $options));
|
||||
}
|
||||
|
||||
file_put_contents($defaultPath, $this->formatCatalogue($messages, $domain, $options));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a domain of a message catalogue to its string representation.
|
||||
*
|
||||
* @param MessageCatalogue $messages
|
||||
* @param string $domain
|
||||
* @param array $options
|
||||
* @param string $domain
|
||||
*
|
||||
* @return string representation
|
||||
*/
|
||||
abstract public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array());
|
||||
abstract public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = []);
|
||||
|
||||
/**
|
||||
* Gets the file extension of the dumper.
|
||||
|
|
@ -109,18 +119,13 @@ abstract class FileDumper implements DumperInterface
|
|||
|
||||
/**
|
||||
* 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)
|
||||
private function getRelativePath(string $domain, string $locale): string
|
||||
{
|
||||
return strtr($this->relativePathTemplate, array(
|
||||
return strtr($this->relativePathTemplate, [
|
||||
'%domain%' => $domain,
|
||||
'%locale%' => $locale,
|
||||
'%extension%' => $this->getExtension(),
|
||||
));
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class IcuResFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
$data = $indexes = $resources = '';
|
||||
|
||||
|
|
@ -82,16 +82,14 @@ class IcuResFileDumper extends FileDumper
|
|||
return $header.$root.$data;
|
||||
}
|
||||
|
||||
private function writePadding($data)
|
||||
private function writePadding(string $data): ?string
|
||||
{
|
||||
$padding = \strlen($data) % 4;
|
||||
|
||||
if ($padding) {
|
||||
return str_repeat("\xAA", 4 - $padding);
|
||||
}
|
||||
return $padding ? str_repeat("\xAA", 4 - $padding) : null;
|
||||
}
|
||||
|
||||
private function getPosition($data)
|
||||
private function getPosition(string $data)
|
||||
{
|
||||
return (\strlen($data) + 28) / 4;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class IniFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
$output = '';
|
||||
|
||||
|
|
|
|||
|
|
@ -23,13 +23,9 @@ class JsonFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
if (isset($options['json_encoding'])) {
|
||||
$flags = $options['json_encoding'];
|
||||
} else {
|
||||
$flags = \defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0;
|
||||
}
|
||||
$flags = $options['json_encoding'] ?? JSON_PRETTY_PRINT;
|
||||
|
||||
return json_encode($messages->all($domain), $flags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,20 +24,20 @@ class MoFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
$sources = $targets = $sourceOffsets = $targetOffsets = '';
|
||||
$offsets = array();
|
||||
$offsets = [];
|
||||
$size = 0;
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$offsets[] = array_map('strlen', array($sources, $source, $targets, $target));
|
||||
$offsets[] = array_map('strlen', [$sources, $source, $targets, $target]);
|
||||
$sources .= "\0".$source;
|
||||
$targets .= "\0".$target;
|
||||
++$size;
|
||||
}
|
||||
|
||||
$header = array(
|
||||
$header = [
|
||||
'magicNumber' => MoFileLoader::MO_LITTLE_ENDIAN_MAGIC,
|
||||
'formatRevision' => 0,
|
||||
'count' => $size,
|
||||
|
|
@ -45,7 +45,7 @@ class MoFileDumper extends FileDumper
|
|||
'offsetTranslated' => MoFileLoader::MO_HEADER_SIZE + (8 * $size),
|
||||
'sizeHashes' => 0,
|
||||
'offsetHashes' => MoFileLoader::MO_HEADER_SIZE + (16 * $size),
|
||||
);
|
||||
];
|
||||
|
||||
$sourcesSize = \strlen($sources);
|
||||
$sourcesStart = $header['offsetHashes'] + 1;
|
||||
|
|
@ -57,7 +57,7 @@ class MoFileDumper extends FileDumper
|
|||
.$this->writeLong($offset[2] + $sourcesStart + $sourcesSize);
|
||||
}
|
||||
|
||||
$output = implode(array_map(array($this, 'writeLong'), $header))
|
||||
$output = implode('', array_map([$this, 'writeLong'], $header))
|
||||
.$sourceOffsets
|
||||
.$targetOffsets
|
||||
.$sources
|
||||
|
|
@ -75,7 +75,7 @@ class MoFileDumper extends FileDumper
|
|||
return 'mo';
|
||||
}
|
||||
|
||||
private function writeLong($str)
|
||||
private function writeLong($str): string
|
||||
{
|
||||
return pack('V*', $str);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class PhpFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
return "<?php\n\nreturn ".var_export($messages->all($domain), true).";\n";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class PoFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
$output = 'msgid ""'."\n";
|
||||
$output .= 'msgstr ""'."\n";
|
||||
|
|
@ -39,13 +39,78 @@ class PoFileDumper extends FileDumper
|
|||
} else {
|
||||
$newLine = true;
|
||||
}
|
||||
$output .= sprintf('msgid "%s"'."\n", $this->escape($source));
|
||||
$output .= sprintf('msgstr "%s"', $this->escape($target));
|
||||
$metadata = $messages->getMetadata($source, $domain);
|
||||
|
||||
if (isset($metadata['comments'])) {
|
||||
$output .= $this->formatComments($metadata['comments']);
|
||||
}
|
||||
if (isset($metadata['flags'])) {
|
||||
$output .= $this->formatComments(implode(',', (array) $metadata['flags']), ',');
|
||||
}
|
||||
if (isset($metadata['sources'])) {
|
||||
$output .= $this->formatComments(implode(' ', (array) $metadata['sources']), ':');
|
||||
}
|
||||
|
||||
$sourceRules = $this->getStandardRules($source);
|
||||
$targetRules = $this->getStandardRules($target);
|
||||
if (2 == \count($sourceRules) && $targetRules !== []) {
|
||||
$output .= sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0]));
|
||||
$output .= sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1]));
|
||||
foreach ($targetRules as $i => $targetRule) {
|
||||
$output .= sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule));
|
||||
}
|
||||
} else {
|
||||
$output .= sprintf('msgid "%s"'."\n", $this->escape($source));
|
||||
$output .= sprintf('msgstr "%s"'."\n", $this->escape($target));
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function getStandardRules(string $id)
|
||||
{
|
||||
// Partly copied from TranslatorTrait::trans.
|
||||
$parts = [];
|
||||
if (preg_match('/^\|++$/', $id)) {
|
||||
$parts = explode('|', $id);
|
||||
} elseif (preg_match_all('/(?:\|\||[^\|])++/', $id, $matches)) {
|
||||
$parts = $matches[0];
|
||||
}
|
||||
|
||||
$intervalRegexp = <<<'EOF'
|
||||
/^(?P<interval>
|
||||
({\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>[\[\]])
|
||||
)\s*(?P<message>.*?)$/xs
|
||||
EOF;
|
||||
|
||||
$standardRules = [];
|
||||
foreach ($parts as $part) {
|
||||
$part = trim(str_replace('||', '|', $part));
|
||||
|
||||
if (preg_match($intervalRegexp, $part)) {
|
||||
// Explicit rule is not a standard rule.
|
||||
return [];
|
||||
} else {
|
||||
$standardRules[] = $part;
|
||||
}
|
||||
}
|
||||
|
||||
return $standardRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -54,8 +119,19 @@ class PoFileDumper extends FileDumper
|
|||
return 'po';
|
||||
}
|
||||
|
||||
private function escape($str)
|
||||
private function escape(string $str): string
|
||||
{
|
||||
return addcslashes($str, "\0..\37\42\134");
|
||||
}
|
||||
|
||||
private function formatComments($comments, string $prefix = ''): ?string
|
||||
{
|
||||
$output = null;
|
||||
|
||||
foreach ((array) $comments as $comment) {
|
||||
$output .= sprintf('#%s %s'."\n", $prefix, $comment);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class QtFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||
$dom->formatOutput = true;
|
||||
|
|
@ -33,6 +33,17 @@ class QtFileDumper extends FileDumper
|
|||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$message = $context->appendChild($dom->createElement('message'));
|
||||
$metadata = $messages->getMetadata($source, $domain);
|
||||
if (isset($metadata['sources'])) {
|
||||
foreach ((array) $metadata['sources'] as $location) {
|
||||
$loc = explode(':', $location, 2);
|
||||
$location = $message->appendChild($dom->createElement('location'));
|
||||
$location->setAttribute('filename', $loc[0]);
|
||||
if (isset($loc[1])) {
|
||||
$location->setAttribute('line', $loc[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$message->appendChild($dom->createElement('source', $source));
|
||||
$message->appendChild($dom->createElement('translation', $target));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ class XliffFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
$xliffVersion = '1.2';
|
||||
if (array_key_exists('xliff_version', $options)) {
|
||||
if (\array_key_exists('xliff_version', $options)) {
|
||||
$xliffVersion = $options['xliff_version'];
|
||||
}
|
||||
|
||||
if (array_key_exists('default_locale', $options)) {
|
||||
if (\array_key_exists('default_locale', $options)) {
|
||||
$defaultLocale = $options['default_locale'];
|
||||
} else {
|
||||
$defaultLocale = \Locale::getDefault();
|
||||
|
|
@ -41,7 +41,7 @@ class XliffFileDumper extends FileDumper
|
|||
return $this->dumpXliff1($defaultLocale, $messages, $domain, $options);
|
||||
}
|
||||
if ('2.0' === $xliffVersion) {
|
||||
return $this->dumpXliff2($defaultLocale, $messages, $domain, $options);
|
||||
return $this->dumpXliff2($defaultLocale, $messages, $domain);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion));
|
||||
|
|
@ -55,10 +55,10 @@ class XliffFileDumper extends FileDumper
|
|||
return 'xlf';
|
||||
}
|
||||
|
||||
private function dumpXliff1($defaultLocale, MessageCatalogue $messages, $domain, array $options = array())
|
||||
private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = [])
|
||||
{
|
||||
$toolInfo = array('tool-id' => 'symfony', 'tool-name' => 'Symfony');
|
||||
if (array_key_exists('tool_info', $options)) {
|
||||
$toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony'];
|
||||
if (\array_key_exists('tool_info', $options)) {
|
||||
$toolInfo = array_merge($toolInfo, $options['tool_info']);
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ class XliffFileDumper extends FileDumper
|
|||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
private function dumpXliff2($defaultLocale, MessageCatalogue $messages, $domain, array $options = array())
|
||||
private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||
$dom->formatOutput = true;
|
||||
|
|
@ -141,11 +141,20 @@ class XliffFileDumper extends FileDumper
|
|||
$xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale()));
|
||||
|
||||
$xliffFile = $xliff->appendChild($dom->createElement('file'));
|
||||
$xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale());
|
||||
if (MessageCatalogue::INTL_DOMAIN_SUFFIX === substr($domain, -($suffixLength = \strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX)))) {
|
||||
$xliffFile->setAttribute('id', substr($domain, 0, -$suffixLength).'.'.$messages->getLocale());
|
||||
} else {
|
||||
$xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale());
|
||||
}
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$translation = $dom->createElement('unit');
|
||||
$translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._'));
|
||||
$name = $source;
|
||||
if (\strlen($source) > 80) {
|
||||
$name = substr(md5($source), -7);
|
||||
}
|
||||
$translation->setAttribute('name', $name);
|
||||
$metadata = $messages->getMetadata($source, $domain);
|
||||
|
||||
// Add notes section
|
||||
|
|
@ -187,14 +196,8 @@ class XliffFileDumper extends FileDumper
|
|||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param array|null $metadata
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasMetadataArrayInfo($key, $metadata = null)
|
||||
private function hasMetadataArrayInfo(string $key, array $metadata = null): bool
|
||||
{
|
||||
return null !== $metadata && array_key_exists($key, $metadata) && ($metadata[$key] instanceof \Traversable || \is_array($metadata[$key]));
|
||||
return null !== $metadata && \array_key_exists($key, $metadata) && ($metadata[$key] instanceof \Traversable || \is_array($metadata[$key]));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class YamlFileDumper extends FileDumper
|
|||
{
|
||||
private $extension;
|
||||
|
||||
public function __construct(/**string */$extension = 'yml')
|
||||
public function __construct(string $extension = 'yml')
|
||||
{
|
||||
$this->extension = $extension;
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ class YamlFileDumper extends FileDumper
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Yaml\Yaml')) {
|
||||
throw new LogicException('Dumping translations in the YAML format requires the Symfony Yaml component.');
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ namespace Symfony\Component\Translation\Exception;
|
|||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface ExceptionInterface
|
||||
interface ExceptionInterface extends \Throwable
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,21 +21,21 @@ use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
|||
abstract class AbstractFileExtractor
|
||||
{
|
||||
/**
|
||||
* @param string|array $resource Files, a file or a directory
|
||||
* @param string|iterable $resource Files, a file or a directory
|
||||
*
|
||||
* @return array
|
||||
* @return iterable
|
||||
*/
|
||||
protected function extractFiles($resource)
|
||||
{
|
||||
if (\is_array($resource) || $resource instanceof \Traversable) {
|
||||
$files = array();
|
||||
if (is_iterable($resource)) {
|
||||
$files = [];
|
||||
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();
|
||||
$files = $this->canBeExtracted($resource) ? [$this->toSplFileInfo($resource)] : [];
|
||||
} else {
|
||||
$files = $this->extractFromDirectory($resource);
|
||||
}
|
||||
|
|
@ -43,14 +43,9 @@ abstract class AbstractFileExtractor
|
|||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return \SplFileInfo
|
||||
*/
|
||||
private function toSplFileInfo($file)
|
||||
private function toSplFileInfo(string $file): \SplFileInfo
|
||||
{
|
||||
return ($file instanceof \SplFileInfo) ? $file : new \SplFileInfo($file);
|
||||
return new \SplFileInfo($file);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -79,7 +74,7 @@ abstract class AbstractFileExtractor
|
|||
/**
|
||||
* @param string|array $resource Files, a file or a directory
|
||||
*
|
||||
* @return array files to be extracted
|
||||
* @return iterable files to be extracted
|
||||
*/
|
||||
abstract protected function extractFromDirectory($resource);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,13 +25,12 @@ class ChainExtractor implements ExtractorInterface
|
|||
*
|
||||
* @var ExtractorInterface[]
|
||||
*/
|
||||
private $extractors = array();
|
||||
private $extractors = [];
|
||||
|
||||
/**
|
||||
* Adds a loader to the translation extractor.
|
||||
*
|
||||
* @param string $format The format of the loader
|
||||
* @param ExtractorInterface $extractor The loader
|
||||
* @param string $format The format of the loader
|
||||
*/
|
||||
public function addExtractor($format, ExtractorInterface $extractor)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ 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
|
||||
* @param string|array $resource Files, a file or a directory
|
||||
*/
|
||||
public function extract($resource, MessageCatalogue $catalogue);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,22 +11,39 @@
|
|||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorTrait;
|
||||
|
||||
/**
|
||||
* IdentityTranslator does not translate anything.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class IdentityTranslator implements TranslatorInterface
|
||||
class IdentityTranslator implements LegacyTranslatorInterface, TranslatorInterface
|
||||
{
|
||||
private $selector;
|
||||
private $locale;
|
||||
use TranslatorTrait {
|
||||
trans as private doTrans;
|
||||
setLocale as private doSetLocale;
|
||||
}
|
||||
|
||||
private $selector;
|
||||
|
||||
/**
|
||||
* @param MessageSelector|null $selector The message selector for pluralization
|
||||
*/
|
||||
public function __construct(MessageSelector $selector = null)
|
||||
{
|
||||
$this->selector = $selector ?: new MessageSelector();
|
||||
$this->selector = $selector;
|
||||
|
||||
if (__CLASS__ !== \get_class($this)) {
|
||||
@trigger_error(sprintf('Calling "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans($id, array $parameters = [], $domain = null, $locale = null)
|
||||
{
|
||||
return $this->doTrans($id, $parameters, $domain, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,30 +51,27 @@ class IdentityTranslator implements TranslatorInterface
|
|||
*/
|
||||
public function setLocale($locale)
|
||||
{
|
||||
$this->locale = $locale;
|
||||
$this->doSetLocale($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
|
||||
*/
|
||||
public function getLocale()
|
||||
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
|
||||
{
|
||||
return $this->locale ?: \Locale::getDefault();
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
if ($this->selector) {
|
||||
return strtr($this->selector->choose((string) $id, $number, $locale ?: $this->getLocale()), $parameters);
|
||||
}
|
||||
|
||||
return $this->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
|
||||
private function getPluralizationRule(int $number, string $locale): int
|
||||
{
|
||||
return strtr((string) $id, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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);
|
||||
return PluralizationRules::get($number, $locale, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2, use IdentityTranslator instead.', Interval::class), E_USER_DEPRECATED);
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
|
|
@ -32,6 +34,7 @@ use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
|||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
|
||||
* @deprecated since Symfony 4.2, use IdentityTranslator instead
|
||||
*/
|
||||
class Interval
|
||||
{
|
||||
|
|
@ -96,7 +99,7 @@ class Interval
|
|||
EOF;
|
||||
}
|
||||
|
||||
private static function convertNumber($number)
|
||||
private static function convertNumber(string $number): float
|
||||
{
|
||||
if ('-Inf' === $number) {
|
||||
return log(0);
|
||||
|
|
|
|||
2
pfosten/vendor/symfony/translation/LICENSE
vendored
2
pfosten/vendor/symfony/translation/LICENSE
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2004-2018 Fabien Potencier
|
||||
Copyright (c) 2004-2019 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class ArrayLoader implements LoaderInterface
|
|||
*/
|
||||
public function load($resource, $locale, $domain = 'messages')
|
||||
{
|
||||
$this->flatten($resource);
|
||||
$resource = $this->flatten($resource);
|
||||
$catalogue = new MessageCatalogue($locale);
|
||||
$catalogue->add($resource, $domain);
|
||||
|
||||
|
|
@ -36,31 +36,23 @@ class ArrayLoader implements LoaderInterface
|
|||
* Flattens an nested array of translations.
|
||||
*
|
||||
* The scheme used is:
|
||||
* 'key' => array('key2' => array('key3' => 'value'))
|
||||
* 'key' => ['key2' => ['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)
|
||||
private function flatten(array $messages): array
|
||||
{
|
||||
if (null === $subnode) {
|
||||
$subnode = &$messages;
|
||||
}
|
||||
foreach ($subnode as $key => $value) {
|
||||
$result = [];
|
||||
foreach ($messages as $key => $value) {
|
||||
if (\is_array($value)) {
|
||||
$nodePath = $path ? $path.'.'.$key : $key;
|
||||
$this->flatten($messages, $value, $nodePath);
|
||||
if (null === $path) {
|
||||
unset($messages[$key]);
|
||||
foreach ($this->flatten($value) as $k => $v) {
|
||||
$result[$key.'.'.$k] = $v;
|
||||
}
|
||||
} elseif (null !== $path) {
|
||||
$messages[$path.'.'.$key] = $value;
|
||||
} else {
|
||||
$result[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class CsvFileLoader extends FileLoader
|
|||
*/
|
||||
protected function loadResource($resource)
|
||||
{
|
||||
$messages = array();
|
||||
$messages = [];
|
||||
|
||||
try {
|
||||
$file = new \SplFileObject($resource, 'rb');
|
||||
|
|
@ -41,6 +41,10 @@ class CsvFileLoader extends FileLoader
|
|||
$file->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
|
||||
|
||||
foreach ($file as $data) {
|
||||
if (false === $data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('#' !== substr($data[0], 0, 1) && isset($data[1]) && 2 === \count($data)) {
|
||||
$messages[$data[0]] = $data[1];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ abstract class FileLoader extends ArrayLoader
|
|||
|
||||
// empty resource
|
||||
if (null === $messages) {
|
||||
$messages = array();
|
||||
$messages = [];
|
||||
}
|
||||
|
||||
// not an array
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ class IcuDatFileLoader extends IcuResFileLoader
|
|||
try {
|
||||
$rb = new \ResourceBundle($locale, $resource);
|
||||
} catch (\Exception $e) {
|
||||
// HHVM compatibility: constructor throws on invalid resource
|
||||
$rb = null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ class IcuResFileLoader implements LoaderInterface
|
|||
try {
|
||||
$rb = new \ResourceBundle($locale, $resource);
|
||||
} catch (\Exception $e) {
|
||||
// HHVM compatibility: constructor throws on invalid resource
|
||||
$rb = null;
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +75,7 @@ class IcuResFileLoader implements LoaderInterface
|
|||
*
|
||||
* @return array the flattened ResourceBundle
|
||||
*/
|
||||
protected function flatten(\ResourceBundle $rb, array &$messages = array(), $path = null)
|
||||
protected function flatten(\ResourceBundle $rb, array &$messages = [], $path = null)
|
||||
{
|
||||
foreach ($rb as $key => $value) {
|
||||
$nodePath = $path ? $path.'.'.$key : $key;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class JsonFileLoader extends FileLoader
|
|||
*/
|
||||
protected function loadResource($resource)
|
||||
{
|
||||
$messages = array();
|
||||
$messages = [];
|
||||
if ($data = file_get_contents($resource)) {
|
||||
$messages = json_decode($data, true);
|
||||
|
||||
|
|
@ -39,12 +39,8 @@ class JsonFileLoader extends FileLoader
|
|||
|
||||
/**
|
||||
* 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)
|
||||
private function getJSONErrorMessage(int $errorCode): string
|
||||
{
|
||||
switch ($errorCode) {
|
||||
case JSON_ERROR_DEPTH:
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class MoFileLoader extends FileLoader
|
|||
// offsetHashes
|
||||
$this->readLong($stream, $isBigEndian);
|
||||
|
||||
$messages = array();
|
||||
$messages = [];
|
||||
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$pluralId = null;
|
||||
|
|
@ -108,20 +108,15 @@ class MoFileLoader extends FileLoader
|
|||
$translated = explode("\000", $translated);
|
||||
}
|
||||
|
||||
$ids = array('singular' => $singularId, 'plural' => $pluralId);
|
||||
$ids = ['singular' => $singularId, 'plural' => $pluralId];
|
||||
$item = compact('ids', 'translated');
|
||||
|
||||
if (\is_array($item['translated'])) {
|
||||
$messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
|
||||
if (!empty($item['ids']['singular'])) {
|
||||
$id = $item['ids']['singular'];
|
||||
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));
|
||||
$id .= '|'.$item['ids']['plural'];
|
||||
}
|
||||
} elseif (!empty($item['ids']['singular'])) {
|
||||
$messages[$item['ids']['singular']] = stripcslashes($item['translated']);
|
||||
$messages[$id] = stripcslashes(implode('|', (array) $item['translated']));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -134,11 +129,8 @@ class MoFileLoader extends FileLoader
|
|||
* Reads an unsigned long from stream respecting endianness.
|
||||
*
|
||||
* @param resource $stream
|
||||
* @param bool $isBigEndian
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function readLong($stream, $isBigEndian)
|
||||
private function readLong($stream, bool $isBigEndian): int
|
||||
{
|
||||
$result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
|
||||
$result = current($result);
|
||||
|
|
|
|||
|
|
@ -18,11 +18,25 @@ namespace Symfony\Component\Translation\Loader;
|
|||
*/
|
||||
class PhpFileLoader extends FileLoader
|
||||
{
|
||||
private static $cache = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource($resource)
|
||||
{
|
||||
return require $resource;
|
||||
if ([] === self::$cache && \function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN) && (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) || filter_var(ini_get('opcache.enable_cli'), FILTER_VALIDATE_BOOLEAN))) {
|
||||
self::$cache = null;
|
||||
}
|
||||
|
||||
if (null === self::$cache) {
|
||||
return require $resource;
|
||||
}
|
||||
|
||||
if (isset(self::$cache[$resource])) {
|
||||
return self::$cache[$resource];
|
||||
}
|
||||
|
||||
return self::$cache[$resource] = require $resource;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
namespace Symfony\Component\Translation\Loader;
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
|
||||
* @copyright Copyright (c) 2010, Union of RAD https://github.com/UnionOfRAD/lithium
|
||||
* @copyright Copyright (c) 2012, Clemens Tolboom
|
||||
*/
|
||||
class PoFileLoader extends FileLoader
|
||||
|
|
@ -20,7 +20,7 @@ class PoFileLoader extends FileLoader
|
|||
/**
|
||||
* Parses portable object (PO) format.
|
||||
*
|
||||
* From http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
|
||||
* From https://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
|
||||
* we should be able to parse files having:
|
||||
*
|
||||
* white-space
|
||||
|
|
@ -64,14 +64,14 @@ class PoFileLoader extends FileLoader
|
|||
{
|
||||
$stream = fopen($resource, 'r');
|
||||
|
||||
$defaults = array(
|
||||
'ids' => array(),
|
||||
$defaults = [
|
||||
'ids' => [],
|
||||
'translated' => null,
|
||||
);
|
||||
];
|
||||
|
||||
$messages = array();
|
||||
$messages = [];
|
||||
$item = $defaults;
|
||||
$flags = array();
|
||||
$flags = [];
|
||||
|
||||
while ($line = fgets($stream)) {
|
||||
$line = trim($line);
|
||||
|
|
@ -82,7 +82,7 @@ class PoFileLoader extends FileLoader
|
|||
$this->addMessage($messages, $item);
|
||||
}
|
||||
$item = $defaults;
|
||||
$flags = array();
|
||||
$flags = [];
|
||||
} elseif ('#,' === substr($line, 0, 2)) {
|
||||
$flags = array_map('trim', explode(',', substr($line, 2)));
|
||||
} elseif ('msgid "' === substr($line, 0, 7)) {
|
||||
|
|
@ -126,23 +126,24 @@ class PoFileLoader extends FileLoader
|
|||
*/
|
||||
private function addMessage(array &$messages, array $item)
|
||||
{
|
||||
if (\is_array($item['translated'])) {
|
||||
$messages[stripcslashes($item['ids']['singular'])] = stripcslashes($item['translated'][0]);
|
||||
if (!empty($item['ids']['singular'])) {
|
||||
$id = stripcslashes($item['ids']['singular']);
|
||||
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));
|
||||
$id .= '|'.stripcslashes($item['ids']['plural']);
|
||||
}
|
||||
} elseif (!empty($item['ids']['singular'])) {
|
||||
$messages[stripcslashes($item['ids']['singular'])] = stripcslashes($item['translated']);
|
||||
|
||||
$translated = (array) $item['translated'];
|
||||
// PO are by definition indexed so sort by index.
|
||||
ksort($translated);
|
||||
// Make sure every index is filled.
|
||||
end($translated);
|
||||
$count = key($translated);
|
||||
// Fill missing spots with '-'.
|
||||
$empties = array_fill(0, $count + 1, '-');
|
||||
$translated += $empties;
|
||||
ksort($translated);
|
||||
|
||||
$messages[$id] = stripcslashes(implode('|', $translated));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ namespace Symfony\Component\Translation\Loader;
|
|||
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Config\Util\XmlUtils;
|
||||
use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Util\XliffUtils;
|
||||
|
||||
/**
|
||||
* XliffFileLoader loads translations from XLIFF files.
|
||||
|
|
@ -48,7 +48,7 @@ class XliffFileLoader implements LoaderInterface
|
|||
return $catalogue;
|
||||
}
|
||||
|
||||
private function extract($resource, MessageCatalogue $catalogue, $domain)
|
||||
private function extract($resource, MessageCatalogue $catalogue, string $domain)
|
||||
{
|
||||
try {
|
||||
$dom = XmlUtils::loadFile($resource);
|
||||
|
|
@ -56,8 +56,10 @@ class XliffFileLoader implements LoaderInterface
|
|||
throw new InvalidResourceException(sprintf('Unable to load "%s": %s', $resource, $e->getMessage()), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$xliffVersion = $this->getVersionNumber($dom);
|
||||
$this->validateSchema($xliffVersion, $dom, $this->getSchema($xliffVersion));
|
||||
$xliffVersion = XliffUtils::getVersionNumber($dom);
|
||||
if ($errors = XliffUtils::validateSchema($dom)) {
|
||||
throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: %s', $resource, XliffUtils::getErrorsAsString($errors)));
|
||||
}
|
||||
|
||||
if ('1.2' === $xliffVersion) {
|
||||
$this->extractXliff1($dom, $catalogue, $domain);
|
||||
|
|
@ -70,57 +72,61 @@ class XliffFileLoader implements LoaderInterface
|
|||
|
||||
/**
|
||||
* Extract messages and metadata from DOMDocument into a MessageCatalogue.
|
||||
*
|
||||
* @param \DOMDocument $dom Source to extract messages and metadata
|
||||
* @param MessageCatalogue $catalogue Catalogue where we'll collect messages and metadata
|
||||
* @param string $domain The domain
|
||||
*/
|
||||
private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, $domain)
|
||||
private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
|
||||
{
|
||||
$xml = simplexml_import_dom($dom);
|
||||
$encoding = strtoupper($dom->encoding);
|
||||
|
||||
$xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
|
||||
foreach ($xml->xpath('//xliff:trans-unit') as $translation) {
|
||||
$attributes = $translation->attributes();
|
||||
$namespace = 'urn:oasis:names:tc:xliff:document:1.2';
|
||||
$xml->registerXPathNamespace('xliff', $namespace);
|
||||
|
||||
if (!(isset($attributes['resname']) || isset($translation->source))) {
|
||||
continue;
|
||||
}
|
||||
foreach ($xml->xpath('//xliff:file') as $file) {
|
||||
$fileAttributes = $file->attributes();
|
||||
|
||||
$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);
|
||||
$file->registerXPathNamespace('xliff', $namespace);
|
||||
|
||||
$catalogue->set((string) $source, $target, $domain);
|
||||
foreach ($file->xpath('.//xliff:trans-unit') as $translation) {
|
||||
$attributes = $translation->attributes();
|
||||
|
||||
$metadata = array();
|
||||
if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) {
|
||||
$metadata['notes'] = $notes;
|
||||
}
|
||||
|
||||
if (isset($translation->target) && $translation->target->attributes()) {
|
||||
$metadata['target-attributes'] = array();
|
||||
foreach ($translation->target->attributes() as $key => $value) {
|
||||
$metadata['target-attributes'][$key] = (string) $value;
|
||||
if (!(isset($attributes['resname']) || isset($translation->source))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($attributes['id'])) {
|
||||
$metadata['id'] = (string) $attributes['id'];
|
||||
}
|
||||
$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) ($translation->target ?? $translation->source), $encoding);
|
||||
|
||||
$catalogue->setMetadata((string) $source, $metadata, $domain);
|
||||
$catalogue->set((string) $source, $target, $domain);
|
||||
|
||||
$metadata = [
|
||||
'source' => (string) $translation->source,
|
||||
'file' => [
|
||||
'original' => (string) $fileAttributes['original'],
|
||||
],
|
||||
];
|
||||
if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) {
|
||||
$metadata['notes'] = $notes;
|
||||
}
|
||||
|
||||
if (isset($translation->target) && $translation->target->attributes()) {
|
||||
$metadata['target-attributes'] = [];
|
||||
foreach ($translation->target->attributes() as $key => $value) {
|
||||
$metadata['target-attributes'][$key] = (string) $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($attributes['id'])) {
|
||||
$metadata['id'] = (string) $attributes['id'];
|
||||
}
|
||||
|
||||
$catalogue->setMetadata((string) $source, $metadata, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMDocument $dom
|
||||
* @param MessageCatalogue $catalogue
|
||||
* @param string $domain
|
||||
*/
|
||||
private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, $domain)
|
||||
private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
|
||||
{
|
||||
$xml = simplexml_import_dom($dom);
|
||||
$encoding = strtoupper($dom->encoding);
|
||||
|
|
@ -137,18 +143,18 @@ class XliffFileLoader implements LoaderInterface
|
|||
|
||||
$catalogue->set((string) $source, $target, $domain);
|
||||
|
||||
$metadata = array();
|
||||
$metadata = [];
|
||||
if (isset($segment->target) && $segment->target->attributes()) {
|
||||
$metadata['target-attributes'] = array();
|
||||
$metadata['target-attributes'] = [];
|
||||
foreach ($segment->target->attributes() as $key => $value) {
|
||||
$metadata['target-attributes'][$key] = (string) $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($unit->notes)) {
|
||||
$metadata['notes'] = array();
|
||||
$metadata['notes'] = [];
|
||||
foreach ($unit->notes->note as $noteNode) {
|
||||
$note = array();
|
||||
$note = [];
|
||||
foreach ($noteNode->attributes() as $key => $value) {
|
||||
$note[$key] = (string) $value;
|
||||
}
|
||||
|
|
@ -164,13 +170,8 @@ class XliffFileLoader implements LoaderInterface
|
|||
|
||||
/**
|
||||
* 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)
|
||||
private function utf8ToCharset(string $content, string $encoding = null): string
|
||||
{
|
||||
if ('UTF-8' !== $encoding && !empty($encoding)) {
|
||||
return mb_convert_encoding($content, $encoding, 'UTF-8');
|
||||
|
|
@ -179,149 +180,9 @@ class XliffFileLoader implements LoaderInterface
|
|||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and parses the given file into a DOMDocument.
|
||||
*
|
||||
* @param string $file
|
||||
* @param \DOMDocument $dom
|
||||
* @param string $schema source of the schema
|
||||
*
|
||||
* @throws InvalidResourceException
|
||||
*/
|
||||
private function validateSchema($file, \DOMDocument $dom, $schema)
|
||||
private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, string $encoding = null): array
|
||||
{
|
||||
$internalErrors = libxml_use_internal_errors(true);
|
||||
|
||||
$disableEntities = libxml_disable_entity_loader(false);
|
||||
|
||||
if (!@$dom->schemaValidateSource($schema)) {
|
||||
libxml_disable_entity_loader($disableEntities);
|
||||
|
||||
throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: %s', $file, implode("\n", $this->getXmlErrors($internalErrors))));
|
||||
}
|
||||
|
||||
libxml_disable_entity_loader($disableEntities);
|
||||
|
||||
$dom->normalizeDocument();
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
}
|
||||
|
||||
private function getSchema($xliffVersion)
|
||||
{
|
||||
if ('1.2' === $xliffVersion) {
|
||||
$schemaSource = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-1.2-strict.xsd');
|
||||
$xmlUri = 'http://www.w3.org/2001/xml.xsd';
|
||||
} elseif ('2.0' === $xliffVersion) {
|
||||
$schemaSource = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-2.0.xsd');
|
||||
$xmlUri = 'informativeCopiesOf3rdPartySchemas/w3c/xml.xsd';
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf('No support implemented for loading XLIFF version "%s".', $xliffVersion));
|
||||
}
|
||||
|
||||
return $this->fixXmlLocation($schemaSource, $xmlUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internally changes the URI of a dependent xsd to be loaded locally.
|
||||
*
|
||||
* @param string $schemaSource Current content of schema file
|
||||
* @param string $xmlUri External URI of XML to convert to local
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function fixXmlLocation($schemaSource, $xmlUri)
|
||||
{
|
||||
$newPath = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
|
||||
$parts = explode('/', $newPath);
|
||||
$locationstart = 'file:///';
|
||||
if (0 === stripos($newPath, 'phar://')) {
|
||||
$tmpfile = tempnam(sys_get_temp_dir(), 'symfony');
|
||||
if ($tmpfile) {
|
||||
copy($newPath, $tmpfile);
|
||||
$parts = explode('/', str_replace('\\', '/', $tmpfile));
|
||||
} else {
|
||||
array_shift($parts);
|
||||
$locationstart = 'phar:///';
|
||||
}
|
||||
}
|
||||
|
||||
$drive = '\\' === \DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
|
||||
$newPath = $locationstart.$drive.implode('/', array_map('rawurlencode', $parts));
|
||||
|
||||
return str_replace($xmlUri, $newPath, $schemaSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets xliff file version based on the root "version" attribute.
|
||||
* Defaults to 1.2 for backwards compatibility.
|
||||
*
|
||||
* @param \DOMDocument $dom
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getVersionNumber(\DOMDocument $dom)
|
||||
{
|
||||
/** @var \DOMNode $xliff */
|
||||
foreach ($dom->getElementsByTagName('xliff') as $xliff) {
|
||||
$version = $xliff->attributes->getNamedItem('version');
|
||||
if ($version) {
|
||||
return $version->nodeValue;
|
||||
}
|
||||
|
||||
$namespace = $xliff->attributes->getNamedItem('xmlns');
|
||||
if ($namespace) {
|
||||
if (0 !== substr_compare('urn:oasis:names:tc:xliff:document:', $namespace->nodeValue, 0, 34)) {
|
||||
throw new InvalidArgumentException(sprintf('Not a valid XLIFF namespace "%s"', $namespace));
|
||||
}
|
||||
|
||||
return substr($namespace, 34);
|
||||
}
|
||||
}
|
||||
|
||||
// Falls back to v1.2
|
||||
return '1.2';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SimpleXMLElement|null $noteElement
|
||||
* @param string|null $encoding
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, $encoding = null)
|
||||
{
|
||||
$notes = array();
|
||||
$notes = [];
|
||||
|
||||
if (null === $noteElement) {
|
||||
return $notes;
|
||||
|
|
@ -330,7 +191,7 @@ class XliffFileLoader implements LoaderInterface
|
|||
/** @var \SimpleXMLElement $xmlNote */
|
||||
foreach ($noteElement as $xmlNote) {
|
||||
$noteAttributes = $xmlNote->attributes();
|
||||
$note = array('content' => $this->utf8ToCharset((string) $xmlNote, $encoding));
|
||||
$note = ['content' => $this->utf8ToCharset((string) $xmlNote, $encoding)];
|
||||
if (isset($noteAttributes['priority'])) {
|
||||
$note['priority'] = (int) $noteAttributes['priority'];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use Symfony\Component\Translation\Exception\InvalidResourceException;
|
|||
use Symfony\Component\Translation\Exception\LogicException;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Parser as YamlParser;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* YamlFileLoader loads translations from Yaml files.
|
||||
|
|
@ -38,20 +39,16 @@ class YamlFileLoader extends FileLoader
|
|||
$this->yamlParser = new YamlParser();
|
||||
}
|
||||
|
||||
$prevErrorHandler = set_error_handler(function ($level, $message, $script, $line) use ($resource, &$prevErrorHandler) {
|
||||
$message = E_USER_DEPRECATED === $level ? preg_replace('/ on line \d+/', ' in "'.$resource.'"$0', $message) : $message;
|
||||
|
||||
return $prevErrorHandler ? $prevErrorHandler($level, $message, $script, $line) : false;
|
||||
});
|
||||
|
||||
try {
|
||||
$messages = $this->yamlParser->parseFile($resource);
|
||||
$messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT);
|
||||
} catch (ParseException $e) {
|
||||
throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $resource), 0, $e);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
return $messages;
|
||||
if (null !== $messages && !\is_array($messages)) {
|
||||
throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource));
|
||||
}
|
||||
|
||||
return $messages ?: [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,411 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
XLIFF Version 2.0
|
||||
OASIS Standard
|
||||
05 August 2014
|
||||
Copyright (c) OASIS Open 2014. All rights reserved.
|
||||
Source: http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/schemas/
|
||||
-->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
xmlns:xlf="urn:oasis:names:tc:xliff:document:2.0"
|
||||
targetNamespace="urn:oasis:names:tc:xliff:document:2.0">
|
||||
|
||||
<!-- Import -->
|
||||
|
||||
<xs:import namespace="http://www.w3.org/XML/1998/namespace"
|
||||
schemaLocation="informativeCopiesOf3rdPartySchemas/w3c/xml.xsd"/>
|
||||
|
||||
<!-- Element Group -->
|
||||
|
||||
<xs:group name="inline">
|
||||
<xs:choice>
|
||||
<xs:element ref="xlf:cp"/>
|
||||
<xs:element ref="xlf:ph"/>
|
||||
<xs:element ref="xlf:pc"/>
|
||||
<xs:element ref="xlf:sc"/>
|
||||
<xs:element ref="xlf:ec"/>
|
||||
<xs:element ref="xlf:mrk"/>
|
||||
<xs:element ref="xlf:sm"/>
|
||||
<xs:element ref="xlf:em"/>
|
||||
</xs:choice>
|
||||
</xs:group>
|
||||
|
||||
<!-- Attribute Types -->
|
||||
|
||||
<xs:simpleType name="yesNo">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="yes"/>
|
||||
<xs:enumeration value="no"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="yesNoFirstNo">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="yes"/>
|
||||
<xs:enumeration value="firstNo"/>
|
||||
<xs:enumeration value="no"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="dirValue">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="ltr"/>
|
||||
<xs:enumeration value="rtl"/>
|
||||
<xs:enumeration value="auto"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="appliesTo">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="source"/>
|
||||
<xs:enumeration value="target"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="userDefinedValue">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[^\s:]+:[^\s:]+"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="attrType_type">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="fmt"/>
|
||||
<xs:enumeration value="ui"/>
|
||||
<xs:enumeration value="quote"/>
|
||||
<xs:enumeration value="link"/>
|
||||
<xs:enumeration value="image"/>
|
||||
<xs:enumeration value="other"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="typeForMrkValues">
|
||||
<xs:restriction base="xs:NMTOKEN">
|
||||
<xs:enumeration value="generic"/>
|
||||
<xs:enumeration value="comment"/>
|
||||
<xs:enumeration value="term"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="attrType_typeForMrk">
|
||||
<xs:union memberTypes="xlf:typeForMrkValues xlf:userDefinedValue"/>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="priorityValue">
|
||||
<xs:restriction base="xs:positiveInteger">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="10"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="stateType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="initial"/>
|
||||
<xs:enumeration value="translated"/>
|
||||
<xs:enumeration value="reviewed"/>
|
||||
<xs:enumeration value="final"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<!-- Structural Elements -->
|
||||
|
||||
<xs:element name="xliff">
|
||||
<xs:complexType mixed="false">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="1" maxOccurs="unbounded" ref="xlf:file"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="version" use="required"/>
|
||||
<xs:attribute name="srcLang" use="required"/>
|
||||
<xs:attribute name="trgLang" use="optional"/>
|
||||
<xs:attribute ref="xml:space" use="optional" default="default"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="file">
|
||||
<xs:complexType mixed="false">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="xlf:skeleton"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"
|
||||
processContents="lax"/>
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="xlf:notes"/>
|
||||
<xs:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:element ref="xlf:unit"/>
|
||||
<xs:element ref="xlf:group"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="canResegment" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="original" use="optional"/>
|
||||
<xs:attribute name="translate" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="srcDir" use="optional" type="xlf:dirValue" default="auto"/>
|
||||
<xs:attribute name="trgDir" use="optional" type="xlf:dirValue" default="auto"/>
|
||||
<xs:attribute ref="xml:space" use="optional"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="skeleton">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:sequence>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"
|
||||
processContents="lax"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="href" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="group">
|
||||
<xs:complexType mixed="false">
|
||||
<xs:sequence>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"
|
||||
processContents="lax"/>
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="xlf:notes"/>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="xlf:unit"/>
|
||||
<xs:element ref="xlf:group"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="name" use="optional"/>
|
||||
<xs:attribute name="canResegment" use="optional" type="xlf:yesNo"/>
|
||||
<xs:attribute name="translate" use="optional" type="xlf:yesNo"/>
|
||||
<xs:attribute name="srcDir" use="optional" type="xlf:dirValue"/>
|
||||
<xs:attribute name="trgDir" use="optional" type="xlf:dirValue"/>
|
||||
<xs:attribute name="type" use="optional" type="xlf:userDefinedValue"/>
|
||||
<xs:attribute ref="xml:space" use="optional"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="unit">
|
||||
<xs:complexType mixed="false">
|
||||
<xs:sequence>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"
|
||||
processContents="lax"/>
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="xlf:notes"/>
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="xlf:originalData"/>
|
||||
<xs:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:element ref="xlf:segment"/>
|
||||
<xs:element ref="xlf:ignorable"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="name" use="optional"/>
|
||||
<xs:attribute name="canResegment" use="optional" type="xlf:yesNo"/>
|
||||
<xs:attribute name="translate" use="optional" type="xlf:yesNo"/>
|
||||
<xs:attribute name="srcDir" use="optional" type="xlf:dirValue"/>
|
||||
<xs:attribute name="trgDir" use="optional" type="xlf:dirValue"/>
|
||||
<xs:attribute ref="xml:space" use="optional"/>
|
||||
<xs:attribute name="type" use="optional" type="xlf:userDefinedValue"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="segment">
|
||||
<xs:complexType mixed="false">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="1" maxOccurs="1" ref="xlf:source"/>
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="xlf:target"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="canResegment" use="optional" type="xlf:yesNo"/>
|
||||
<xs:attribute name="state" use="optional" type="xlf:stateType" default="initial"/>
|
||||
<xs:attribute name="subState" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="ignorable">
|
||||
<xs:complexType mixed="false">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="1" maxOccurs="1" ref="xlf:source"/>
|
||||
<xs:element minOccurs="0" maxOccurs="1" ref="xlf:target"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" use="optional" type="xs:NMTOKEN"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="notes">
|
||||
<xs:complexType mixed="false">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="1" maxOccurs="unbounded" ref="xlf:note"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="note">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:attribute name="id" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="appliesTo" use="optional" type="xlf:appliesTo"/>
|
||||
<xs:attribute name="category" use="optional"/>
|
||||
<xs:attribute name="priority" use="optional" type="xlf:priorityValue" default="1"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="originalData">
|
||||
<xs:complexType mixed="false">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="1" maxOccurs="unbounded" ref="xlf:data"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="data">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="xlf:cp"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dir" use="optional" type="xlf:dirValue" default="auto"/>
|
||||
<xs:attribute ref="xml:space" use="optional" fixed="preserve"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="source">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:group ref="xlf:inline" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:attribute ref="xml:lang" use="optional"/>
|
||||
<xs:attribute ref="xml:space" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="target">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:group ref="xlf:inline" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:attribute ref="xml:lang" use="optional"/>
|
||||
<xs:attribute ref="xml:space" use="optional"/>
|
||||
<xs:attribute name="order" use="optional" type="xs:positiveInteger"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<!-- Inline Elements -->
|
||||
|
||||
<xs:element name="cp">
|
||||
<!-- Code Point -->
|
||||
<xs:complexType mixed="false">
|
||||
<xs:attribute name="hex" use="required" type="xs:hexBinary"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="ph">
|
||||
<!-- Placeholder -->
|
||||
<xs:complexType mixed="false">
|
||||
<xs:attribute name="canCopy" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canDelete" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canReorder" use="optional" type="xlf:yesNoFirstNo" default="yes"/>
|
||||
<xs:attribute name="copyOf" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="disp" use="optional"/>
|
||||
<xs:attribute name="equiv" use="optional"/>
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dataRef" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="subFlows" use="optional" type="xs:NMTOKENS"/>
|
||||
<xs:attribute name="subType" use="optional" type="xlf:userDefinedValue"/>
|
||||
<xs:attribute name="type" use="optional" type="xlf:attrType_type"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="pc">
|
||||
<!-- Paired Code -->
|
||||
<xs:complexType mixed="true">
|
||||
<xs:group ref="xlf:inline" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:attribute name="canCopy" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canDelete" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canOverlap" use="optional" type="xlf:yesNo"/>
|
||||
<xs:attribute name="canReorder" use="optional" type="xlf:yesNoFirstNo" default="yes"/>
|
||||
<xs:attribute name="copyOf" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dispEnd" use="optional"/>
|
||||
<xs:attribute name="dispStart" use="optional"/>
|
||||
<xs:attribute name="equivEnd" use="optional"/>
|
||||
<xs:attribute name="equivStart" use="optional"/>
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dataRefEnd" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dataRefStart" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="subFlowsEnd" use="optional" type="xs:NMTOKENS"/>
|
||||
<xs:attribute name="subFlowsStart" use="optional" type="xs:NMTOKENS"/>
|
||||
<xs:attribute name="subType" use="optional" type="xlf:userDefinedValue"/>
|
||||
<xs:attribute name="type" use="optional" type="xlf:attrType_type"/>
|
||||
<xs:attribute name="dir" use="optional" type="xlf:dirValue"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="sc">
|
||||
<!-- Start Code -->
|
||||
<xs:complexType mixed="false">
|
||||
<xs:attribute name="canCopy" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canDelete" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canOverlap" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canReorder" use="optional" type="xlf:yesNoFirstNo" default="yes"/>
|
||||
<xs:attribute name="copyOf" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dataRef" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dir" use="optional" type="xlf:dirValue"/>
|
||||
<xs:attribute name="disp" use="optional"/>
|
||||
<xs:attribute name="equiv" use="optional"/>
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="isolated" use="optional" type="xlf:yesNo" default="no"/>
|
||||
<xs:attribute name="subFlows" use="optional" type="xs:NMTOKENS"/>
|
||||
<xs:attribute name="subType" use="optional" type="xlf:userDefinedValue"/>
|
||||
<xs:attribute name="type" use="optional" type="xlf:attrType_type"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="ec">
|
||||
<!-- End Code -->
|
||||
<xs:complexType mixed="false">
|
||||
<xs:attribute name="canCopy" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canDelete" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canOverlap" use="optional" type="xlf:yesNo" default="yes"/>
|
||||
<xs:attribute name="canReorder" use="optional" type="xlf:yesNoFirstNo" default="yes"/>
|
||||
<xs:attribute name="copyOf" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dataRef" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="dir" use="optional" type="xlf:dirValue"/>
|
||||
<xs:attribute name="disp" use="optional"/>
|
||||
<xs:attribute name="equiv" use="optional"/>
|
||||
<xs:attribute name="id" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="isolated" use="optional" type="xlf:yesNo" default="no"/>
|
||||
<xs:attribute name="startRef" use="optional" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="subFlows" use="optional" type="xs:NMTOKENS"/>
|
||||
<xs:attribute name="subType" use="optional" type="xlf:userDefinedValue"/>
|
||||
<xs:attribute name="type" use="optional" type="xlf:attrType_type"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="mrk">
|
||||
<!-- Annotation Marker -->
|
||||
<xs:complexType mixed="true">
|
||||
<xs:group ref="xlf:inline" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="translate" use="optional" type="xlf:yesNo"/>
|
||||
<xs:attribute name="type" use="optional" type="xlf:attrType_typeForMrk"/>
|
||||
<xs:attribute name="ref" use="optional" type="xs:anyURI"/>
|
||||
<xs:attribute name="value" use="optional"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="sm">
|
||||
<!-- Start Annotation Marker -->
|
||||
<xs:complexType mixed="false">
|
||||
<xs:attribute name="id" use="required" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="translate" use="optional" type="xlf:yesNo"/>
|
||||
<xs:attribute name="type" use="optional" type="xlf:attrType_typeForMrk"/>
|
||||
<xs:attribute name="ref" use="optional" type="xs:anyURI"/>
|
||||
<xs:attribute name="value" use="optional"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="em">
|
||||
<!-- End Annotation Marker -->
|
||||
<xs:complexType mixed="false">
|
||||
<xs:attribute name="startRef" use="required" type="xs:NMTOKEN"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
||||
|
|
@ -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>
|
||||
|
|
@ -13,11 +13,14 @@ namespace Symfony\Component\Translation;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
|
||||
use Symfony\Contracts\Translation\LocaleAwareInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
*/
|
||||
class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
||||
class LoggingTranslator implements TranslatorInterface, LegacyTranslatorInterface, TranslatorBagInterface
|
||||
{
|
||||
/**
|
||||
* @var TranslatorInterface|TranslatorBagInterface
|
||||
|
|
@ -28,12 +31,14 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
|||
|
||||
/**
|
||||
* @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator, LoggerInterface $logger)
|
||||
public function __construct($translator, LoggerInterface $logger)
|
||||
{
|
||||
if (!$translator instanceof TranslatorBagInterface) {
|
||||
throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface and TranslatorBagInterface.', \get_class($translator)));
|
||||
if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
|
||||
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
|
||||
}
|
||||
if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) {
|
||||
throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', \get_class($translator)));
|
||||
}
|
||||
|
||||
$this->translator = $translator;
|
||||
|
|
@ -43,7 +48,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
|
||||
public function trans($id, array $parameters = [], $domain = null, $locale = null)
|
||||
{
|
||||
$trans = $this->translator->trans($id, $parameters, $domain, $locale);
|
||||
$this->log($id, $domain, $locale);
|
||||
|
|
@ -53,10 +58,19 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
|||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
|
||||
*/
|
||||
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
|
||||
public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
|
||||
{
|
||||
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
if ($this->translator instanceof TranslatorInterface) {
|
||||
$trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
|
||||
} else {
|
||||
$trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
|
||||
}
|
||||
|
||||
$this->log($id, $domain, $locale);
|
||||
|
||||
return $trans;
|
||||
|
|
@ -67,7 +81,13 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
|||
*/
|
||||
public function setLocale($locale)
|
||||
{
|
||||
$prev = $this->translator->getLocale();
|
||||
$this->translator->setLocale($locale);
|
||||
if ($prev === $locale) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->debug(sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,7 +109,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
|||
/**
|
||||
* Gets the fallback locales.
|
||||
*
|
||||
* @return array $locales The fallback locales
|
||||
* @return array The fallback locales
|
||||
*/
|
||||
public function getFallbackLocales()
|
||||
{
|
||||
|
|
@ -97,7 +117,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
|||
return $this->translator->getFallbackLocales();
|
||||
}
|
||||
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -105,17 +125,13 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
|||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return \call_user_func_array(array($this->translator, $method), $args);
|
||||
return $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)
|
||||
private function log(?string $id, ?string $domain, ?string $locale)
|
||||
{
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
|
|
@ -128,9 +144,9 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface
|
|||
}
|
||||
|
||||
if ($catalogue->has($id, $domain)) {
|
||||
$this->logger->debug('Translation use fallback catalogue.', array('id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()));
|
||||
$this->logger->debug('Translation use fallback catalogue.', ['id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()]);
|
||||
} else {
|
||||
$this->logger->warning('Translation not found.', array('id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()));
|
||||
$this->logger->warning('Translation not found.', ['id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ use Symfony\Component\Translation\Exception\LogicException;
|
|||
*/
|
||||
class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface
|
||||
{
|
||||
private $messages = array();
|
||||
private $metadata = array();
|
||||
private $resources = array();
|
||||
private $messages = [];
|
||||
private $metadata = [];
|
||||
private $resources = [];
|
||||
private $locale;
|
||||
private $fallbackCatalogue;
|
||||
private $parent;
|
||||
|
|
@ -30,8 +30,12 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
* @param string $locale The locale
|
||||
* @param array $messages An array of messages classified by domain
|
||||
*/
|
||||
public function __construct($locale, array $messages = array())
|
||||
public function __construct(?string $locale, array $messages = [])
|
||||
{
|
||||
if (null === $locale) {
|
||||
@trigger_error(sprintf('Passing "null" to the first argument of the "%s" method has been deprecated since Symfony 4.4 and will throw an error in 5.0.', __METHOD__), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
$this->locale = $locale;
|
||||
$this->messages = $messages;
|
||||
}
|
||||
|
|
@ -49,7 +53,17 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
*/
|
||||
public function getDomains()
|
||||
{
|
||||
return array_keys($this->messages);
|
||||
$domains = [];
|
||||
$suffixLength = \strlen(self::INTL_DOMAIN_SUFFIX);
|
||||
|
||||
foreach ($this->messages as $domain => $messages) {
|
||||
if (\strlen($domain) > $suffixLength && false !== $i = strpos($domain, self::INTL_DOMAIN_SUFFIX, -$suffixLength)) {
|
||||
$domain = substr($domain, 0, $i);
|
||||
}
|
||||
$domains[$domain] = $domain;
|
||||
}
|
||||
|
||||
return array_values($domains);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -57,11 +71,23 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
*/
|
||||
public function all($domain = null)
|
||||
{
|
||||
if (null === $domain) {
|
||||
return $this->messages;
|
||||
if (null !== $domain) {
|
||||
return ($this->messages[$domain.self::INTL_DOMAIN_SUFFIX] ?? []) + ($this->messages[$domain] ?? []);
|
||||
}
|
||||
|
||||
return isset($this->messages[$domain]) ? $this->messages[$domain] : array();
|
||||
$allMessages = [];
|
||||
$suffixLength = \strlen(self::INTL_DOMAIN_SUFFIX);
|
||||
|
||||
foreach ($this->messages as $domain => $messages) {
|
||||
if (\strlen($domain) > $suffixLength && false !== $i = strpos($domain, self::INTL_DOMAIN_SUFFIX, -$suffixLength)) {
|
||||
$domain = substr($domain, 0, $i);
|
||||
$allMessages[$domain] = $messages + ($allMessages[$domain] ?? []);
|
||||
} else {
|
||||
$allMessages[$domain] = ($allMessages[$domain] ?? []) + $messages;
|
||||
}
|
||||
}
|
||||
|
||||
return $allMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -69,7 +95,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
*/
|
||||
public function set($id, $translation, $domain = 'messages')
|
||||
{
|
||||
$this->add(array($id => $translation), $domain);
|
||||
$this->add([$id => $translation], $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -77,7 +103,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
*/
|
||||
public function has($id, $domain = 'messages')
|
||||
{
|
||||
if (isset($this->messages[$domain][$id])) {
|
||||
if (isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +119,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
*/
|
||||
public function defines($id, $domain = 'messages')
|
||||
{
|
||||
return isset($this->messages[$domain][$id]);
|
||||
return isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -101,6 +127,10 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
*/
|
||||
public function get($id, $domain = 'messages')
|
||||
{
|
||||
if (isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {
|
||||
return $this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id];
|
||||
}
|
||||
|
||||
if (isset($this->messages[$domain][$id])) {
|
||||
return $this->messages[$domain][$id];
|
||||
}
|
||||
|
|
@ -117,7 +147,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
*/
|
||||
public function replace($messages, $domain = 'messages')
|
||||
{
|
||||
$this->messages[$domain] = array();
|
||||
unset($this->messages[$domain], $this->messages[$domain.self::INTL_DOMAIN_SUFFIX]);
|
||||
|
||||
$this->add($messages, $domain);
|
||||
}
|
||||
|
|
@ -144,6 +174,10 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
}
|
||||
|
||||
foreach ($catalogue->all() as $domain => $messages) {
|
||||
if ($intlMessages = $catalogue->all($domain.self::INTL_DOMAIN_SUFFIX)) {
|
||||
$this->add($intlMessages, $domain.self::INTL_DOMAIN_SUFFIX);
|
||||
$messages = array_diff_key($messages, $intlMessages);
|
||||
}
|
||||
$this->add($messages, $domain);
|
||||
}
|
||||
|
||||
|
|
@ -231,6 +265,8 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
return $this->metadata[$domain][$key];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -247,7 +283,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
|||
public function deleteMetadata($key = '', $domain = 'messages')
|
||||
{
|
||||
if ('' == $domain) {
|
||||
$this->metadata = array();
|
||||
$this->metadata = [];
|
||||
} elseif ('' == $key) {
|
||||
unset($this->metadata[$domain]);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ use Symfony\Component\Config\Resource\ResourceInterface;
|
|||
*/
|
||||
interface MessageCatalogueInterface
|
||||
{
|
||||
const INTL_DOMAIN_SUFFIX = '+intl-icu';
|
||||
|
||||
/**
|
||||
* Gets the catalogue locale.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2, use IdentityTranslator instead.', MessageSelector::class), E_USER_DEPRECATED);
|
||||
|
||||
use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
|
|
@ -18,6 +20,8 @@ use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
|||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @deprecated since Symfony 4.2, use IdentityTranslator instead.
|
||||
*/
|
||||
class MessageSelector
|
||||
{
|
||||
|
|
@ -39,9 +43,9 @@ class MessageSelector
|
|||
* 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
|
||||
* @param string $message The message being translated
|
||||
* @param int|float $number The number of items represented for the message
|
||||
* @param string $locale The locale to use for choosing
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
|
|
@ -49,15 +53,15 @@ class MessageSelector
|
|||
*/
|
||||
public function choose($message, $number, $locale)
|
||||
{
|
||||
$parts = array();
|
||||
$parts = [];
|
||||
if (preg_match('/^\|++$/', $message)) {
|
||||
$parts = explode('|', $message);
|
||||
} elseif (preg_match_all('/(?:\|\||[^\|])++/', $message, $matches)) {
|
||||
$parts = $matches[0];
|
||||
}
|
||||
|
||||
$explicitRules = array();
|
||||
$standardRules = array();
|
||||
$explicitRules = [];
|
||||
$standardRules = [];
|
||||
foreach ($parts as $part) {
|
||||
$part = trim(str_replace('||', '|', $part));
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ namespace Symfony\Component\Translation;
|
|||
* Returns the plural rules for a given locale.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Symfony 4.2, use IdentityTranslator instead
|
||||
*/
|
||||
class PluralizationRules
|
||||
{
|
||||
private static $rules = array();
|
||||
private static $rules = [];
|
||||
|
||||
/**
|
||||
* Returns the plural position to use for the given locale and number.
|
||||
|
|
@ -28,8 +30,12 @@ class PluralizationRules
|
|||
*
|
||||
* @return int The plural position
|
||||
*/
|
||||
public static function get($number, $locale)
|
||||
public static function get($number, $locale/*, bool $triggerDeprecation = true*/)
|
||||
{
|
||||
if (3 > \func_num_args() || func_get_arg(2)) {
|
||||
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
if ('pt_BR' === $locale) {
|
||||
// temporary set a locale for brazilian
|
||||
$locale = 'xbr';
|
||||
|
|
@ -40,7 +46,7 @@ class PluralizationRules
|
|||
}
|
||||
|
||||
if (isset(self::$rules[$locale])) {
|
||||
$return = \call_user_func(self::$rules[$locale], $number);
|
||||
$return = self::$rules[$locale]($number);
|
||||
|
||||
if (!\is_int($return) || $return < 0) {
|
||||
return 0;
|
||||
|
|
@ -196,6 +202,8 @@ class PluralizationRules
|
|||
*/
|
||||
public static function set(callable $rule, $locale)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED);
|
||||
|
||||
if ('pt_BR' === $locale) {
|
||||
// temporary set a locale for brazilian
|
||||
$locale = 'xbr';
|
||||
|
|
|
|||
|
|
@ -1,74 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
abstract class AbstractOperationTest extends 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->{method_exists($this, $_ = 'expectException') ? $_ : '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,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,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\TargetOperation;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
|
||||
class TargetOperationTest 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 TargetOperation($source, $target);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\DataCollector\TranslationDataCollector;
|
||||
use Symfony\Component\Translation\DataCollectorTranslator;
|
||||
|
||||
class TranslationDataCollectorTest extends 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()->getValue());
|
||||
}
|
||||
|
||||
public function testCollect()
|
||||
{
|
||||
$collectedMessages = array(
|
||||
array(
|
||||
'id' => 'foo',
|
||||
'translation' => 'foo (en)',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_DEFINED,
|
||||
'parameters' => array(),
|
||||
'transChoiceNumber' => null,
|
||||
),
|
||||
array(
|
||||
'id' => 'bar',
|
||||
'translation' => 'bar (fr)',
|
||||
'locale' => 'fr',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
'parameters' => array(),
|
||||
'transChoiceNumber' => null,
|
||||
),
|
||||
array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
'parameters' => array('%count%' => 3),
|
||||
'transChoiceNumber' => 3,
|
||||
),
|
||||
array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
'parameters' => array('%count%' => 3),
|
||||
'transChoiceNumber' => 3,
|
||||
),
|
||||
array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
'parameters' => array('%count%' => 4, '%foo%' => 'bar'),
|
||||
'transChoiceNumber' => 4,
|
||||
),
|
||||
);
|
||||
$expectedMessages = array(
|
||||
array(
|
||||
'id' => 'foo',
|
||||
'translation' => 'foo (en)',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_DEFINED,
|
||||
'count' => 1,
|
||||
'parameters' => array(),
|
||||
'transChoiceNumber' => null,
|
||||
),
|
||||
array(
|
||||
'id' => 'bar',
|
||||
'translation' => 'bar (fr)',
|
||||
'locale' => 'fr',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
'count' => 1,
|
||||
'parameters' => array(),
|
||||
'transChoiceNumber' => null,
|
||||
),
|
||||
array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
'count' => 3,
|
||||
'parameters' => array(
|
||||
array('%count%' => 3),
|
||||
array('%count%' => 3),
|
||||
array('%count%' => 4, '%foo%' => 'bar'),
|
||||
),
|
||||
'transChoiceNumber' => 3,
|
||||
),
|
||||
);
|
||||
|
||||
$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()->getValue(true)));
|
||||
}
|
||||
|
||||
private function getTranslator()
|
||||
{
|
||||
$translator = $this
|
||||
->getMockBuilder('Symfony\Component\Translation\DataCollectorTranslator')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
;
|
||||
|
||||
return $translator;
|
||||
}
|
||||
}
|
||||
|
|
@ -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\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\DataCollectorTranslator;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
|
||||
class DataCollectorTranslatorTest extends TestCase
|
||||
{
|
||||
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');
|
||||
$collector->trans('bar_ru', array('foo' => 'bar'));
|
||||
|
||||
$expectedMessages = array();
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'foo',
|
||||
'translation' => 'foo (en)',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_DEFINED,
|
||||
'parameters' => array(),
|
||||
'transChoiceNumber' => null,
|
||||
);
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'bar',
|
||||
'translation' => 'bar (fr)',
|
||||
'locale' => 'fr',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
'parameters' => array(),
|
||||
'transChoiceNumber' => null,
|
||||
);
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'choice',
|
||||
'translation' => 'choice',
|
||||
'locale' => 'en',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_MISSING,
|
||||
'parameters' => array(),
|
||||
'transChoiceNumber' => 0,
|
||||
);
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'bar_ru',
|
||||
'translation' => 'bar (ru)',
|
||||
'locale' => 'ru',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
'parameters' => array(),
|
||||
'transChoiceNumber' => null,
|
||||
);
|
||||
$expectedMessages[] = array(
|
||||
'id' => 'bar_ru',
|
||||
'translation' => 'bar (ru)',
|
||||
'locale' => 'ru',
|
||||
'domain' => 'messages',
|
||||
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
|
||||
'parameters' => array('foo' => 'bar'),
|
||||
'transChoiceNumber' => null,
|
||||
);
|
||||
|
||||
$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');
|
||||
|
||||
return new DataCollectorTranslator($translator);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\CsvFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class CsvFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar', 'bar' => 'foo
|
||||
foo', 'foo;foo' => 'bar'));
|
||||
|
||||
$dumper = new CsvFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/valid.csv', $dumper->formatCatalogue($catalogue, 'messages'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,89 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\FileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class FileDumperTest extends TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
$tempDir = sys_get_temp_dir();
|
||||
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new ConcreteFileDumper();
|
||||
$dumper->dump($catalogue, array('path' => $tempDir));
|
||||
|
||||
$this->assertFileExists($tempDir.'/messages.en.concrete');
|
||||
|
||||
@unlink($tempDir.'/messages.en.concrete');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
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->assertFileExists($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->assertFileExists($file);
|
||||
|
||||
@unlink($file);
|
||||
@rmdir($translationsDir);
|
||||
}
|
||||
}
|
||||
|
||||
class ConcreteFileDumper extends FileDumper
|
||||
{
|
||||
public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = array())
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function getExtension()
|
||||
{
|
||||
return 'concrete';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\IcuResFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class IcuResFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new IcuResFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/resourcebundle/res/en.res', $dumper->formatCatalogue($catalogue, 'messages'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\IniFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class IniFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new IniFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.ini', $dumper->formatCatalogue($catalogue, 'messages'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\JsonFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class JsonFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new JsonFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.json', $dumper->formatCatalogue($catalogue, 'messages'));
|
||||
}
|
||||
|
||||
public function testDumpWithCustomEncoding()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => '"bar"'));
|
||||
|
||||
$dumper = new JsonFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.dump.json', $dumper->formatCatalogue($catalogue, 'messages', array('json_encoding' => JSON_HEX_QUOT)));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\MoFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class MoFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new MoFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.mo', $dumper->formatCatalogue($catalogue, 'messages'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\PhpFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class PhpFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new PhpFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.php', $dumper->formatCatalogue($catalogue, 'messages'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\PoFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class PoFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new PoFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.po', $dumper->formatCatalogue($catalogue, 'messages'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\QtFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class QtFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(array('foo' => 'bar'), 'resources');
|
||||
|
||||
$dumper = new QtFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.ts', $dumper->formatCatalogue($catalogue, 'resources'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,115 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\XliffFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class XliffFileDumperTest extends TestCase
|
||||
{
|
||||
public function testFormatCatalogue()
|
||||
{
|
||||
$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'))));
|
||||
|
||||
$dumper = new XliffFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(
|
||||
__DIR__.'/../fixtures/resources-clean.xlf',
|
||||
$dumper->formatCatalogue($catalogue, 'messages', array('default_locale' => 'fr_FR'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatCatalogueXliff2()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en_US');
|
||||
$catalogue->add(array(
|
||||
'foo' => 'bar',
|
||||
'key' => '',
|
||||
'key.with.cdata' => '<source> & <target>',
|
||||
));
|
||||
$catalogue->setMetadata('key', array('target-attributes' => array('order' => 1)));
|
||||
|
||||
$dumper = new XliffFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(
|
||||
__DIR__.'/../fixtures/resources-2.0-clean.xlf',
|
||||
$dumper->formatCatalogue($catalogue, 'messages', array('default_locale' => 'fr_FR', 'xliff_version' => '2.0'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatCatalogueWithCustomToolInfo()
|
||||
{
|
||||
$options = array(
|
||||
'default_locale' => 'en_US',
|
||||
'tool_info' => array('tool-id' => 'foo', 'tool-name' => 'foo', 'tool-version' => '0.0', 'tool-company' => 'Foo'),
|
||||
);
|
||||
|
||||
$catalogue = new MessageCatalogue('en_US');
|
||||
$catalogue->add(array('foo' => 'bar'));
|
||||
|
||||
$dumper = new XliffFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(
|
||||
__DIR__.'/../fixtures/resources-tool-info.xlf',
|
||||
$dumper->formatCatalogue($catalogue, 'messages', $options)
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatCatalogueWithTargetAttributesMetadata()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en_US');
|
||||
$catalogue->add(array(
|
||||
'foo' => 'bar',
|
||||
));
|
||||
$catalogue->setMetadata('foo', array('target-attributes' => array('state' => 'needs-translation')));
|
||||
|
||||
$dumper = new XliffFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(
|
||||
__DIR__.'/../fixtures/resources-target-attributes.xlf',
|
||||
$dumper->formatCatalogue($catalogue, 'messages', array('default_locale' => 'fr_FR'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatCatalogueWithNotesMetadata()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en_US');
|
||||
$catalogue->add(array(
|
||||
'foo' => 'bar',
|
||||
'baz' => 'biz',
|
||||
));
|
||||
$catalogue->setMetadata('foo', array('notes' => array(
|
||||
array('category' => 'state', 'content' => 'new'),
|
||||
array('category' => 'approved', 'content' => 'true'),
|
||||
array('category' => 'section', 'content' => 'user login', 'priority' => '1'),
|
||||
)));
|
||||
$catalogue->setMetadata('baz', array('notes' => array(
|
||||
array('id' => 'x', 'content' => 'x_content'),
|
||||
array('appliesTo' => 'target', 'category' => 'quality', 'content' => 'Fuzzy'),
|
||||
)));
|
||||
|
||||
$dumper = new XliffFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(
|
||||
__DIR__.'/../fixtures/resources-notes-meta.xlf',
|
||||
$dumper->formatCatalogue($catalogue, 'messages', array('default_locale' => 'fr_FR', 'xliff_version' => '2.0'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\YamlFileDumper;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class YamlFileDumperTest extends TestCase
|
||||
{
|
||||
public function testTreeFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(
|
||||
array(
|
||||
'foo.bar1' => 'value1',
|
||||
'foo.bar2' => 'value2',
|
||||
));
|
||||
|
||||
$dumper = new YamlFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/messages.yml', $dumper->formatCatalogue($catalogue, 'messages', array('as_tree' => true, 'inline' => 999)));
|
||||
}
|
||||
|
||||
public function testLinearFormatCatalogue()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->add(
|
||||
array(
|
||||
'foo.bar1' => 'value1',
|
||||
'foo.bar2' => 'value2',
|
||||
));
|
||||
|
||||
$dumper = new YamlFileDumper();
|
||||
|
||||
$this->assertStringEqualsFile(__DIR__.'/../fixtures/messages_linear.yml', $dumper->formatCatalogue($catalogue, 'messages'));
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Intl\Util\IntlTestHelper;
|
||||
use Symfony\Component\Translation\IdentityTranslator;
|
||||
|
||||
class IdentityTranslatorTest extends 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, false);
|
||||
|
||||
$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,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;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Interval;
|
||||
|
||||
class IntervalTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getTests
|
||||
*/
|
||||
public function testTest($expected, $number, $interval)
|
||||
{
|
||||
$this->assertEquals($expected, Interval::test($number, $interval));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\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,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\Tests\Loader;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\CsvFileLoader;
|
||||
|
||||
class CsvFileLoaderTest extends 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,64 +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\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\IcuDatFileLoader;
|
||||
|
||||
/**
|
||||
* @requires extension intl
|
||||
*/
|
||||
class IcuDatFileLoaderTest extends LocalizedTestCase
|
||||
{
|
||||
/**
|
||||
* @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,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\Tests\Loader;
|
||||
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use Symfony\Component\Translation\Loader\IcuResFileLoader;
|
||||
|
||||
/**
|
||||
* @requires extension intl
|
||||
*/
|
||||
class IcuResFileLoaderTest extends LocalizedTestCase
|
||||
{
|
||||
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,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\Tests\Loader;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\IniFileLoader;
|
||||
|
||||
class IniFileLoaderTest extends 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,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\Tests\Loader;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\JsonFileLoader;
|
||||
|
||||
class JsonFileLoaderTest extends TestCase
|
||||
{
|
||||
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,24 +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 PHPUnit\Framework\TestCase;
|
||||
|
||||
abstract class LocalizedTestCase extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!\extension_loaded('intl')) {
|
||||
$this->markTestSkipped('Extension intl is required.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\MoFileLoader;
|
||||
|
||||
class MoFileLoaderTest extends 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,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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\PhpFileLoader;
|
||||
|
||||
class PhpFileLoaderTest extends 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,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\Tests\Loader;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\PoFileLoader;
|
||||
|
||||
class PoFileLoaderTest extends 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"']);
|
||||
}
|
||||
|
||||
public function testSkipFuzzyTranslations()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/fuzzy-translations.po';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$messages = $catalogue->all('domain1');
|
||||
$this->assertArrayHasKey('foo1', $messages);
|
||||
$this->assertArrayNotHasKey('foo2', $messages);
|
||||
$this->assertArrayHasKey('foo3', $messages);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\QtFileLoader;
|
||||
|
||||
class QtFileLoaderTest extends 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';
|
||||
|
||||
if (method_exists($this, 'expectException')) {
|
||||
$this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
|
||||
$this->expectExceptionMessage(sprintf('Unable to load "%s".', $resource));
|
||||
} else {
|
||||
$this->setExpectedException('Symfony\Component\Translation\Exception\InvalidResourceException', sprintf('Unable to load "%s".', $resource));
|
||||
}
|
||||
|
||||
$loader->load($resource, 'en', 'domain1');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,260 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\XliffFileLoader;
|
||||
|
||||
class XliffFileLoaderTest extends 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()
|
||||
{
|
||||
$internalErrors = 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());
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
}
|
||||
|
||||
public function testLoadWithExternalEntitiesDisabled()
|
||||
{
|
||||
$disableEntities = libxml_disable_entity_loader(true);
|
||||
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources.xlf';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
libxml_disable_entity_loader($disableEntities);
|
||||
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalogue->getResources());
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
$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'))), 'id' => '1'), $catalogue->getMetadata('foo', 'domain1'));
|
||||
}
|
||||
|
||||
public function testTargetAttributesAreStoredCorrectly()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$catalogue = $loader->load(__DIR__.'/../fixtures/with-attributes.xlf', 'en', 'domain1');
|
||||
|
||||
$metadata = $catalogue->getMetadata('foo', 'domain1');
|
||||
$this->assertEquals('translated', $metadata['target-attributes']['state']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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';
|
||||
|
||||
if (method_exists($this, 'expectException')) {
|
||||
$this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
|
||||
$this->expectExceptionMessage(sprintf('Unable to load "%s":', $resource));
|
||||
} else {
|
||||
$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')), 'id' => '1'), $catalogue->getMetadata('foo', 'domain1'));
|
||||
// message without target
|
||||
$this->assertEquals(array('notes' => array(array('content' => 'bar', 'from' => 'foo')), 'id' => '2'), $catalogue->getMetadata('extra', 'domain1'));
|
||||
// message with empty target
|
||||
$this->assertEquals(array('notes' => array(array('content' => 'baz'), array('priority' => 2, 'from' => 'bar', 'content' => 'qux')), 'id' => '123'), $catalogue->getMetadata('key', 'domain1'));
|
||||
}
|
||||
|
||||
public function testLoadVersion2()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources-2.0.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());
|
||||
|
||||
$domains = $catalogue->all();
|
||||
$this->assertCount(3, $domains['domain1']);
|
||||
$this->assertContainsOnly('string', $catalogue->all('domain1'));
|
||||
|
||||
// target attributes
|
||||
$this->assertEquals(array('target-attributes' => array('order' => 1)), $catalogue->getMetadata('bar', 'domain1'));
|
||||
}
|
||||
|
||||
public function testLoadVersion2WithNoteMeta()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources-notes-meta.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());
|
||||
|
||||
// test for "foo" metadata
|
||||
$this->assertTrue($catalogue->defines('foo', 'domain1'));
|
||||
$metadata = $catalogue->getMetadata('foo', 'domain1');
|
||||
$this->assertNotEmpty($metadata);
|
||||
$this->assertCount(3, $metadata['notes']);
|
||||
|
||||
$this->assertEquals('state', $metadata['notes'][0]['category']);
|
||||
$this->assertEquals('new', $metadata['notes'][0]['content']);
|
||||
|
||||
$this->assertEquals('approved', $metadata['notes'][1]['category']);
|
||||
$this->assertEquals('true', $metadata['notes'][1]['content']);
|
||||
|
||||
$this->assertEquals('section', $metadata['notes'][2]['category']);
|
||||
$this->assertEquals('1', $metadata['notes'][2]['priority']);
|
||||
$this->assertEquals('user login', $metadata['notes'][2]['content']);
|
||||
|
||||
// test for "baz" metadata
|
||||
$this->assertTrue($catalogue->defines('baz', 'domain1'));
|
||||
$metadata = $catalogue->getMetadata('baz', 'domain1');
|
||||
$this->assertNotEmpty($metadata);
|
||||
$this->assertCount(2, $metadata['notes']);
|
||||
|
||||
$this->assertEquals('x', $metadata['notes'][0]['id']);
|
||||
$this->assertEquals('x_content', $metadata['notes'][0]['content']);
|
||||
|
||||
$this->assertEquals('target', $metadata['notes'][1]['appliesTo']);
|
||||
$this->assertEquals('quality', $metadata['notes'][1]['category']);
|
||||
$this->assertEquals('Fuzzy', $metadata['notes'][1]['content']);
|
||||
}
|
||||
|
||||
public function testLoadVersion2WithMultiSegmentUnit()
|
||||
{
|
||||
$loader = new XliffFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/resources-2.0-multi-segment-unit.xlf';
|
||||
$catalog = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertSame('en', $catalog->getLocale());
|
||||
$this->assertEquals(array(new FileResource($resource)), $catalog->getResources());
|
||||
$this->assertFalse(libxml_get_last_error());
|
||||
|
||||
// test for "foo" metadata
|
||||
$this->assertTrue($catalog->defines('foo', 'domain1'));
|
||||
$metadata = $catalog->getMetadata('foo', 'domain1');
|
||||
$this->assertNotEmpty($metadata);
|
||||
$this->assertCount(1, $metadata['notes']);
|
||||
|
||||
$this->assertSame('processed', $metadata['notes'][0]['category']);
|
||||
$this->assertSame('true', $metadata['notes'][0]['content']);
|
||||
|
||||
// test for "bar" metadata
|
||||
$this->assertTrue($catalog->defines('bar', 'domain1'));
|
||||
$metadata = $catalog->getMetadata('bar', 'domain1');
|
||||
$this->assertNotEmpty($metadata);
|
||||
$this->assertCount(1, $metadata['notes']);
|
||||
|
||||
$this->assertSame('processed', $metadata['notes'][0]['category']);
|
||||
$this->assertSame('true', $metadata['notes'][0]['content']);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Translation\Loader\YamlFileLoader;
|
||||
|
||||
class YamlFileLoaderTest extends 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,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;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
use Symfony\Component\Translation\LoggingTranslator;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
|
||||
class LoggingTranslatorTest extends TestCase
|
||||
{
|
||||
public function testTransWithNoTranslationIsLogged()
|
||||
{
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$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->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$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,222 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
class MessageCatalogueTest extends 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->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
|
||||
$r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
|
||||
|
||||
$r1 = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
|
||||
$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->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
|
||||
$r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
|
||||
|
||||
$r1 = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
|
||||
$r1->expects($this->any())->method('__toString')->will($this->returnValue('r1'));
|
||||
|
||||
$r2 = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
|
||||
$r2->expects($this->any())->method('__toString')->will($this->returnValue('r2'));
|
||||
|
||||
$catalogue = new MessageCatalogue('fr_FR', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
|
||||
$catalogue->addResource($r);
|
||||
|
||||
$catalogue1 = new MessageCatalogue('fr', array('domain1' => array('foo' => 'bar', 'foo1' => 'foo1')));
|
||||
$catalogue1->addResource($r1);
|
||||
|
||||
$catalogue2 = new MessageCatalogue('en');
|
||||
$catalogue2->addResource($r2);
|
||||
|
||||
$catalogue->addFallbackCatalogue($catalogue1);
|
||||
$catalogue1->addFallbackCatalogue($catalogue2);
|
||||
|
||||
$this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
|
||||
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
|
||||
|
||||
$this->assertEquals(array($r, $r1, $r2), $catalogue->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\LogicException
|
||||
*/
|
||||
public function testAddFallbackCatalogueWithParentCircularReference()
|
||||
{
|
||||
$main = new MessageCatalogue('en_US');
|
||||
$fallback = new MessageCatalogue('fr_FR');
|
||||
|
||||
$fallback->addFallbackCatalogue($main);
|
||||
$main->addFallbackCatalogue($fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Translation\Exception\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 \Symfony\Component\Translation\Exception\LogicException
|
||||
*/
|
||||
public function testAddCatalogueWhenLocaleIsNotTheSameAsTheCurrentOne()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$catalogue->addCatalogue(new MessageCatalogue('fr', array()));
|
||||
}
|
||||
|
||||
public function testGetAddResource()
|
||||
{
|
||||
$catalogue = new MessageCatalogue('en');
|
||||
$r = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
|
||||
$r->expects($this->any())->method('__toString')->will($this->returnValue('r'));
|
||||
$catalogue->addResource($r);
|
||||
$catalogue->addResource($r);
|
||||
$r1 = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
|
||||
$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,137 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\MessageSelector;
|
||||
|
||||
class MessageSelectorTest extends 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 \Symfony\Component\Translation\Exception\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),
|
||||
// esacape pipe
|
||||
array('This is a text with | in it. Selector = 0.', '{0}This is a text with || in it. Selector = 0.|{1}This is a text with || in it. Selector = 1.', 0),
|
||||
// Empty plural set (2 plural forms) from a .PO file
|
||||
array('', '|', 1),
|
||||
// Empty plural set (3 plural forms) from a .PO file
|
||||
array('', '||', 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
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 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($langCodes);
|
||||
$this->validateMatrix($nplural, $matrix, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider successLangcodes
|
||||
*/
|
||||
public function testLangcodes($nplural, $langCodes)
|
||||
{
|
||||
$matrix = $this->generateTestData($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', 'hy', 'hy_AM')),
|
||||
array('3', array('be', 'bs', 'cs', 'hr')),
|
||||
array('4', array('cy', 'mt', 'sl')),
|
||||
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')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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($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,311 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Resource\SelfCheckingResourceInterface;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
use Symfony\Component\Translation\Loader\LoaderInterface;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
|
||||
class TranslatorCacheTest extends 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->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock();
|
||||
$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 testGeneratedCacheFilesAreOnlyBelongRequestedLocales()
|
||||
{
|
||||
$translator = new Translator('a', null, $this->tmpDir);
|
||||
$translator->setFallbackLocales(array('b'));
|
||||
$translator->trans('bar');
|
||||
|
||||
$cachedFiles = glob($this->tmpDir.'/*.php');
|
||||
|
||||
$this->assertCount(1, $cachedFiles);
|
||||
}
|
||||
|
||||
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->getMockBuilder('Symfony\Component\Config\Resource\SelfCheckingResourceInterface')->getMock();
|
||||
$loader = $this->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock();
|
||||
$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->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock();
|
||||
$loader
|
||||
->expects($this->never())
|
||||
->method('load');
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
class StaleResource implements SelfCheckingResourceInterface
|
||||
{
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getResource()
|
||||
{
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,549 +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 PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
|
||||
class TranslatorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getInvalidLocalesTests
|
||||
* @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorInvalidLocale($locale)
|
||||
{
|
||||
new Translator($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testConstructorValidLocale($locale)
|
||||
{
|
||||
$translator = new Translator($locale);
|
||||
|
||||
$this->assertEquals($locale, $translator->getLocale());
|
||||
}
|
||||
|
||||
public function testConstructorWithoutLocale()
|
||||
{
|
||||
$translator = new Translator(null);
|
||||
|
||||
$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 \Symfony\Component\Translation\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testSetInvalidLocale($locale)
|
||||
{
|
||||
$translator = new Translator('fr');
|
||||
$translator->setLocale($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testSetValidLocale($locale)
|
||||
{
|
||||
$translator = new Translator($locale);
|
||||
$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 \Symfony\Component\Translation\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testSetFallbackInvalidLocales($locale)
|
||||
{
|
||||
$translator = new Translator('fr');
|
||||
$translator->setFallbackLocales(array('fr', $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testSetFallbackValidLocales($locale)
|
||||
{
|
||||
$translator = new Translator($locale);
|
||||
$translator->setFallbackLocales(array('fr', $locale));
|
||||
// no assertion. this method just asserts that no exception is thrown
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
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 \Symfony\Component\Translation\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testAddResourceInvalidLocales($locale)
|
||||
{
|
||||
$translator = new Translator('fr');
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidLocalesTests
|
||||
*/
|
||||
public function testAddResourceValidLocales($locale)
|
||||
{
|
||||
$translator = new Translator('fr');
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), $locale);
|
||||
// no assertion. this method just asserts that no exception is thrown
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
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 \Symfony\Component\Translation\Exception\RuntimeException
|
||||
*/
|
||||
public function testWhenAResourceHasNoRegisteredLoader()
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$translator->addResource('array', array('foo' => 'foofoo'), 'en');
|
||||
|
||||
$translator->trans('foo');
|
||||
}
|
||||
|
||||
public function testNestedFallbackCatalogueWhenUsingMultipleLocales()
|
||||
{
|
||||
$translator = new Translator('fr');
|
||||
$translator->setFallbackLocales(array('ru', 'en'));
|
||||
|
||||
$translator->getCatalogue('fr');
|
||||
|
||||
$this->assertNotNull($translator->getCatalogue('ru')->getFallbackCatalogue());
|
||||
}
|
||||
|
||||
public function testFallbackCatalogueResources()
|
||||
{
|
||||
$translator = new Translator('en_GB');
|
||||
$translator->addLoader('yml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
|
||||
$translator->addResource('yml', __DIR__.'/fixtures/empty.yml', 'en_GB');
|
||||
$translator->addResource('yml', __DIR__.'/fixtures/resources.yml', 'en');
|
||||
|
||||
// force catalogue loading
|
||||
$this->assertEquals('bar', $translator->trans('foo', array()));
|
||||
|
||||
$resources = $translator->getCatalogue('en')->getResources();
|
||||
$this->assertCount(1, $resources);
|
||||
$this->assertContains(__DIR__.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'resources.yml', $resources);
|
||||
|
||||
$resources = $translator->getCatalogue('en_GB')->getResources();
|
||||
$this->assertCount(2, $resources);
|
||||
$this->assertContains(__DIR__.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'empty.yml', $resources);
|
||||
$this->assertContains(__DIR__.\DIRECTORY_SEPARATOR.'fixtures'.\DIRECTORY_SEPARATOR.'resources.yml', $resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 \Symfony\Component\Translation\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testTransInvalidLocale($locale)
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$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);
|
||||
$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 \Symfony\Component\Translation\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testTransChoiceInvalidLocale($locale)
|
||||
{
|
||||
$translator = new Translator('en');
|
||||
$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');
|
||||
$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
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
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(), '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(), '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(), '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(), '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(), '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(), '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(), '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(), '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(), '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(), '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(), '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(), '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(), 'fr', ''),
|
||||
|
||||
// Override %count% with a custom value
|
||||
array('Il y a quelques pommes', 'one: There is one apple|more: There are %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 2, array('%count%' => 'quelques'), '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)));
|
||||
}
|
||||
}
|
||||
|
||||
class StringClass
|
||||
{
|
||||
protected $str;
|
||||
|
||||
public function __construct($str)
|
||||
{
|
||||
$this->str = $str;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->str;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +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\Util;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Util\ArrayConverter;
|
||||
|
||||
class ArrayConverterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider messagesData
|
||||
*/
|
||||
public function testDump($input, $expectedOutput)
|
||||
{
|
||||
$this->assertEquals($expectedOutput, ArrayConverter::expandToTree($input));
|
||||
}
|
||||
|
||||
public function messagesData()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
// input
|
||||
array(
|
||||
'foo1' => 'bar',
|
||||
'foo.bar' => 'value',
|
||||
),
|
||||
// expected output
|
||||
array(
|
||||
'foo1' => 'bar',
|
||||
'foo' => array('bar' => 'value'),
|
||||
),
|
||||
),
|
||||
array(
|
||||
// input
|
||||
array(
|
||||
'foo.bar' => 'value1',
|
||||
'foo.bar.test' => 'value2',
|
||||
),
|
||||
// expected output
|
||||
array(
|
||||
'foo' => array(
|
||||
'bar' => 'value1',
|
||||
'bar.test' => 'value2',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
// input
|
||||
array(
|
||||
'foo.level2.level3.level4' => 'value1',
|
||||
'foo.level2' => 'value2',
|
||||
'foo.bar' => 'value3',
|
||||
),
|
||||
// expected output
|
||||
array(
|
||||
'foo' => array(
|
||||
'level2' => 'value2',
|
||||
'level2.level3.level4' => 'value1',
|
||||
'bar' => 'value3',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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\Writer;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Translation\Dumper\DumperInterface;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Writer\TranslationWriter;
|
||||
|
||||
class TranslationWriterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation The "Symfony\Component\Translation\Writer\TranslationWriter::writeTranslations()" method is deprecated since Symfony 3.4 and will be removed in 4.0. Use write() instead.
|
||||
*/
|
||||
public function testWriteTranslations()
|
||||
{
|
||||
$dumper = $this->getMockBuilder('Symfony\Component\Translation\Dumper\DumperInterface')->getMock();
|
||||
$dumper
|
||||
->expects($this->once())
|
||||
->method('dump');
|
||||
|
||||
$writer = new TranslationWriter();
|
||||
$writer->addDumper('test', $dumper);
|
||||
$writer->writeTranslations(new MessageCatalogue('en'), 'test');
|
||||
}
|
||||
|
||||
public function testWrite()
|
||||
{
|
||||
$dumper = $this->getMockBuilder('Symfony\Component\Translation\Dumper\DumperInterface')->getMock();
|
||||
$dumper
|
||||
->expects($this->once())
|
||||
->method('dump');
|
||||
|
||||
$writer = new TranslationWriter();
|
||||
$writer->addDumper('test', $dumper);
|
||||
$writer->write(new MessageCatalogue(array()), 'test');
|
||||
}
|
||||
|
||||
public function testDisableBackup()
|
||||
{
|
||||
$nonBackupDumper = new NonBackupDumper();
|
||||
$backupDumper = new BackupDumper();
|
||||
|
||||
$writer = new TranslationWriter();
|
||||
$writer->addDumper('non_backup', $nonBackupDumper);
|
||||
$writer->addDumper('backup', $backupDumper);
|
||||
$writer->disableBackup();
|
||||
|
||||
$this->assertFalse($backupDumper->backup, 'backup can be disabled if setBackup() method does exist');
|
||||
}
|
||||
}
|
||||
|
||||
class NonBackupDumper implements DumperInterface
|
||||
{
|
||||
public function dump(MessageCatalogue $messages, $options = array())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class BackupDumper implements DumperInterface
|
||||
{
|
||||
public $backup = true;
|
||||
|
||||
public function dump(MessageCatalogue $messages, $options = array())
|
||||
{
|
||||
}
|
||||
|
||||
public function setBackup($backup)
|
||||
{
|
||||
$this->backup = $backup;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
msgid "foo"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en" datatype="plaintext" original="file.ext">
|
||||
<body>
|
||||
<trans-unit id="1" resname="foo">
|
||||
<source>foo</source>
|
||||
<target>bär</target>
|
||||
<note>bäz</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="2" resname="bar">
|
||||
<source>bar</source>
|
||||
<target>föö</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en\n"
|
||||
|
||||
msgid "escaped \"foo\""
|
||||
msgid_plural "escaped \"foos\""
|
||||
msgstr[0] "escaped \"bar\""
|
||||
msgstr[1] "escaped \"bars\""
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en\n"
|
||||
|
||||
msgid "escaped \"foo\""
|
||||
msgstr "escaped \"bar\""
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#, php-format
|
||||
msgid "foo1"
|
||||
msgstr "bar1"
|
||||
|
||||
#, fuzzy, php-format
|
||||
msgid "foo2"
|
||||
msgstr "fuzzy bar2"
|
||||
|
||||
msgid "foo3"
|
||||
msgstr "bar3"
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en" datatype="plaintext" original="file.ext">
|
||||
<body>
|
||||
<trans-unit id="1">
|
||||
<source>foo</source>
|
||||
<target>bar
|
||||
</trans-unit>
|
||||
<trans-unit id="2">
|
||||
<source>extra</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="3">
|
||||
<source>key</source>
|
||||
<target></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="4">
|
||||
<source>test</source>
|
||||
<target>with</target>
|
||||
<note>note</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"foo" "bar"
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
foo:
|
||||
bar1: value1
|
||||
bar2: value2
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue