Dependency updates and update version number

This commit is contained in:
Kode
2018-06-13 19:35:28 +01:00
parent 18ec208381
commit e3ec7de23a
1261 changed files with 45582 additions and 29687 deletions

View File

@@ -1,6 +1,20 @@
CHANGELOG
=========
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
-----

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\Translation\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -33,7 +34,7 @@ class XliffLintCommand extends Command
private $directoryIteratorProvider;
private $isReadableProvider;
public function __construct($name = null, $directoryIteratorProvider = null, $isReadableProvider = null)
public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null)
{
parent::__construct($name);
@@ -81,14 +82,14 @@ EOF
if (!$filename) {
if (!$stdin = $this->getStdin()) {
throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
return $this->display($io, array($this->validate($stdin)));
}
if (!$this->isReadable($filename)) {
throw new \RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
}
$filesInfo = array();
@@ -101,6 +102,8 @@ EOF
private function validate($content, $file = null)
{
$errors = array();
// Avoid: Warning DOMDocument::loadXML(): Empty string supplied as input
if ('' === trim($content)) {
return array('file' => $file, 'valid' => true);
@@ -110,22 +113,33 @@ EOF
$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)) {
$expectedFileExtension = sprintf('%s.xlf', str_replace('-', '_', $targetLanguage));
$realFileExtension = explode('.', basename($file), 2)[1] ?? '';
if ($expectedFileExtension !== $realFileExtension) {
$errors[] = array(
'line' => -1,
'column' => -1,
'message' => sprintf('There is a mismatch between the file extension ("%s") and the "%s" value used in the "target-language" attribute of the file.', $realFileExtension, $targetLanguage),
);
}
}
$errorMessages = array_map(function ($error) {
return array(
'line' => $error->line,
'column' => $error->column,
'message' => trim($error->message),
);
}, libxml_get_errors());
$document->schemaValidate(__DIR__.'/../Resources/schemas/xliff-core-1.2-strict.xsd');
foreach (libxml_get_errors() as $xmlError) {
$errors[] = array(
'line' => $xmlError->line,
'column' => $xmlError->column,
'message' => trim($xmlError->message),
);
}
libxml_clear_errors();
libxml_use_internal_errors(false);
return array('file' => $file, 'valid' => false, 'messages' => $errorMessages);
return array('file' => $file, 'valid' => 0 === count($errors), 'messages' => $errors);
}
private function display(SymfonyStyle $io, array $files)
@@ -136,7 +150,7 @@ EOF
case 'json':
return $this->displayJson($io, $files);
default:
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
}
}
@@ -242,4 +256,15 @@ EOF
return $default($fileOrDirectory);
}
private function getTargetLanguageFromFile(\DOMDocument $xliffContents): ?string
{
foreach ($xliffContents->getElementsByTagName('file')[0]->attributes ?? array() as $attribute) {
if ('target-language' === $attribute->nodeName) {
return $attribute->nodeValue;
}
}
return null;
}
}

View File

@@ -23,7 +23,7 @@ class TranslationDumperPass implements CompilerPassInterface
private $writerServiceId;
private $dumperTag;
public function __construct($writerServiceId = 'translation.writer', $dumperTag = 'translation.dumper')
public function __construct(string $writerServiceId = 'translation.writer', string $dumperTag = 'translation.dumper')
{
$this->writerServiceId = $writerServiceId;
$this->dumperTag = $dumperTag;

View File

@@ -24,7 +24,7 @@ class TranslationExtractorPass implements CompilerPassInterface
private $extractorServiceId;
private $extractorTag;
public function __construct($extractorServiceId = 'translation.extractor', $extractorTag = 'translation.extractor')
public function __construct(string $extractorServiceId = 'translation.extractor', string $extractorTag = 'translation.extractor')
{
$this->extractorServiceId = $extractorServiceId;
$this->extractorTag = $extractorTag;

View File

@@ -24,12 +24,8 @@ class TranslatorPass implements CompilerPassInterface
private $debugCommandServiceId;
private $updateCommandServiceId;
public function __construct($translatorServiceId = 'translator.default', $readerServiceId = 'translation.loader', $loaderTag = 'translation.loader', $debugCommandServiceId = 'console.command.translation_debug', $updateCommandServiceId = 'console.command.translation_update')
public function __construct(string $translatorServiceId = 'translator.default', string $readerServiceId = 'translation.reader', string $loaderTag = 'translation.loader', string $debugCommandServiceId = 'console.command.translation_debug', string $updateCommandServiceId = 'console.command.translation_update')
{
if ('translation.loader' === $readerServiceId && 2 > func_num_args()) {
@trigger_error('The default value for $readerServiceId will change in 4.0 to "translation.reader".', E_USER_DEPRECATED);
}
$this->translatorServiceId = $translatorServiceId;
$this->readerServiceId = $readerServiceId;
$this->loaderTag = $loaderTag;
@@ -62,18 +58,6 @@ class TranslatorPass implements CompilerPassInterface
}
}
// Duplicated code to support "translation.reader", to be removed in 4.0
if ('translation.reader' !== $this->readerServiceId) {
if ($container->hasDefinition('translation.reader')) {
$definition = $container->getDefinition('translation.reader');
foreach ($loaders as $id => $formats) {
foreach ($formats as $format) {
$definition->addMethodCall('addLoader', array($format, $loaderRefs[$id]));
}
}
}
}
$container
->findDefinition($this->translatorServiceId)
->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs))

View File

@@ -17,7 +17,6 @@ use Symfony\Component\Translation\Exception\RuntimeException;
/**
* 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.
*
@@ -54,10 +46,16 @@ abstract class FileDumper implements DumperInterface
* Sets backup flag.
*
* @param bool
*
* @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.');
}
}
/**
@@ -71,14 +69,8 @@ abstract class FileDumper implements DumperInterface
// 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.'~');
}
} else {
if (!file_exists($fullpath)) {
$directory = dirname($fullpath);
if (!file_exists($directory) && !@mkdir($directory, 0777, true)) {
throw new RuntimeException(sprintf('Unable to create directory "%s".', $directory));
@@ -109,13 +101,8 @@ 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(
'%domain%' => $domain,

View File

@@ -28,7 +28,7 @@ class JsonFileDumper extends FileDumper
if (isset($options['json_encoding'])) {
$flags = $options['json_encoding'];
} else {
$flags = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0;
$flags = JSON_PRETTY_PRINT;
}
return json_encode($messages->all($domain), $flags);

View File

@@ -146,6 +146,11 @@ class XliffFileDumper extends FileDumper
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

View File

@@ -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;
}

View File

@@ -43,12 +43,7 @@ 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);
}

View File

@@ -83,10 +83,8 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
foreach ($files as $file) {
$this->parseTokens(token_get_all(file_get_contents($file)), $catalog);
if (\PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches();
}
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches();
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -134,11 +134,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);

View File

@@ -75,7 +75,7 @@ class XliffFileLoader implements LoaderInterface
* @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);
@@ -115,12 +115,7 @@ class XliffFileLoader implements LoaderInterface
}
}
/**
* @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);
@@ -128,48 +123,44 @@ class XliffFileLoader implements LoaderInterface
$xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0');
foreach ($xml->xpath('//xliff:unit') as $unit) {
$segment = $unit->segment;
$source = $segment->source;
foreach ($unit->segment as $segment) {
$source = $segment->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($segment->target) ? $segment->target : $source), $encoding);
// 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($segment->target) ? $segment->target : $source), $encoding);
$catalogue->set((string) $source, $target, $domain);
$catalogue->set((string) $source, $target, $domain);
$metadata = array();
if (isset($segment->target) && $segment->target->attributes()) {
$metadata['target-attributes'] = array();
foreach ($segment->target->attributes() as $key => $value) {
$metadata['target-attributes'][$key] = (string) $value;
}
}
if (isset($unit->notes)) {
$metadata['notes'] = array();
foreach ($unit->notes->note as $noteNode) {
$note = array();
foreach ($noteNode->attributes() as $key => $value) {
$note[$key] = (string) $value;
$metadata = array();
if (isset($segment->target) && $segment->target->attributes()) {
$metadata['target-attributes'] = array();
foreach ($segment->target->attributes() as $key => $value) {
$metadata['target-attributes'][$key] = (string) $value;
}
$note['content'] = (string) $noteNode;
$metadata['notes'][] = $note;
}
}
$catalogue->setMetadata((string) $source, $metadata, $domain);
if (isset($unit->notes)) {
$metadata['notes'] = array();
foreach ($unit->notes->note as $noteNode) {
$note = array();
foreach ($noteNode->attributes() as $key => $value) {
$note[$key] = (string) $value;
}
$note['content'] = (string) $noteNode;
$metadata['notes'][] = $note;
}
}
$catalogue->setMetadata((string) $source, $metadata, $domain);
}
}
}
/**
* 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');
@@ -181,13 +172,9 @@ class XliffFileLoader implements LoaderInterface
/**
* 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 validateSchema(string $file, \DOMDocument $dom, string $schema)
{
$internalErrors = libxml_use_internal_errors(true);
@@ -224,13 +211,8 @@ class XliffFileLoader implements LoaderInterface
/**
* 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)
private function fixXmlLocation(string $schemaSource, string $xmlUri): string
{
$newPath = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
$parts = explode('/', $newPath);
@@ -254,12 +236,8 @@ class XliffFileLoader implements LoaderInterface
/**
* Returns the XML errors of the internal XML parser.
*
* @param bool $internalErrors
*
* @return array An array of errors
*/
private function getXmlErrors($internalErrors)
private function getXmlErrors(bool $internalErrors): array
{
$errors = array();
foreach (libxml_get_errors() as $error) {
@@ -283,13 +261,9 @@ class XliffFileLoader implements LoaderInterface
* 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)
private function getVersionNumber(\DOMDocument $dom): string
{
/** @var \DOMNode $xliff */
foreach ($dom->getElementsByTagName('xliff') as $xliff) {
@@ -312,13 +286,7 @@ class XliffFileLoader implements LoaderInterface
return '1.2';
}
/**
* @param \SimpleXMLElement|null $noteElement
* @param string|null $encoding
*
* @return array
*/
private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, $encoding = null)
private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, string $encoding = null): array
{
$notes = array();

View File

@@ -15,6 +15,7 @@ use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\LogicException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
/**
* YamlFileLoader loads translations from Yaml files.
@@ -38,18 +39,10 @@ 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;

View File

@@ -30,7 +30,7 @@ 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 = array())
{
$this->locale = $locale;
$this->messages = $messages;

View File

@@ -105,7 +105,7 @@ interface MessageCatalogueInterface
*
* The two catalogues must have the same locale.
*/
public function addCatalogue(MessageCatalogueInterface $catalogue);
public function addCatalogue(self $catalogue);
/**
* Merges translations from the given Catalogue into the current one
@@ -113,7 +113,7 @@ interface MessageCatalogueInterface
*
* This is used to provide default translations when they do not exist for the current locale.
*/
public function addFallbackCatalogue(MessageCatalogueInterface $catalogue);
public function addFallbackCatalogue(self $catalogue);
/**
* Gets the fallback catalogue.

View File

@@ -107,6 +107,7 @@ class PluralizationRules
case 'nl':
case 'nn':
case 'no':
case 'oc':
case 'om':
case 'or':
case 'pa':

View File

@@ -3,16 +3,16 @@
<!--
May-19-2004:
- Changed the <choice> for ElemType_header, moving minOccurs="0" maxOccurs="unbounded" from its elements
- Changed the <choice> for ElemType_header, moving minOccurs="0" maxOccurs="unbounded" from its elements
to <choice> itself.
- Added <choice> for ElemType_trans-unit to allow "any order" for <context-group>, <count-group>, <prop-group>, <note>, and
<alt-trans>.
Oct-2005
- updated version info to 1.2
- equiv-trans attribute to <trans-unit> element
- equiv-trans attribute to <trans-unit> element
- merged-trans attribute for <group> element
- Add the <seg-source> element as optional in the <trans-unit> and <alt-trans> content models, at the same level as <source>
- Add the <seg-source> element as optional in the <trans-unit> and <alt-trans> content models, at the same level as <source>
- Create a new value "seg" for the mtype attribute of the <mrk> element
- Add mid as an optional attribute for the <alt-trans> element
@@ -2220,4 +2220,4 @@ Jan-10-2006
<xsd:anyAttribute namespace="##other" processContents="strict"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</xsd:schema>

View File

@@ -0,0 +1,163 @@
<?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\Command;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Translation\Command\XliffLintCommand;
/**
* Tests the XliffLintCommand.
*
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
*/
class XliffLintCommandTest extends TestCase
{
private $files;
public function testLintCorrectFile()
{
$tester = $this->createCommandTester();
$filename = $this->createFile();
$tester->execute(
array('filename' => $filename),
array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false)
);
$this->assertEquals(0, $tester->getStatusCode(), 'Returns 0 in case of success');
$this->assertContains('OK', trim($tester->getDisplay()));
}
public function testLintIncorrectXmlSyntax()
{
$tester = $this->createCommandTester();
$filename = $this->createFile('note <target>');
$tester->execute(array('filename' => $filename), array('decorated' => false));
$this->assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error');
$this->assertContains('Opening and ending tag mismatch: target line 6 and source', trim($tester->getDisplay()));
}
public function testLintIncorrectTargetLanguage()
{
$tester = $this->createCommandTester();
$filename = $this->createFile('note', 'es');
$tester->execute(array('filename' => $filename), array('decorated' => false));
$this->assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error');
$this->assertContains('There is a mismatch between the file extension ("en.xlf") and the "es" value used in the "target-language" attribute of the file.', trim($tester->getDisplay()));
}
/**
* @expectedException \RuntimeException
*/
public function testLintFileNotReadable()
{
$tester = $this->createCommandTester();
$filename = $this->createFile();
unlink($filename);
$tester->execute(array('filename' => $filename), array('decorated' => false));
}
public function testGetHelp()
{
$command = new XliffLintCommand();
$expected = <<<EOF
The <info>%command.name%</info> command lints a XLIFF file and outputs to STDOUT
the first encountered syntax error.
You can validates XLIFF contents passed from STDIN:
<info>cat filename | php %command.full_name%</info>
You can also validate the syntax of a file:
<info>php %command.full_name% filename</info>
Or of a whole directory:
<info>php %command.full_name% dirname</info>
<info>php %command.full_name% dirname --format=json</info>
EOF;
$this->assertEquals($expected, $command->getHelp());
}
/**
* @return string Path to the new file
*/
private function createFile($sourceContent = 'note', $targetLanguage = 'en')
{
$xliffContent = <<<XLIFF
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" target-language="$targetLanguage" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="note">
<source>$sourceContent</source>
<target>NOTE</target>
</trans-unit>
</body>
</file>
</xliff>
XLIFF;
$filename = sprintf('%s/translation-xliff-lint-test/messages.en.xlf', sys_get_temp_dir());
file_put_contents($filename, $xliffContent);
$this->files[] = $filename;
return $filename;
}
/**
* @return CommandTester
*/
private function createCommandTester($application = null)
{
if (!$application) {
$application = new Application();
$application->add(new XliffLintCommand());
}
$command = $application->find('lint:xliff');
if ($application) {
$command->setApplication($application);
}
return new CommandTester($command);
}
protected function setUp()
{
$this->files = array();
@mkdir(sys_get_temp_dir().'/translation-xliff-lint-test');
}
protected function tearDown()
{
foreach ($this->files as $file) {
if (file_exists($file)) {
unlink($file);
}
}
rmdir(sys_get_temp_dir().'/translation-xliff-lint-test');
}
}

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\Translation\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Translation\DependencyInjection\TranslationDumperPass;
@@ -19,48 +20,29 @@ class TranslationDumperPassTest extends TestCase
{
public function testProcess()
{
$definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->disableOriginalConstructor()->getMock();
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->disableOriginalConstructor()->getMock();
$container->expects($this->once())
->method('hasDefinition')
->with('translation.writer')
->will($this->returnValue(true));
$container->expects($this->once())
->method('getDefinition')
->with('translation.writer')
->will($this->returnValue($definition));
$valueTaggedServiceIdsFound = array(
'foo.id' => array(
array('alias' => 'bar.alias'),
),
);
$container->expects($this->once())
->method('findTaggedServiceIds')
->with('translation.dumper', true)
->will($this->returnValue($valueTaggedServiceIdsFound));
$definition->expects($this->once())->method('addMethodCall')->with('addDumper', array('bar.alias', new Reference('foo.id')));
$container = new ContainerBuilder();
$writerDefinition = $container->register('translation.writer');
$container->register('foo.id')
->addTag('translation.dumper', array('alias' => 'bar.alias'));
$translationDumperPass = new TranslationDumperPass();
$translationDumperPass->process($container);
$this->assertEquals(array(array('addDumper', array('bar.alias', new Reference('foo.id')))), $writerDefinition->getMethodCalls());
}
public function testProcessNoDefinitionFound()
{
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->disableOriginalConstructor()->getMock();
$container = new ContainerBuilder();
$container->expects($this->once())
->method('hasDefinition')
->with('translation.writer')
->will($this->returnValue(false));
$container->expects($this->never())->method('getDefinition');
$container->expects($this->never())->method('findTaggedServiceIds');
$definitionsBefore = count($container->getDefinitions());
$aliasesBefore = count($container->getAliases());
$translationDumperPass = new TranslationDumperPass();
$translationDumperPass->process($container);
// the container is untouched (i.e. no new definitions or aliases)
$this->assertCount($definitionsBefore, $container->getDefinitions());
$this->assertCount($aliasesBefore, $container->getAliases());
}
}

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\Translation\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass;
@@ -19,49 +20,30 @@ class TranslationExtractorPassTest extends TestCase
{
public function testProcess()
{
$definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->disableOriginalConstructor()->getMock();
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->disableOriginalConstructor()->getMock();
$container->expects($this->once())
->method('hasDefinition')
->with('translation.extractor')
->will($this->returnValue(true));
$container->expects($this->once())
->method('getDefinition')
->with('translation.extractor')
->will($this->returnValue($definition));
$valueTaggedServiceIdsFound = array(
'foo.id' => array(
array('alias' => 'bar.alias'),
),
);
$container->expects($this->once())
->method('findTaggedServiceIds')
->with('translation.extractor', true)
->will($this->returnValue($valueTaggedServiceIdsFound));
$definition->expects($this->once())->method('addMethodCall')->with('addExtractor', array('bar.alias', new Reference('foo.id')));
$container = new ContainerBuilder();
$extractorDefinition = $container->register('translation.extractor');
$container->register('foo.id')
->addTag('translation.extractor', array('alias' => 'bar.alias'));
$translationDumperPass = new TranslationExtractorPass();
$translationDumperPass->process($container);
$this->assertEquals(array(array('addExtractor', array('bar.alias', new Reference('foo.id')))), $extractorDefinition->getMethodCalls());
}
public function testProcessNoDefinitionFound()
{
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->disableOriginalConstructor()->getMock();
$container = new ContainerBuilder();
$container->expects($this->once())
->method('hasDefinition')
->with('translation.extractor')
->will($this->returnValue(false));
$container->expects($this->never())->method('getDefinition');
$container->expects($this->never())->method('findTaggedServiceIds');
$definitionsBefore = count($container->getDefinitions());
$aliasesBefore = count($container->getAliases());
$translationDumperPass = new TranslationExtractorPass();
$translationDumperPass->process($container);
// the container is untouched (i.e. no new definitions or aliases)
$this->assertCount($definitionsBefore, $container->getDefinitions());
$this->assertCount($aliasesBefore, $container->getAliases());
}
/**
@@ -71,25 +53,10 @@ class TranslationExtractorPassTest extends TestCase
public function testProcessMissingAlias()
{
$definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->disableOriginalConstructor()->getMock();
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->disableOriginalConstructor()->getMock();
$container->expects($this->once())
->method('hasDefinition')
->with('translation.extractor')
->will($this->returnValue(true));
$container->expects($this->once())
->method('getDefinition')
->with('translation.extractor')
->will($this->returnValue($definition));
$valueTaggedServiceIdsFound = array(
'foo.id' => array(),
);
$container->expects($this->once())
->method('findTaggedServiceIds')
->with('translation.extractor', true)
->will($this->returnValue($valueTaggedServiceIdsFound));
$container = new ContainerBuilder();
$container->register('translation.extractor');
$container->register('foo.id')
->addTag('translation.extractor', array());
$definition->expects($this->never())->method('addMethodCall');

View File

@@ -54,50 +54,4 @@ class TranslationPassTest extends TestCase
$expected = array('translation.xliff_loader' => new ServiceClosureArgument(new Reference('translation.xliff_loader')));
$this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));
}
/**
* @group legacy
* @expectedDeprecation The default value for $readerServiceId will change in 4.0 to "translation.reader".
*
* A test that verifies the deprecated "translation.loader" gets the LoaderInterfaces added.
*
* This test should be removed in 4.0.
*/
public function testValidCollectorWithDeprecatedTranslationLoader()
{
$loader = (new Definition())
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'));
$legacyReader = new Definition();
$reader = new Definition();
$translator = (new Definition())
->setArguments(array(null, null, null, null));
$container = new ContainerBuilder();
$container->setDefinition('translator.default', $translator);
$container->setDefinition('translation.loader', $legacyReader);
$container->setDefinition('translation.reader', $reader);
$container->setDefinition('translation.xliff_loader', $loader);
$pass = new TranslatorPass();
$pass->process($container);
$expectedReader = (new Definition())
->addMethodCall('addLoader', array('xliff', new Reference('translation.xliff_loader')))
->addMethodCall('addLoader', array('xlf', new Reference('translation.xliff_loader')))
;
$this->assertEquals($expectedReader, $legacyReader);
$this->assertEquals($expectedReader, $reader);
$expectedLoader = (new Definition())
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'))
;
$this->assertEquals($expectedLoader, $loader);
$this->assertSame(array('translation.xliff_loader' => array('xliff', 'xlf')), $translator->getArgument(3));
$expected = array('translation.xliff_loader' => new ServiceClosureArgument(new Reference('translation.xliff_loader')));
$this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));
}
}

View File

@@ -32,29 +32,6 @@ class FileDumperTest extends TestCase
@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();

View File

@@ -228,4 +228,33 @@ class XliffFileLoaderTest extends TestCase
$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']);
}
}

View File

@@ -18,22 +18,6 @@ use Symfony\Component\Translation\Writer\TranslationWriter;
class TranslationWriterTest extends TestCase
{
/**
* @group legacy
* @expectedDeprecation Method Symfony\Component\Translation\Writer\TranslationWriter::writeTranslations() 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();
@@ -43,9 +27,12 @@ class TranslationWriterTest extends TestCase
$writer = new TranslationWriter();
$writer->addDumper('test', $dumper);
$writer->write(new MessageCatalogue(array()), 'test');
$writer->write(new MessageCatalogue('en'), 'test');
}
/**
* @group legacy
*/
public function testDisableBackup()
{
$nonBackupDumper = new NonBackupDumper();

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="fr-FR" trgLang="en-US">
<file id="messages.en_US">
<unit id="LCa0a2j">
<unit id="LCa0a2j" name="foo">
<segment>
<source>foo</source>
<target>bar</target>
</segment>
</unit>
<unit id="LHDhK3o">
<unit id="LHDhK3o" name="key">
<segment>
<source>key</source>
<target order="1"></target>
</segment>
</unit>
<unit id="2DA_bnh">
<unit id="2DA_bnh" name="key.with.cdata">
<segment>
<source>key.with.cdata</source>
<target><![CDATA[<source> & <target>]]></target>

View File

@@ -0,0 +1,17 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en-US" trgLang="en-US">
<file id="f1">
<unit id="1">
<notes>
<note category="processed">true</note>
</notes>
<segment id="id-foo">
<source>foo</source>
<target>foo (translated)</target>
</segment>
<segment id="id-bar">
<source>bar</source>
<target>bar (translated)</target>
</segment>
</unit>
</file>
</xliff>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="fr-FR" trgLang="en-US">
<file id="messages.en_US">
<unit id="LCa0a2j">
<unit id="LCa0a2j" name="foo">
<notes>
<note category="state">new</note>
<note category="approved">true</note>
@@ -12,7 +12,7 @@
<target>bar</target>
</segment>
</unit>
<unit id="uqWglk0">
<unit id="uqWglk0" name="baz">
<notes>
<note id="x">x_content</note>
<note appliesTo="target" category="quality">Fuzzy</note>

View File

@@ -74,21 +74,13 @@ class Translator implements TranslatorInterface, TranslatorBagInterface
private $configCacheFactory;
/**
* @param string $locale The locale
* @param MessageFormatterInterface|null $formatter The message formatter
* @param string|null $cacheDir The directory to use for the cache
* @param bool $debug Use cache in debug mode ?
*
* @throws InvalidArgumentException If a locale contains invalid characters
*/
public function __construct($locale, $formatter = null, $cacheDir = null, $debug = false)
public function __construct(?string $locale, MessageFormatterInterface $formatter = null, string $cacheDir = null, bool $debug = false)
{
$this->setLocale($locale);
if ($formatter instanceof MessageSelector) {
$formatter = new MessageFormatter($formatter);
@trigger_error(sprintf('Passing a "%s" instance into the "%s" as a second argument is deprecated since Symfony 3.4 and will be removed in 4.0. Inject a "%s" implementation instead.', MessageSelector::class, __METHOD__, MessageFormatterInterface::class), E_USER_DEPRECATED);
} elseif (null === $formatter) {
if (null === $formatter) {
$formatter = new MessageFormatter();
}
@@ -283,10 +275,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface
$this->loadFallbackCatalogues($locale);
}
/**
* @param string $locale
*/
private function initializeCacheCatalogue($locale)
private function initializeCacheCatalogue(string $locale): void
{
if (isset($this->catalogues[$locale])) {
/* Catalogue already initialized. */
@@ -309,7 +298,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface
$this->catalogues[$locale] = include $cache->getPath();
}
private function dumpCatalogue($locale, ConfigCacheInterface $cache)
private function dumpCatalogue($locale, ConfigCacheInterface $cache): void
{
$this->initializeCatalogue($locale);
$fallbackContent = $this->getFallbackContent($this->catalogues[$locale]);
@@ -334,7 +323,7 @@ EOF
$cache->write($content, $this->catalogues[$locale]->getResources());
}
private function getFallbackContent(MessageCatalogue $catalogue)
private function getFallbackContent(MessageCatalogue $catalogue): string
{
$fallbackContent = '';
$current = '';
@@ -369,7 +358,7 @@ EOF
return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->fallbackLocales), true)), 0, 7), '/', '_').'.php';
}
private function doLoadCatalogue($locale)
private function doLoadCatalogue($locale): void
{
$this->catalogues[$locale] = new MessageCatalogue($locale);
@@ -383,7 +372,7 @@ EOF
}
}
private function loadFallbackCatalogues($locale)
private function loadFallbackCatalogues($locale): void
{
$current = $this->catalogues[$locale];
@@ -436,10 +425,8 @@ EOF
/**
* Provides the ConfigCache factory implementation, falling back to a
* default implementation if necessary.
*
* @return ConfigCacheFactoryInterface $configCacheFactory
*/
private function getConfigCacheFactory()
private function getConfigCacheFactory(): ConfigCacheFactoryInterface
{
if (!$this->configCacheFactory) {
$this->configCacheFactory = new ConfigCacheFactory($this->debug);

View File

@@ -38,9 +38,13 @@ class TranslationWriter implements TranslationWriterInterface
/**
* Disables dumper backup.
*
* @deprecated since Symfony 4.1
*/
public function disableBackup()
{
@trigger_error(sprintf('The %s() method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
foreach ($this->dumpers as $dumper) {
if (method_exists($dumper, 'setBackup')) {
$dumper->setBackup(false);
@@ -83,21 +87,4 @@ class TranslationWriter implements TranslationWriterInterface
// save
$dumper->dump($catalogue, $options);
}
/**
* Writes translation from the catalogue according to the selected format.
*
* @param MessageCatalogue $catalogue The message catalogue to write
* @param string $format The format to use to dump the messages
* @param array $options Options that are passed to the dumper
*
* @throws InvalidArgumentException
*
* @deprecated since 3.4 will be removed in 4.0. Use write instead.
*/
public function writeTranslations(MessageCatalogue $catalogue, $format, $options = array())
{
@trigger_error(sprintf('Method %s() is deprecated since Symfony 3.4 and will be removed in 4.0. Use write() instead.', __METHOD__), E_USER_DEPRECATED);
$this->write($catalogue, $format, $options);
}
}

View File

@@ -16,26 +16,27 @@
}
],
"require": {
"php": "^5.5.9|>=7.0.8",
"php": "^7.1.3",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"symfony/config": "~2.8|~3.0|~4.0",
"symfony/config": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/intl": "^2.8.18|^3.2.5|~4.0",
"symfony/intl": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0",
"symfony/finder": "~2.8|~3.0|~4.0",
"psr/log": "~1.0"
},
"conflict": {
"symfony/config": "<2.8",
"symfony/config": "<3.4",
"symfony/dependency-injection": "<3.4",
"symfony/yaml": "<3.4"
},
"suggest": {
"symfony/config": "",
"symfony/yaml": "",
"psr/log": "To use logging capability in translator"
"psr/log-implementation": "To use logging capability in translator"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Translation\\": "" },
@@ -46,7 +47,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
"dev-master": "4.1-dev"
}
}
}