+ 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.
+
+
+ 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.
+
+
+
+
Notes
+
+ 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.
+
+
+ The union allows for the 'un-declaration' of xml:lang with
+ the empty string.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
space (as an attribute name)
+
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
base (as an attribute name)
+
+ 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.
+
+ 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.
+ 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:
+
+
+
+
+ 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".
+
+ This schema defines attributes and an attribute group suitable
+ for use by schemas wishing to allow xml:base,
+ xml:lang, xml:space or
+ xml:id attributes on elements they define.
+
+
+
+ To enable this, such a schema must import this schema for
+ the XML namespace, e.g. as follows:
+
+ 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
+ http://www.w3.org/2001/xml.xsd
+
+ will change accordingly; the version at
+
+ http://www.w3.org/2009/01/xml.xsd
+
+ will not change.
+
+
+
+ Previous dated (and unchanging) versions of this schema
+ document are at:
+
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/Catalogue/AbstractOperationTest.php b/vendor/symfony/translation/Tests/Catalogue/AbstractOperationTest.php
new file mode 100644
index 0000000..f82b18f
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Catalogue/AbstractOperationTest.php
@@ -0,0 +1,74 @@
+
+ *
+ * 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(
+ [],
+ $this->createOperation(
+ new MessageCatalogue('en'),
+ new MessageCatalogue('en')
+ )->getDomains()
+ );
+ }
+
+ public function testGetMergedDomains()
+ {
+ $this->assertEquals(
+ ['a', 'b', 'c'],
+ $this->createOperation(
+ new MessageCatalogue('en', ['a' => [], 'b' => []]),
+ new MessageCatalogue('en', ['b' => [], 'c' => []])
+ )->getDomains()
+ );
+ }
+
+ public function testGetMessagesFromUnknownDomain()
+ {
+ $this->expectException('InvalidArgumentException');
+ $this->createOperation(
+ new MessageCatalogue('en'),
+ new MessageCatalogue('en')
+ )->getMessages('domain');
+ }
+
+ public function testGetEmptyMessages()
+ {
+ $this->assertEquals(
+ [],
+ $this->createOperation(
+ new MessageCatalogue('en', ['a' => []]),
+ 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);
+}
diff --git a/vendor/symfony/translation/Tests/Catalogue/MergeOperationTest.php b/vendor/symfony/translation/Tests/Catalogue/MergeOperationTest.php
new file mode 100644
index 0000000..22af86e
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Catalogue/MergeOperationTest.php
@@ -0,0 +1,97 @@
+
+ *
+ * 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', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]),
+ new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'c' => 'new_c']])
+ );
+
+ $this->assertEquals(
+ ['a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'],
+ $operation->getMessages('messages')
+ );
+
+ $this->assertEquals(
+ ['c' => 'new_c'],
+ $operation->getNewMessages('messages')
+ );
+
+ $this->assertEquals(
+ [],
+ $operation->getObsoleteMessages('messages')
+ );
+ }
+
+ public function testGetResultFromSingleDomain()
+ {
+ $this->assertEquals(
+ new MessageCatalogue('en', [
+ 'messages' => ['a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'],
+ ]),
+ $this->createOperation(
+ new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]),
+ new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'c' => 'new_c']])
+ )->getResult()
+ );
+ }
+
+ public function testGetResultFromIntlDomain()
+ {
+ $this->assertEquals(
+ new MessageCatalogue('en', [
+ 'messages' => ['a' => 'old_a', 'b' => 'old_b'],
+ 'messages+intl-icu' => ['d' => 'old_d', 'c' => 'new_c'],
+ ]),
+ $this->createOperation(
+ new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b'], 'messages+intl-icu' => ['d' => 'old_d']]),
+ new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'new_a', 'c' => 'new_c']])
+ )->getResult()
+ );
+ }
+
+ public function testGetResultWithMetadata()
+ {
+ $leftCatalogue = new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]);
+ $leftCatalogue->setMetadata('a', 'foo', 'messages');
+ $leftCatalogue->setMetadata('b', 'bar', 'messages');
+ $rightCatalogue = new MessageCatalogue('en', ['messages' => ['b' => 'new_b', 'c' => 'new_c']]);
+ $rightCatalogue->setMetadata('b', 'baz', 'messages');
+ $rightCatalogue->setMetadata('c', 'qux', 'messages');
+
+ $mergedCatalogue = new MessageCatalogue('en', ['messages' => ['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);
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Catalogue/TargetOperationTest.php b/vendor/symfony/translation/Tests/Catalogue/TargetOperationTest.php
new file mode 100644
index 0000000..570b503
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Catalogue/TargetOperationTest.php
@@ -0,0 +1,96 @@
+
+ *
+ * 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', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]),
+ new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'c' => 'new_c']])
+ );
+
+ $this->assertEquals(
+ ['a' => 'old_a', 'c' => 'new_c'],
+ $operation->getMessages('messages')
+ );
+
+ $this->assertEquals(
+ ['c' => 'new_c'],
+ $operation->getNewMessages('messages')
+ );
+
+ $this->assertEquals(
+ ['b' => 'old_b'],
+ $operation->getObsoleteMessages('messages')
+ );
+ }
+
+ public function testGetResultFromSingleDomain()
+ {
+ $this->assertEquals(
+ new MessageCatalogue('en', [
+ 'messages' => ['a' => 'old_a', 'c' => 'new_c'],
+ ]),
+ $this->createOperation(
+ new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]),
+ new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'c' => 'new_c']])
+ )->getResult()
+ );
+ }
+
+ public function testGetResultFromIntlDomain()
+ {
+ $this->assertEquals(
+ new MessageCatalogue('en', [
+ 'messages' => ['a' => 'old_a'],
+ 'messages+intl-icu' => ['c' => 'new_c'],
+ ]),
+ $this->createOperation(
+ new MessageCatalogue('en', ['messages' => ['a' => 'old_a'], 'messages+intl-icu' => ['b' => 'old_b']]),
+ new MessageCatalogue('en', ['messages' => ['a' => 'new_a'], 'messages+intl-icu' => ['c' => 'new_c']])
+ )->getResult()
+ );
+ }
+
+ public function testGetResultWithMetadata()
+ {
+ $leftCatalogue = new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]);
+ $leftCatalogue->setMetadata('a', 'foo', 'messages');
+ $leftCatalogue->setMetadata('b', 'bar', 'messages');
+ $rightCatalogue = new MessageCatalogue('en', ['messages' => ['b' => 'new_b', 'c' => 'new_c']]);
+ $rightCatalogue->setMetadata('b', 'baz', 'messages');
+ $rightCatalogue->setMetadata('c', 'qux', 'messages');
+
+ $diffCatalogue = new MessageCatalogue('en', ['messages' => ['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);
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Command/XliffLintCommandTest.php b/vendor/symfony/translation/Tests/Command/XliffLintCommandTest.php
new file mode 100644
index 0000000..df2e2f0
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Command/XliffLintCommandTest.php
@@ -0,0 +1,218 @@
+
+ *
+ * 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
+ */
+class XliffLintCommandTest extends TestCase
+{
+ private $files;
+
+ public function testLintCorrectFile()
+ {
+ $tester = $this->createCommandTester();
+ $filename = $this->createFile();
+
+ $tester->execute(
+ ['filename' => $filename],
+ ['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 testLintCorrectFiles()
+ {
+ $tester = $this->createCommandTester();
+ $filename1 = $this->createFile();
+ $filename2 = $this->createFile();
+
+ $tester->execute(
+ ['filename' => [$filename1, $filename2]],
+ ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]
+ );
+
+ $this->assertEquals(0, $tester->getStatusCode(), 'Returns 0 in case of success');
+ $this->assertContains('OK', trim($tester->getDisplay()));
+ }
+
+ /**
+ * @dataProvider provideStrictFilenames
+ */
+ public function testStrictFilenames($requireStrictFileNames, $fileNamePattern, $targetLanguage, $mustFail)
+ {
+ $tester = $this->createCommandTester($requireStrictFileNames);
+ $filename = $this->createFile('note', $targetLanguage, $fileNamePattern);
+
+ $tester->execute(
+ ['filename' => $filename],
+ ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]
+ );
+
+ $this->assertEquals($mustFail ? 1 : 0, $tester->getStatusCode());
+ $this->assertContains($mustFail ? '[WARNING] 0 XLIFF files have valid syntax and 1 contain errors.' : '[OK] All 1 XLIFF files contain valid syntax.', $tester->getDisplay());
+ }
+
+ public function testLintIncorrectXmlSyntax()
+ {
+ $tester = $this->createCommandTester();
+ $filename = $this->createFile('note ');
+
+ $tester->execute(['filename' => $filename], ['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(['filename' => $filename], ['decorated' => false]);
+
+ $this->assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error');
+ $this->assertContains('There is a mismatch between the language included in the file name ("messages.en.xlf") and the "es" value used in the "target-language" attribute of the file.', trim($tester->getDisplay()));
+ }
+
+ public function testLintTargetLanguageIsCaseInsensitive()
+ {
+ $tester = $this->createCommandTester();
+ $filename = $this->createFile('note', 'zh-cn', 'messages.zh_CN.xlf');
+
+ $tester->execute(['filename' => $filename], ['decorated' => false]);
+
+ $this->assertEquals(0, $tester->getStatusCode());
+ $this->assertContains('[OK] All 1 XLIFF files contain valid syntax.', trim($tester->getDisplay()));
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testLintFileNotReadable()
+ {
+ $tester = $this->createCommandTester();
+ $filename = $this->createFile();
+ unlink($filename);
+
+ $tester->execute(['filename' => $filename], ['decorated' => false]);
+ }
+
+ public function testGetHelp()
+ {
+ $command = new XliffLintCommand();
+ $expected = <<%command.name% command lints a XLIFF file and outputs to STDOUT
+the first encountered syntax error.
+
+You can validates XLIFF contents passed from STDIN:
+
+ cat filename | php %command.full_name%
+
+You can also validate the syntax of a file:
+
+ php %command.full_name% filename
+
+Or of a whole directory:
+
+ php %command.full_name% dirname
+ php %command.full_name% dirname --format=json
+
+EOF;
+
+ $this->assertEquals($expected, $command->getHelp());
+ }
+
+ /**
+ * @return string Path to the new file
+ */
+ private function createFile($sourceContent = 'note', $targetLanguage = 'en', $fileNamePattern = 'messages.%locale%.xlf')
+ {
+ $xliffContent = <<
+
+
+
+
+ $sourceContent
+ NOTE
+
+
+
+
+XLIFF;
+
+ $filename = sprintf('%s/translation-xliff-lint-test/%s', sys_get_temp_dir(), str_replace('%locale%', 'en', $fileNamePattern));
+ file_put_contents($filename, $xliffContent);
+
+ $this->files[] = $filename;
+
+ return $filename;
+ }
+
+ /**
+ * @return CommandTester
+ */
+ private function createCommandTester($requireStrictFileNames = true, $application = null)
+ {
+ if (!$application) {
+ $application = new Application();
+ $application->add(new XliffLintCommand(null, null, null, $requireStrictFileNames));
+ }
+
+ $command = $application->find('lint:xliff');
+
+ if ($application) {
+ $command->setApplication($application);
+ }
+
+ return new CommandTester($command);
+ }
+
+ protected function setUp()
+ {
+ $this->files = [];
+ @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');
+ }
+
+ public function provideStrictFilenames()
+ {
+ yield [false, 'messages.%locale%.xlf', 'en', false];
+ yield [false, 'messages.%locale%.xlf', 'es', true];
+ yield [false, '%locale%.messages.xlf', 'en', false];
+ yield [false, '%locale%.messages.xlf', 'es', true];
+ yield [true, 'messages.%locale%.xlf', 'en', false];
+ yield [true, 'messages.%locale%.xlf', 'es', true];
+ yield [true, '%locale%.messages.xlf', 'en', true];
+ yield [true, '%locale%.messages.xlf', 'es', true];
+ }
+}
diff --git a/vendor/symfony/translation/Tests/DataCollector/TranslationDataCollectorTest.php b/vendor/symfony/translation/Tests/DataCollector/TranslationDataCollectorTest.php
new file mode 100644
index 0000000..bd97a24
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DataCollector/TranslationDataCollectorTest.php
@@ -0,0 +1,150 @@
+
+ *
+ * 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')->willReturn([]);
+
+ $dataCollector = new TranslationDataCollector($translator);
+ $dataCollector->lateCollect();
+
+ $this->assertEquals(0, $dataCollector->getCountMissings());
+ $this->assertEquals(0, $dataCollector->getCountFallbacks());
+ $this->assertEquals(0, $dataCollector->getCountDefines());
+ $this->assertEquals([], $dataCollector->getMessages()->getValue());
+ }
+
+ public function testCollect()
+ {
+ $collectedMessages = [
+ [
+ 'id' => 'foo',
+ 'translation' => 'foo (en)',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_DEFINED,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ],
+ [
+ 'id' => 'bar',
+ 'translation' => 'bar (fr)',
+ 'locale' => 'fr',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ],
+ [
+ 'id' => 'choice',
+ 'translation' => 'choice',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_MISSING,
+ 'parameters' => ['%count%' => 3],
+ 'transChoiceNumber' => 3,
+ ],
+ [
+ 'id' => 'choice',
+ 'translation' => 'choice',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_MISSING,
+ 'parameters' => ['%count%' => 3],
+ 'transChoiceNumber' => 3,
+ ],
+ [
+ 'id' => 'choice',
+ 'translation' => 'choice',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_MISSING,
+ 'parameters' => ['%count%' => 4, '%foo%' => 'bar'],
+ 'transChoiceNumber' => 4,
+ ],
+ ];
+ $expectedMessages = [
+ [
+ 'id' => 'foo',
+ 'translation' => 'foo (en)',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_DEFINED,
+ 'count' => 1,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ],
+ [
+ 'id' => 'bar',
+ 'translation' => 'bar (fr)',
+ 'locale' => 'fr',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
+ 'count' => 1,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ],
+ [
+ 'id' => 'choice',
+ 'translation' => 'choice',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_MISSING,
+ 'count' => 3,
+ 'parameters' => [
+ ['%count%' => 3],
+ ['%count%' => 3],
+ ['%count%' => 4, '%foo%' => 'bar'],
+ ],
+ 'transChoiceNumber' => 3,
+ ],
+ ];
+
+ $translator = $this->getTranslator();
+ $translator->expects($this->any())->method('getCollectedMessages')->willReturn($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;
+ }
+}
diff --git a/vendor/symfony/translation/Tests/DataCollectorTranslatorTest.php b/vendor/symfony/translation/Tests/DataCollectorTranslatorTest.php
new file mode 100644
index 0000000..138172e
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DataCollectorTranslatorTest.php
@@ -0,0 +1,116 @@
+
+ *
+ * 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(['fr', 'ru']);
+
+ $collector->trans('foo');
+ $collector->trans('bar');
+ $collector->trans('choice', ['%count%' => 0]);
+ $collector->trans('bar_ru');
+ $collector->trans('bar_ru', ['foo' => 'bar']);
+
+ $expectedMessages = [];
+ $expectedMessages[] = [
+ 'id' => 'foo',
+ 'translation' => 'foo (en)',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_DEFINED,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ];
+ $expectedMessages[] = [
+ 'id' => 'bar',
+ 'translation' => 'bar (fr)',
+ 'locale' => 'fr',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ];
+ $expectedMessages[] = [
+ 'id' => 'choice',
+ 'translation' => 'choice',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_MISSING,
+ 'parameters' => ['%count%' => 0],
+ 'transChoiceNumber' => 0,
+ ];
+ $expectedMessages[] = [
+ 'id' => 'bar_ru',
+ 'translation' => 'bar (ru)',
+ 'locale' => 'ru',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ];
+ $expectedMessages[] = [
+ 'id' => 'bar_ru',
+ 'translation' => 'bar (ru)',
+ 'locale' => 'ru',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
+ 'parameters' => ['foo' => 'bar'],
+ 'transChoiceNumber' => null,
+ ];
+
+ $this->assertEquals($expectedMessages, $collector->getCollectedMessages());
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testCollectMessagesTransChoice()
+ {
+ $collector = $this->createCollector();
+ $collector->setFallbackLocales(['fr', 'ru']);
+ $collector->transChoice('choice', 0);
+
+ $expectedMessages = [];
+
+ $expectedMessages[] = [
+ 'id' => 'choice',
+ 'translation' => 'choice',
+ 'locale' => 'en',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_MISSING,
+ 'parameters' => ['%count%' => 0],
+ 'transChoiceNumber' => 0,
+ ];
+
+ $this->assertEquals($expectedMessages, $collector->getCollectedMessages());
+ }
+
+ private function createCollector()
+ {
+ $translator = new Translator('en');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foo (en)'], 'en');
+ $translator->addResource('array', ['bar' => 'bar (fr)'], 'fr');
+ $translator->addResource('array', ['bar_ru' => 'bar (ru)'], 'ru');
+
+ return new DataCollectorTranslator($translator);
+ }
+}
diff --git a/vendor/symfony/translation/Tests/DependencyInjection/TranslationDumperPassTest.php b/vendor/symfony/translation/Tests/DependencyInjection/TranslationDumperPassTest.php
new file mode 100644
index 0000000..94769e9
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DependencyInjection/TranslationDumperPassTest.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+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;
+
+class TranslationDumperPassTest extends TestCase
+{
+ public function testProcess()
+ {
+ $container = new ContainerBuilder();
+ $writerDefinition = $container->register('translation.writer');
+ $container->register('foo.id')
+ ->addTag('translation.dumper', ['alias' => 'bar.alias']);
+
+ $translationDumperPass = new TranslationDumperPass();
+ $translationDumperPass->process($container);
+
+ $this->assertEquals([['addDumper', ['bar.alias', new Reference('foo.id')]]], $writerDefinition->getMethodCalls());
+ }
+
+ public function testProcessNoDefinitionFound()
+ {
+ $container = new ContainerBuilder();
+
+ $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());
+ }
+}
diff --git a/vendor/symfony/translation/Tests/DependencyInjection/TranslationExtractorPassTest.php b/vendor/symfony/translation/Tests/DependencyInjection/TranslationExtractorPassTest.php
new file mode 100644
index 0000000..a638498
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DependencyInjection/TranslationExtractorPassTest.php
@@ -0,0 +1,66 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+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;
+
+class TranslationExtractorPassTest extends TestCase
+{
+ public function testProcess()
+ {
+ $container = new ContainerBuilder();
+ $extractorDefinition = $container->register('translation.extractor');
+ $container->register('foo.id')
+ ->addTag('translation.extractor', ['alias' => 'bar.alias']);
+
+ $translationDumperPass = new TranslationExtractorPass();
+ $translationDumperPass->process($container);
+
+ $this->assertEquals([['addExtractor', ['bar.alias', new Reference('foo.id')]]], $extractorDefinition->getMethodCalls());
+ }
+
+ public function testProcessNoDefinitionFound()
+ {
+ $container = new ContainerBuilder();
+
+ $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());
+ }
+
+ /**
+ * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
+ * @expectedExceptionMessage The alias for the tag "translation.extractor" of service "foo.id" must be set.
+ */
+ public function testProcessMissingAlias()
+ {
+ $definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->disableOriginalConstructor()->getMock();
+ $container = new ContainerBuilder();
+ $container->register('translation.extractor');
+ $container->register('foo.id')
+ ->addTag('translation.extractor', []);
+
+ $definition->expects($this->never())->method('addMethodCall');
+
+ $translationDumperPass = new TranslationExtractorPass();
+ $translationDumperPass->process($container);
+ }
+}
diff --git a/vendor/symfony/translation/Tests/DependencyInjection/TranslationPassTest.php b/vendor/symfony/translation/Tests/DependencyInjection/TranslationPassTest.php
new file mode 100644
index 0000000..f62fc85
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DependencyInjection/TranslationPassTest.php
@@ -0,0 +1,122 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests\DependencyInjection;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
+
+class TranslationPassTest extends TestCase
+{
+ public function testValidCollector()
+ {
+ $loader = (new Definition())
+ ->addTag('translation.loader', ['alias' => 'xliff', 'legacy-alias' => 'xlf']);
+
+ $reader = new Definition();
+
+ $translator = (new Definition())
+ ->setArguments([null, null, null, null]);
+
+ $container = new ContainerBuilder();
+ $container->setDefinition('translator.default', $translator);
+ $container->setDefinition('translation.reader', $reader);
+ $container->setDefinition('translation.xliff_loader', $loader);
+
+ $pass = new TranslatorPass('translator.default', 'translation.reader');
+ $pass->process($container);
+
+ $expectedReader = (new Definition())
+ ->addMethodCall('addLoader', ['xliff', new Reference('translation.xliff_loader')])
+ ->addMethodCall('addLoader', ['xlf', new Reference('translation.xliff_loader')])
+ ;
+ $this->assertEquals($expectedReader, $reader);
+
+ $expectedLoader = (new Definition())
+ ->addTag('translation.loader', ['alias' => 'xliff', 'legacy-alias' => 'xlf'])
+ ;
+ $this->assertEquals($expectedLoader, $loader);
+
+ $this->assertSame(['translation.xliff_loader' => ['xliff', 'xlf']], $translator->getArgument(3));
+
+ $expected = ['translation.xliff_loader' => new ServiceClosureArgument(new Reference('translation.xliff_loader'))];
+ $this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));
+ }
+
+ public function testValidCommandsViewPathsArgument()
+ {
+ $container = new ContainerBuilder();
+ $container->register('translator.default')
+ ->setArguments([null, null, null, null])
+ ;
+ $debugCommand = $container->register('console.command.translation_debug')
+ ->setArguments([null, null, null, null, null, [], []])
+ ;
+ $updateCommand = $container->register('console.command.translation_update')
+ ->setArguments([null, null, null, null, null, null, [], []])
+ ;
+ $container->register('twig.template_iterator')
+ ->setArguments([null, null, ['other/templates' => null, 'tpl' => 'App']])
+ ;
+ $container->setParameter('twig.default_path', 'templates');
+
+ $pass = new TranslatorPass('translator.default');
+ $pass->process($container);
+
+ $expectedViewPaths = ['other/templates', 'tpl'];
+
+ $this->assertSame('templates', $debugCommand->getArgument(4));
+ $this->assertSame('templates', $updateCommand->getArgument(5));
+ $this->assertSame($expectedViewPaths, $debugCommand->getArgument(6));
+ $this->assertSame($expectedViewPaths, $updateCommand->getArgument(7));
+ }
+
+ public function testCommandsViewPathsArgumentsAreIgnoredWithOldServiceDefinitions()
+ {
+ $container = new ContainerBuilder();
+ $container->register('translator.default')
+ ->setArguments([null, null, null, null])
+ ;
+ $debugCommand = $container->register('console.command.translation_debug')
+ ->setArguments([
+ new Reference('translator'),
+ new Reference('translation.reader'),
+ new Reference('translation.extractor'),
+ '%translator.default_path%',
+ null,
+ ])
+ ;
+ $updateCommand = $container->register('console.command.translation_update')
+ ->setArguments([
+ new Reference('translation.writer'),
+ new Reference('translation.reader'),
+ new Reference('translation.extractor'),
+ '%kernel.default_locale%',
+ '%translator.default_path%',
+ null,
+ ])
+ ;
+ $container->register('twig.template_iterator')
+ ->setArguments([null, null, ['other/templates' => null, 'tpl' => 'App']])
+ ;
+ $container->setParameter('twig.default_path', 'templates');
+
+ $pass = new TranslatorPass('translator.default');
+ $pass->process($container);
+
+ $this->assertSame('templates', $debugCommand->getArgument(4));
+ $this->assertSame('templates', $updateCommand->getArgument(5));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/DependencyInjection/TranslationPathsPassTest.php b/vendor/symfony/translation/Tests/DependencyInjection/TranslationPathsPassTest.php
new file mode 100644
index 0000000..42ab398
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DependencyInjection/TranslationPathsPassTest.php
@@ -0,0 +1,89 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests\DependencyInjection;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\ServiceLocator;
+use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass;
+use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ControllerArguments;
+use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceArguments;
+use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceMethodCalls;
+use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceProperties;
+use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceSubscriber;
+
+class TranslationPathsPassTest extends TestCase
+{
+ public function testProcess()
+ {
+ $container = new ContainerBuilder();
+ $container->register('translator');
+ $debugCommand = $container->register('console.command.translation_debug')
+ ->setArguments([null, null, null, null, null, [], []])
+ ;
+ $updateCommand = $container->register('console.command.translation_update')
+ ->setArguments([null, null, null, null, null, null, [], []])
+ ;
+ $container->register(ControllerArguments::class, ControllerArguments::class)
+ ->setTags(['controller.service_arguments'])
+ ;
+ $container->register(ServiceArguments::class, ServiceArguments::class)
+ ->setArguments([new Reference('translator')])
+ ;
+ $container->register(ServiceProperties::class, ServiceProperties::class)
+ ->setProperties([new Reference('translator')])
+ ;
+ $container->register(ServiceMethodCalls::class, ServiceMethodCalls::class)
+ ->setMethodCalls([['setTranslator', [new Reference('translator')]]])
+ ;
+ $container->register('service_rc')
+ ->setArguments([new Definition(), new Reference(ServiceMethodCalls::class)])
+ ;
+ $serviceLocator1 = $container->register('.service_locator.foo', ServiceLocator::class)
+ ->setArguments([new ServiceClosureArgument(new Reference('translator'))])
+ ;
+ $serviceLocator2 = (new Definition(ServiceLocator::class))
+ ->setArguments([ServiceSubscriber::class, new Reference('service_container')])
+ ->setFactory([$serviceLocator1, 'withContext'])
+ ;
+ $container->register('service_subscriber', ServiceSubscriber::class)
+ ->setArguments([$serviceLocator2])
+ ;
+ $container->register('.service_locator.bar', ServiceLocator::class)
+ ->setArguments([[
+ ControllerArguments::class.'::index' => new ServiceClosureArgument(new Reference('.service_locator.foo')),
+ ControllerArguments::class.'::__invoke' => new ServiceClosureArgument(new Reference('.service_locator.foo')),
+ ControllerArguments::class => new ServiceClosureArgument(new Reference('.service_locator.foo')),
+ ]])
+ ;
+ $container->register('argument_resolver.service')
+ ->setArguments([new Reference('.service_locator.bar')])
+ ;
+
+ $pass = new TranslatorPathsPass('translator', 'console.command.translation_debug', 'console.command.translation_update', 'argument_resolver.service');
+ $pass->process($container);
+
+ $expectedPaths = [
+ $container->getReflectionClass(ServiceArguments::class)->getFileName(),
+ $container->getReflectionClass(ServiceProperties::class)->getFileName(),
+ $container->getReflectionClass(ServiceMethodCalls::class)->getFileName(),
+ $container->getReflectionClass(ControllerArguments::class)->getFileName(),
+ $container->getReflectionClass(ServiceSubscriber::class)->getFileName(),
+ ];
+
+ $this->assertSame($expectedPaths, $debugCommand->getArgument(6));
+ $this->assertSame($expectedPaths, $updateCommand->getArgument(7));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ControllerArguments.php b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ControllerArguments.php
new file mode 100644
index 0000000..97a53fa
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ControllerArguments.php
@@ -0,0 +1,16 @@
+ TranslatorInterface::class];
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/CsvFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/CsvFileDumperTest.php
new file mode 100644
index 0000000..0d1cf2c
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/CsvFileDumperTest.php
@@ -0,0 +1,30 @@
+
+ *
+ * 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(['foo' => 'bar', 'bar' => 'foo
+foo', 'foo;foo' => 'bar']);
+
+ $dumper = new CsvFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/valid.csv', $dumper->formatCatalogue($catalogue, 'messages'));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/FileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/FileDumperTest.php
new file mode 100644
index 0000000..20fa918
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/FileDumperTest.php
@@ -0,0 +1,90 @@
+
+ *
+ * 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(['foo' => 'bar']);
+
+ $dumper = new ConcreteFileDumper();
+ $dumper->dump($catalogue, ['path' => $tempDir]);
+
+ $this->assertFileExists($tempDir.'/messages.en.concrete');
+
+ @unlink($tempDir.'/messages.en.concrete');
+ }
+
+ public function testDumpIntl()
+ {
+ $tempDir = sys_get_temp_dir();
+
+ $catalogue = new MessageCatalogue('en');
+ $catalogue->add(['foo' => 'bar'], 'd1');
+ $catalogue->add(['bar' => 'foo'], 'd1+intl-icu');
+ $catalogue->add(['bar' => 'foo'], 'd2+intl-icu');
+
+ $dumper = new ConcreteFileDumper();
+ @unlink($tempDir.'/d2.en.concrete');
+ $dumper->dump($catalogue, ['path' => $tempDir]);
+
+ $this->assertStringEqualsFile($tempDir.'/d1.en.concrete', 'foo=bar');
+ @unlink($tempDir.'/d1.en.concrete');
+
+ $this->assertStringEqualsFile($tempDir.'/d1+intl-icu.en.concrete', 'bar=foo');
+ @unlink($tempDir.'/d1+intl-icu.en.concrete');
+
+ $this->assertFileNotExists($tempDir.'/d2.en.concrete');
+ $this->assertStringEqualsFile($tempDir.'/d2+intl-icu.en.concrete', 'bar=foo');
+ @unlink($tempDir.'/d2+intl-icu.en.concrete');
+ }
+
+ public function testDumpCreatesNestedDirectoriesAndFile()
+ {
+ $tempDir = sys_get_temp_dir();
+ $translationsDir = $tempDir.'/test/translations';
+ $file = $translationsDir.'/messages.en.concrete';
+
+ $catalogue = new MessageCatalogue('en');
+ $catalogue->add(['foo' => 'bar']);
+
+ $dumper = new ConcreteFileDumper();
+ $dumper->setRelativePathTemplate('test/translations/%domain%.%locale%.%extension%');
+ $dumper->dump($catalogue, ['path' => $tempDir]);
+
+ $this->assertFileExists($file);
+
+ @unlink($file);
+ @rmdir($translationsDir);
+ }
+}
+
+class ConcreteFileDumper extends FileDumper
+{
+ public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
+ {
+ return http_build_query($messages->all($domain), '', '&');
+ }
+
+ protected function getExtension()
+ {
+ return 'concrete';
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/IcuResFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/IcuResFileDumperTest.php
new file mode 100644
index 0000000..dcb9c2c
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/IcuResFileDumperTest.php
@@ -0,0 +1,29 @@
+
+ *
+ * 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(['foo' => 'bar']);
+
+ $dumper = new IcuResFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/resourcebundle/res/en.res', $dumper->formatCatalogue($catalogue, 'messages'));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/IniFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/IniFileDumperTest.php
new file mode 100644
index 0000000..1ed168b
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/IniFileDumperTest.php
@@ -0,0 +1,29 @@
+
+ *
+ * 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(['foo' => 'bar']);
+
+ $dumper = new IniFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.ini', $dumper->formatCatalogue($catalogue, 'messages'));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/JsonFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/JsonFileDumperTest.php
new file mode 100644
index 0000000..04e3d86
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/JsonFileDumperTest.php
@@ -0,0 +1,39 @@
+
+ *
+ * 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(['foo' => 'bar']);
+
+ $dumper = new JsonFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.json', $dumper->formatCatalogue($catalogue, 'messages'));
+ }
+
+ public function testDumpWithCustomEncoding()
+ {
+ $catalogue = new MessageCatalogue('en');
+ $catalogue->add(['foo' => '"bar"']);
+
+ $dumper = new JsonFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.dump.json', $dumper->formatCatalogue($catalogue, 'messages', ['json_encoding' => JSON_HEX_QUOT]));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/MoFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/MoFileDumperTest.php
new file mode 100644
index 0000000..fbbd75d
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/MoFileDumperTest.php
@@ -0,0 +1,29 @@
+
+ *
+ * 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(['foo' => 'bar']);
+
+ $dumper = new MoFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.mo', $dumper->formatCatalogue($catalogue, 'messages'));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/PhpFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/PhpFileDumperTest.php
new file mode 100644
index 0000000..00e535d
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/PhpFileDumperTest.php
@@ -0,0 +1,29 @@
+
+ *
+ * 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(['foo' => 'bar']);
+
+ $dumper = new PhpFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.php', $dumper->formatCatalogue($catalogue, 'messages'));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/PoFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/PoFileDumperTest.php
new file mode 100644
index 0000000..46df869
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/PoFileDumperTest.php
@@ -0,0 +1,48 @@
+
+ *
+ * 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(['foo' => 'bar', 'bar' => 'foo', 'foo_bar' => 'foobar', 'bar_foo' => 'barfoo']);
+ $catalogue->setMetadata('foo_bar', [
+ 'comments' => [
+ 'Comment 1',
+ 'Comment 2',
+ ],
+ 'flags' => [
+ 'fuzzy',
+ 'another',
+ ],
+ 'sources' => [
+ 'src/file_1',
+ 'src/file_2:50',
+ ],
+ ]);
+ $catalogue->setMetadata('bar_foo', [
+ 'comments' => 'Comment',
+ 'flags' => 'fuzzy',
+ 'sources' => 'src/file_1',
+ ]);
+
+ $dumper = new PoFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.po', $dumper->formatCatalogue($catalogue, 'messages'));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/QtFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/QtFileDumperTest.php
new file mode 100644
index 0000000..6c4b559
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/QtFileDumperTest.php
@@ -0,0 +1,48 @@
+
+ *
+ * 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(['foo' => 'bar', 'foo_bar' => 'foobar', 'bar_foo' => 'barfoo'], 'resources');
+ $catalogue->setMetadata('foo_bar', [
+ 'comments' => [
+ 'Comment 1',
+ 'Comment 2',
+ ],
+ 'flags' => [
+ 'fuzzy',
+ 'another',
+ ],
+ 'sources' => [
+ 'src/file_1',
+ 'src/file_2:50',
+ ],
+ ], 'resources');
+ $catalogue->setMetadata('bar_foo', [
+ 'comments' => 'Comment',
+ 'flags' => 'fuzzy',
+ 'sources' => 'src/file_1',
+ ], 'resources');
+
+ $dumper = new QtFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/resources.ts', $dumper->formatCatalogue($catalogue, 'resources'));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/XliffFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/XliffFileDumperTest.php
new file mode 100644
index 0000000..6377132
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/XliffFileDumperTest.php
@@ -0,0 +1,130 @@
+
+ *
+ * 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([
+ 'foo' => 'bar',
+ 'key' => '',
+ 'key.with.cdata' => ' & ',
+ ]);
+ $catalogue->setMetadata('foo', ['notes' => [['priority' => 1, 'from' => 'bar', 'content' => 'baz']]]);
+ $catalogue->setMetadata('key', ['notes' => [['content' => 'baz'], ['content' => 'qux']]]);
+
+ $dumper = new XliffFileDumper();
+
+ $this->assertStringEqualsFile(
+ __DIR__.'/../fixtures/resources-clean.xlf',
+ $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR'])
+ );
+ }
+
+ public function testFormatCatalogueXliff2()
+ {
+ $catalogue = new MessageCatalogue('en_US');
+ $catalogue->add([
+ 'foo' => 'bar',
+ 'key' => '',
+ 'key.with.cdata' => ' & ',
+ ]);
+ $catalogue->setMetadata('key', ['target-attributes' => ['order' => 1]]);
+
+ $dumper = new XliffFileDumper();
+
+ $this->assertStringEqualsFile(
+ __DIR__.'/../fixtures/resources-2.0-clean.xlf',
+ $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR', 'xliff_version' => '2.0'])
+ );
+ }
+
+ public function testFormatIcuCatalogueXliff2()
+ {
+ $catalogue = new MessageCatalogue('en_US');
+ $catalogue->add([
+ 'foo' => 'bar',
+ ], 'messages'.MessageCatalogue::INTL_DOMAIN_SUFFIX);
+
+ $dumper = new XliffFileDumper();
+
+ $this->assertStringEqualsFile(
+ __DIR__.'/../fixtures/resources-2.0+intl-icu.xlf',
+ $dumper->formatCatalogue($catalogue, 'messages'.MessageCatalogue::INTL_DOMAIN_SUFFIX, ['default_locale' => 'fr_FR', 'xliff_version' => '2.0'])
+ );
+ }
+
+ public function testFormatCatalogueWithCustomToolInfo()
+ {
+ $options = [
+ 'default_locale' => 'en_US',
+ 'tool_info' => ['tool-id' => 'foo', 'tool-name' => 'foo', 'tool-version' => '0.0', 'tool-company' => 'Foo'],
+ ];
+
+ $catalogue = new MessageCatalogue('en_US');
+ $catalogue->add(['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([
+ 'foo' => 'bar',
+ ]);
+ $catalogue->setMetadata('foo', ['target-attributes' => ['state' => 'needs-translation']]);
+
+ $dumper = new XliffFileDumper();
+
+ $this->assertStringEqualsFile(
+ __DIR__.'/../fixtures/resources-target-attributes.xlf',
+ $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR'])
+ );
+ }
+
+ public function testFormatCatalogueWithNotesMetadata()
+ {
+ $catalogue = new MessageCatalogue('en_US');
+ $catalogue->add([
+ 'foo' => 'bar',
+ 'baz' => 'biz',
+ ]);
+ $catalogue->setMetadata('foo', ['notes' => [
+ ['category' => 'state', 'content' => 'new'],
+ ['category' => 'approved', 'content' => 'true'],
+ ['category' => 'section', 'content' => 'user login', 'priority' => '1'],
+ ]]);
+ $catalogue->setMetadata('baz', ['notes' => [
+ ['id' => 'x', 'content' => 'x_content'],
+ ['appliesTo' => 'target', 'category' => 'quality', 'content' => 'Fuzzy'],
+ ]]);
+
+ $dumper = new XliffFileDumper();
+
+ $this->assertStringEqualsFile(
+ __DIR__.'/../fixtures/resources-notes-meta.xlf',
+ $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR', 'xliff_version' => '2.0'])
+ );
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Dumper/YamlFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/YamlFileDumperTest.php
new file mode 100644
index 0000000..e46da5a
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Dumper/YamlFileDumperTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * 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([
+ 'foo.bar1' => 'value1',
+ 'foo.bar2' => 'value2',
+ ]);
+
+ $dumper = new YamlFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/messages.yml', $dumper->formatCatalogue($catalogue, 'messages', ['as_tree' => true, 'inline' => 999]));
+ }
+
+ public function testLinearFormatCatalogue()
+ {
+ $catalogue = new MessageCatalogue('en');
+ $catalogue->add([
+ 'foo.bar1' => 'value1',
+ 'foo.bar2' => 'value2',
+ ]);
+
+ $dumper = new YamlFileDumper();
+
+ $this->assertStringEqualsFile(__DIR__.'/../fixtures/messages_linear.yml', $dumper->formatCatalogue($catalogue, 'messages'));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Extractor/PhpExtractorTest.php b/vendor/symfony/translation/Tests/Extractor/PhpExtractorTest.php
new file mode 100644
index 0000000..a6d7c50
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Extractor/PhpExtractorTest.php
@@ -0,0 +1,101 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests\Extractor;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Translation\Extractor\PhpExtractor;
+use Symfony\Component\Translation\MessageCatalogue;
+
+class PhpExtractorTest extends TestCase
+{
+ /**
+ * @dataProvider resourcesProvider
+ *
+ * @param array|string $resource
+ */
+ public function testExtraction($resource)
+ {
+ // Arrange
+ $extractor = new PhpExtractor();
+ $extractor->setPrefix('prefix');
+ $catalogue = new MessageCatalogue('en');
+
+ // Act
+ $extractor->extract($resource, $catalogue);
+
+ $expectedHeredoc = << [
+ 'single-quoted key' => 'prefixsingle-quoted key',
+ 'double-quoted key' => 'prefixdouble-quoted key',
+ 'heredoc key' => 'prefixheredoc key',
+ 'nowdoc key' => 'prefixnowdoc key',
+ "double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixdouble-quoted key with whitespace and escaped \$\n\" sequences",
+ 'single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixsingle-quoted key with whitespace and nonescaped \$\n\' sequences',
+ 'single-quoted key with "quote mark at the end"' => 'prefixsingle-quoted key with "quote mark at the end"',
+ $expectedHeredoc => 'prefix'.$expectedHeredoc,
+ $expectedNowdoc => 'prefix'.$expectedNowdoc,
+ '{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples' => 'prefix{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples',
+ 'concatenated message with heredoc and nowdoc' => 'prefixconcatenated message with heredoc and nowdoc',
+ 'default domain' => 'prefixdefault domain',
+ ],
+ 'not_messages' => [
+ 'other-domain-test-no-params-short-array' => 'prefixother-domain-test-no-params-short-array',
+ 'other-domain-test-no-params-long-array' => 'prefixother-domain-test-no-params-long-array',
+ 'other-domain-test-params-short-array' => 'prefixother-domain-test-params-short-array',
+ 'other-domain-test-params-long-array' => 'prefixother-domain-test-params-long-array',
+ 'other-domain-test-trans-choice-short-array-%count%' => 'prefixother-domain-test-trans-choice-short-array-%count%',
+ 'other-domain-test-trans-choice-long-array-%count%' => 'prefixother-domain-test-trans-choice-long-array-%count%',
+ 'typecast' => 'prefixtypecast',
+ 'msg1' => 'prefixmsg1',
+ 'msg2' => 'prefixmsg2',
+ ],
+ ];
+ $actualCatalogue = $catalogue->all();
+
+ $this->assertEquals($expectedCatalogue, $actualCatalogue);
+
+ $filename = str_replace(\DIRECTORY_SEPARATOR, '/', __DIR__).'/../fixtures/extractor/translation.html.php';
+ $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('single-quoted key'));
+ $this->assertEquals(['sources' => [$filename.':43']], $catalogue->getMetadata('other-domain-test-no-params-short-array', 'not_messages'));
+ }
+
+ public function resourcesProvider()
+ {
+ $directory = __DIR__.'/../fixtures/extractor/';
+ $splFiles = [];
+ foreach (new \DirectoryIterator($directory) as $fileInfo) {
+ if ($fileInfo->isDot()) {
+ continue;
+ }
+ if ('translation.html.php' === $fileInfo->getBasename()) {
+ $phpFile = $fileInfo->getPathname();
+ }
+ $splFiles[] = $fileInfo->getFileInfo();
+ }
+
+ return [
+ [$directory],
+ [$phpFile],
+ [glob($directory.'*')],
+ [$splFiles],
+ [new \ArrayObject(glob($directory.'*'))],
+ [new \ArrayObject($splFiles)],
+ ];
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Formatter/IntlFormatterTest.php b/vendor/symfony/translation/Tests/Formatter/IntlFormatterTest.php
new file mode 100644
index 0000000..45ce6d4
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Formatter/IntlFormatterTest.php
@@ -0,0 +1,96 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests\Formatter;
+
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+use Symfony\Component\Translation\Formatter\IntlFormatter;
+use Symfony\Component\Translation\Formatter\IntlFormatterInterface;
+
+/**
+ * @requires extension intl
+ */
+class IntlFormatterTest extends \PHPUnit\Framework\TestCase
+{
+ /**
+ * @dataProvider provideDataForFormat
+ */
+ public function testFormat($expected, $message, $arguments)
+ {
+ $this->assertEquals($expected, trim((new IntlFormatter())->formatIntl($message, 'en', $arguments)));
+ }
+
+ public function testInvalidFormat()
+ {
+ $this->expectException(InvalidArgumentException::class);
+ (new IntlFormatter())->formatIntl('{foo', 'en', [2]);
+ }
+
+ public function testFormatWithNamedArguments()
+ {
+ if (version_compare(INTL_ICU_VERSION, '4.8', '<')) {
+ $this->markTestSkipped('Format with named arguments can only be run with ICU 4.8 or higher and PHP >= 5.5');
+ }
+
+ $chooseMessage = <<<'_MSG_'
+{gender_of_host, select,
+ female {{num_guests, plural, offset:1
+ =0 {{host} does not give a party.}
+ =1 {{host} invites {guest} to her party.}
+ =2 {{host} invites {guest} and one other person to her party.}
+ other {{host} invites {guest} as one of the # people invited to her party.}}}
+ male {{num_guests, plural, offset:1
+ =0 {{host} does not give a party.}
+ =1 {{host} invites {guest} to his party.}
+ =2 {{host} invites {guest} and one other person to his party.}
+ other {{host} invites {guest} as one of the # people invited to his party.}}}
+ other {{num_guests, plural, offset:1
+ =0 {{host} does not give a party.}
+ =1 {{host} invites {guest} to their party.}
+ =2 {{host} invites {guest} and one other person to their party.}
+ other {{host} invites {guest} as one of the # people invited to their party.}}}}
+_MSG_;
+
+ $message = (new IntlFormatter())->formatIntl($chooseMessage, 'en', [
+ 'gender_of_host' => 'male',
+ 'num_guests' => 10,
+ 'host' => 'Fabien',
+ 'guest' => 'Guilherme',
+ ]);
+
+ $this->assertEquals('Fabien invites Guilherme as one of the 9 people invited to his party.', $message);
+ }
+
+ public function provideDataForFormat()
+ {
+ return [
+ [
+ 'There is one apple',
+ 'There is one apple',
+ [],
+ ],
+ [
+ '4,560 monkeys on 123 trees make 37.073 monkeys per tree',
+ '{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree',
+ [4560, 123, 4560 / 123],
+ ],
+ ];
+ }
+
+ public function testPercentsAndBracketsAreTrimmed()
+ {
+ $formatter = new IntlFormatter();
+ $this->assertInstanceof(IntlFormatterInterface::class, $formatter);
+ $this->assertSame('Hello Fab', $formatter->formatIntl('Hello {name}', 'en', ['name' => 'Fab']));
+ $this->assertSame('Hello Fab', $formatter->formatIntl('Hello {name}', 'en', ['%name%' => 'Fab']));
+ $this->assertSame('Hello Fab', $formatter->formatIntl('Hello {name}', 'en', ['{{ name }}' => 'Fab']));
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Formatter/MessageFormatterTest.php b/vendor/symfony/translation/Tests/Formatter/MessageFormatterTest.php
new file mode 100644
index 0000000..232bcf9
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Formatter/MessageFormatterTest.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests\Formatter;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Translation\Formatter\MessageFormatter;
+
+class MessageFormatterTest extends TestCase
+{
+ /**
+ * @dataProvider getTransMessages
+ */
+ public function testFormat($expected, $message, $parameters = [])
+ {
+ $this->assertEquals($expected, $this->getMessageFormatter()->format($message, 'en', $parameters));
+ }
+
+ /**
+ * @dataProvider getTransChoiceMessages
+ * @group legacy
+ */
+ public function testFormatPlural($expected, $message, $number, $parameters)
+ {
+ $this->assertEquals($expected, $this->getMessageFormatter()->choiceFormat($message, $number, 'fr', $parameters));
+ }
+
+ public function getTransMessages()
+ {
+ return [
+ [
+ 'There is one apple',
+ 'There is one apple',
+ ],
+ [
+ 'There are 5 apples',
+ 'There are %count% apples',
+ ['%count%' => 5],
+ ],
+ [
+ 'There are 5 apples',
+ 'There are {{count}} apples',
+ ['{{count}}' => 5],
+ ],
+ ];
+ }
+
+ public function getTransChoiceMessages()
+ {
+ return [
+ ['Il y a 0 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, ['%count%' => 0]],
+ ['Il y a 1 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, ['%count%' => 1]],
+ ['Il y a 10 pommes', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, ['%count%' => 10]],
+
+ ['Il y a 0 pomme', 'Il y a %count% pomme|Il y a %count% pommes', 0, ['%count%' => 0]],
+ ['Il y a 1 pomme', 'Il y a %count% pomme|Il y a %count% pommes', 1, ['%count%' => 1]],
+ ['Il y a 10 pommes', 'Il y a %count% pomme|Il y a %count% pommes', 10, ['%count%' => 10]],
+
+ ['Il y a 0 pomme', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, ['%count%' => 0]],
+ ['Il y a 1 pomme', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, ['%count%' => 1]],
+ ['Il y a 10 pommes', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, ['%count%' => 10]],
+
+ ['Il n\'y a aucune pomme', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 0, ['%count%' => 0]],
+ ['Il y a 1 pomme', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 1, ['%count%' => 1]],
+ ['Il y a 10 pommes', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, ['%count%' => 10]],
+
+ ['Il y a 0 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, ['%count%' => 0]],
+ ];
+ }
+
+ private function getMessageFormatter()
+ {
+ return new MessageFormatter();
+ }
+}
diff --git a/vendor/symfony/translation/Tests/IdentityTranslatorTest.php b/vendor/symfony/translation/Tests/IdentityTranslatorTest.php
new file mode 100644
index 0000000..cf618d9
--- /dev/null
+++ b/vendor/symfony/translation/Tests/IdentityTranslatorTest.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests;
+
+use Symfony\Component\Translation\IdentityTranslator;
+use Symfony\Contracts\Translation\Test\TranslatorTest;
+
+class IdentityTranslatorTest extends TranslatorTest
+{
+ public function getTranslator()
+ {
+ return new IdentityTranslator();
+ }
+}
diff --git a/vendor/symfony/translation/Tests/IntervalTest.php b/vendor/symfony/translation/Tests/IntervalTest.php
new file mode 100644
index 0000000..bfd90a2
--- /dev/null
+++ b/vendor/symfony/translation/Tests/IntervalTest.php
@@ -0,0 +1,52 @@
+
+ *
+ * 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;
+
+/**
+ * @group legacy
+ */
+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 [
+ [true, 3, '{1,2, 3 ,4}'],
+ [false, 10, '{1,2, 3 ,4}'],
+ [false, 3, '[1,2]'],
+ [true, 1, '[1,2]'],
+ [true, 2, '[1,2]'],
+ [false, 1, ']1,2['],
+ [false, 2, ']1,2['],
+ [true, log(0), '[-Inf,2['],
+ [true, -log(0), '[-2,+Inf]'],
+ ];
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/CsvFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/CsvFileLoaderTest.php
new file mode 100644
index 0000000..4fd5752
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/CsvFileLoaderTest.php
@@ -0,0 +1,61 @@
+
+ *
+ * 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(['foo' => 'bar'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ }
+
+ public function testLoadDoesNothingIfEmpty()
+ {
+ $loader = new CsvFileLoader();
+ $resource = __DIR__.'/../fixtures/empty.csv';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals([], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/IcuDatFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/IcuDatFileLoaderTest.php
new file mode 100644
index 0000000..601680a
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/IcuDatFileLoaderTest.php
@@ -0,0 +1,64 @@
+
+ *
+ * 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(['symfony' => 'Symfony 2 is great'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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(['symfony' => 'Symfony 2 est génial'], $catalogue->all('domain1'));
+ $this->assertEquals('fr', $catalogue->getLocale());
+ $this->assertEquals([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');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/IcuResFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/IcuResFileLoaderTest.php
new file mode 100644
index 0000000..962c3af
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/IcuResFileLoaderTest.php
@@ -0,0 +1,51 @@
+
+ *
+ * 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(['foo' => 'bar'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/IniFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/IniFileLoaderTest.php
new file mode 100644
index 0000000..e0d8b2f
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/IniFileLoaderTest.php
@@ -0,0 +1,51 @@
+
+ *
+ * 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(['foo' => 'bar'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ }
+
+ public function testLoadDoesNothingIfEmpty()
+ {
+ $loader = new IniFileLoader();
+ $resource = __DIR__.'/../fixtures/empty.ini';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals([], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/JsonFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/JsonFileLoaderTest.php
new file mode 100644
index 0000000..4c507da
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/JsonFileLoaderTest.php
@@ -0,0 +1,62 @@
+
+ *
+ * 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(['foo' => 'bar'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ }
+
+ public function testLoadDoesNothingIfEmpty()
+ {
+ $loader = new JsonFileLoader();
+ $resource = __DIR__.'/../fixtures/empty.json';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals([], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/LocalizedTestCase.php b/vendor/symfony/translation/Tests/Loader/LocalizedTestCase.php
new file mode 100644
index 0000000..279e9fd
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/LocalizedTestCase.php
@@ -0,0 +1,24 @@
+
+ *
+ * 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.');
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/MoFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/MoFileLoaderTest.php
new file mode 100644
index 0000000..d6adecb
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/MoFileLoaderTest.php
@@ -0,0 +1,75 @@
+
+ *
+ * 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(['foo' => 'bar'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ }
+
+ public function testLoadPlurals()
+ {
+ $loader = new MoFileLoader();
+ $resource = __DIR__.'/../fixtures/plurals.mo';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals([
+ 'foo|foos' => 'bar|bars',
+ '{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',
+ ], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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([], $catalogue->all('message'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/PhpFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/PhpFileLoaderTest.php
new file mode 100644
index 0000000..68cb2d0
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/PhpFileLoaderTest.php
@@ -0,0 +1,50 @@
+
+ *
+ * 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(['foo' => 'bar'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/PoFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/PoFileLoaderTest.php
new file mode 100644
index 0000000..cb94e90
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/PoFileLoaderTest.php
@@ -0,0 +1,122 @@
+
+ *
+ * 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(['foo' => 'bar', 'bar' => 'foo'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ }
+
+ public function testLoadPlurals()
+ {
+ $loader = new PoFileLoader();
+ $resource = __DIR__.'/../fixtures/plurals.po';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals([
+ 'foo|foos' => 'bar|bars',
+ '{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',
+ ], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ }
+
+ public function testLoadDoesNothingIfEmpty()
+ {
+ $loader = new PoFileLoader();
+ $resource = __DIR__.'/../fixtures/empty.po';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals([], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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(['foo' => ''], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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"|escaped "foos"', $messages);
+ $this->assertEquals('escaped "bar"|escaped "bars"', $messages['escaped "foo"|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);
+ }
+
+ public function testMissingPlurals()
+ {
+ $loader = new PoFileLoader();
+ $resource = __DIR__.'/../fixtures/missing-plurals.po';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals([
+ 'foo|foos' => '-|bar|-|bars',
+ ], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/QtFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/QtFileLoaderTest.php
new file mode 100644
index 0000000..f149b8c
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/QtFileLoaderTest.php
@@ -0,0 +1,79 @@
+
+ *
+ * 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([
+ 'foo' => 'bar',
+ 'foo_bar' => 'foobar',
+ 'bar_foo' => 'barfoo',
+ ], $catalogue->all('resources'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/XliffFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/XliffFileLoaderTest.php
new file mode 100644
index 0000000..1ca8336
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/XliffFileLoaderTest.php
@@ -0,0 +1,331 @@
+
+ *
+ * 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([new FileResource($resource)], $catalogue->getResources());
+ $this->assertSame([], libxml_get_errors());
+ $this->assertContainsOnly('string', $catalogue->all('domain1'));
+ }
+
+ public function testLoadWithInternalErrorsEnabled()
+ {
+ $internalErrors = libxml_use_internal_errors(true);
+
+ $this->assertSame([], libxml_get_errors());
+
+ $loader = new XliffFileLoader();
+ $resource = __DIR__.'/../fixtures/resources.xlf';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ $this->assertSame([], 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([new FileResource($resource)], $catalogue->getResources());
+ }
+
+ public function testLoadWithResname()
+ {
+ $loader = new XliffFileLoader();
+ $catalogue = $loader->load(__DIR__.'/../fixtures/resname.xlf', 'en', 'domain1');
+
+ $this->assertEquals(['foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo', 'qux' => 'qux source'], $catalogue->all('domain1'));
+ }
+
+ public function testIncompleteResource()
+ {
+ $loader = new XliffFileLoader();
+ $catalogue = $loader->load(__DIR__.'/../fixtures/resources.xlf', 'en', 'domain1');
+
+ $this->assertEquals(['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(
+ [
+ 'source' => 'foo',
+ 'notes' => [['content' => utf8_decode('bäz')]],
+ 'id' => '1',
+ 'file' => [
+ 'original' => 'file.ext',
+ ],
+ ],
+ $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(
+ [
+ 'source' => 'foo',
+ 'notes' => [['priority' => 1, 'content' => 'foo']],
+ 'id' => '1',
+ 'file' => [
+ 'original' => 'file.ext',
+ ],
+ ],
+ $catalogue->getMetadata('foo', 'domain1')
+ );
+ // message without target
+ $this->assertEquals(
+ [
+ 'source' => 'extrasource',
+ 'notes' => [['content' => 'bar', 'from' => 'foo']],
+ 'id' => '2',
+ 'file' => [
+ 'original' => 'file.ext',
+ ],
+ ],
+ $catalogue->getMetadata('extra', 'domain1')
+ );
+ // message with empty target
+ $this->assertEquals(
+ [
+ 'source' => 'key',
+ 'notes' => [
+ ['content' => 'baz'],
+ ['priority' => 2, 'from' => 'bar', 'content' => 'qux'],
+ ],
+ 'id' => '123',
+ 'file' => [
+ 'original' => 'file.ext',
+ ],
+ ],
+ $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([new FileResource($resource)], $catalogue->getResources());
+ $this->assertSame([], libxml_get_errors());
+
+ $domains = $catalogue->all();
+ $this->assertCount(3, $domains['domain1']);
+ $this->assertContainsOnly('string', $catalogue->all('domain1'));
+
+ // target attributes
+ $this->assertEquals(['target-attributes' => ['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([new FileResource($resource)], $catalogue->getResources());
+ $this->assertSame([], 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([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']);
+ }
+
+ public function testLoadWithMultipleFileNodes()
+ {
+ $loader = new XliffFileLoader();
+ $catalogue = $loader->load(__DIR__.'/../fixtures/resources-multi-files.xlf', 'en', 'domain1');
+
+ $this->assertEquals(
+ [
+ 'source' => 'foo',
+ 'id' => '1',
+ 'file' => [
+ 'original' => 'file.ext',
+ ],
+ ],
+ $catalogue->getMetadata('foo', 'domain1')
+ );
+ $this->assertEquals(
+ [
+ 'source' => 'test',
+ 'notes' => [['content' => 'note']],
+ 'id' => '4',
+ 'file' => [
+ 'original' => 'otherfile.ext',
+ ],
+ ],
+ $catalogue->getMetadata('test', 'domain1')
+ );
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Loader/YamlFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/YamlFileLoaderTest.php
new file mode 100644
index 0000000..a535db5
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/YamlFileLoaderTest.php
@@ -0,0 +1,71 @@
+
+ *
+ * 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(['foo' => 'bar'], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([new FileResource($resource)], $catalogue->getResources());
+ }
+
+ public function testLoadDoesNothingIfEmpty()
+ {
+ $loader = new YamlFileLoader();
+ $resource = __DIR__.'/../fixtures/empty.yml';
+ $catalogue = $loader->load($resource, 'en', 'domain1');
+
+ $this->assertEquals([], $catalogue->all('domain1'));
+ $this->assertEquals('en', $catalogue->getLocale());
+ $this->assertEquals([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');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/LoggingTranslatorTest.php b/vendor/symfony/translation/Tests/LoggingTranslatorTest.php
new file mode 100644
index 0000000..450e060
--- /dev/null
+++ b/vendor/symfony/translation/Tests/LoggingTranslatorTest.php
@@ -0,0 +1,68 @@
+
+ *
+ * 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(1))
+ ->method('warning')
+ ->with('Translation not found.')
+ ;
+
+ $translator = new Translator('ar');
+ $loggableTranslator = new LoggingTranslator($translator, $logger);
+ $loggableTranslator->trans('bar');
+ }
+
+ /**
+ * @group legacy
+ */
+ 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(['en']);
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['some_message2' => 'one thing|%count% things'], 'en');
+ $loggableTranslator = new LoggingTranslator($translator, $logger);
+ $loggableTranslator->transChoice('some_message2', 10, ['%count%' => 10]);
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testTransChoiceWithNoTranslationIsLogged()
+ {
+ $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
+ $logger->expects($this->exactly(1))
+ ->method('warning')
+ ->with('Translation not found.')
+ ;
+
+ $translator = new Translator('ar');
+ $loggableTranslator = new LoggingTranslator($translator, $logger);
+ $loggableTranslator->transChoice('some_message2', 10, ['%count%' => 10]);
+ }
+}
diff --git a/vendor/symfony/translation/Tests/MessageCatalogueTest.php b/vendor/symfony/translation/Tests/MessageCatalogueTest.php
new file mode 100644
index 0000000..cf0dd1a
--- /dev/null
+++ b/vendor/symfony/translation/Tests/MessageCatalogueTest.php
@@ -0,0 +1,243 @@
+
+ *
+ * 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', ['domain1' => [], 'domain2' => [], 'domain2+intl-icu' => [], 'domain3+intl-icu' => []]);
+
+ $this->assertEquals(['domain1', 'domain2', 'domain3'], $catalogue->getDomains());
+ }
+
+ public function testAll()
+ {
+ $catalogue = new MessageCatalogue('en', $messages = ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar']]);
+
+ $this->assertEquals(['foo' => 'foo'], $catalogue->all('domain1'));
+ $this->assertEquals([], $catalogue->all('domain88'));
+ $this->assertEquals($messages, $catalogue->all());
+
+ $messages = ['domain1+intl-icu' => ['foo' => 'bar']] + $messages + [
+ 'domain2+intl-icu' => ['bar' => 'foo'],
+ 'domain3+intl-icu' => ['biz' => 'biz'],
+ ];
+ $catalogue = new MessageCatalogue('en', $messages);
+
+ $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));
+ $this->assertEquals(['bar' => 'foo'], $catalogue->all('domain2'));
+ $this->assertEquals(['biz' => 'biz'], $catalogue->all('domain3'));
+
+ $messages = [
+ 'domain1' => ['foo' => 'bar'],
+ 'domain2' => ['bar' => 'foo'],
+ 'domain3' => ['biz' => 'biz'],
+ ];
+ $this->assertEquals($messages, $catalogue->all());
+ }
+
+ public function testHas()
+ {
+ $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2+intl-icu' => ['bar' => 'bar']]);
+
+ $this->assertTrue($catalogue->has('foo', 'domain1'));
+ $this->assertTrue($catalogue->has('bar', 'domain2'));
+ $this->assertFalse($catalogue->has('bar', 'domain1'));
+ $this->assertFalse($catalogue->has('foo', 'domain88'));
+ }
+
+ public function testGetSet()
+ {
+ $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar'], 'domain2+intl-icu' => ['bar' => 'foo']]);
+ $catalogue->set('foo1', 'foo1', 'domain1');
+
+ $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
+ $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
+ $this->assertEquals('foo', $catalogue->get('bar', 'domain2'));
+ }
+
+ public function testAdd()
+ {
+ $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar']]);
+ $catalogue->add(['foo1' => 'foo1'], 'domain1');
+
+ $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
+ $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
+
+ $catalogue->add(['foo' => 'bar'], 'domain1');
+ $this->assertEquals('bar', $catalogue->get('foo', 'domain1'));
+ $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
+
+ $catalogue->add(['foo' => 'bar'], 'domain88');
+ $this->assertEquals('bar', $catalogue->get('foo', 'domain88'));
+ }
+
+ public function testReplace()
+ {
+ $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain1+intl-icu' => ['bar' => 'bar']]);
+ $catalogue->replace($messages = ['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')->willReturn('r');
+
+ $r1 = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
+ $r1->expects($this->any())->method('__toString')->willReturn('r1');
+
+ $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo']]);
+ $catalogue->addResource($r);
+
+ $catalogue1 = new MessageCatalogue('en', ['domain1' => ['foo1' => 'foo1'], 'domain2+intl-icu' => ['bar' => 'bar']]);
+ $catalogue1->addResource($r1);
+
+ $catalogue->addCatalogue($catalogue1);
+
+ $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
+ $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
+ $this->assertEquals('bar', $catalogue->get('bar', 'domain2'));
+ $this->assertEquals('bar', $catalogue->get('bar', 'domain2+intl-icu'));
+
+ $this->assertEquals([$r, $r1], $catalogue->getResources());
+ }
+
+ public function testAddFallbackCatalogue()
+ {
+ $r = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
+ $r->expects($this->any())->method('__toString')->willReturn('r');
+
+ $r1 = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
+ $r1->expects($this->any())->method('__toString')->willReturn('r1');
+
+ $r2 = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
+ $r2->expects($this->any())->method('__toString')->willReturn('r2');
+
+ $catalogue = new MessageCatalogue('fr_FR', ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar']]);
+ $catalogue->addResource($r);
+
+ $catalogue1 = new MessageCatalogue('fr', ['domain1' => ['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([$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', []));
+ }
+
+ public function testGetAddResource()
+ {
+ $catalogue = new MessageCatalogue('en');
+ $r = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
+ $r->expects($this->any())->method('__toString')->willReturn('r');
+ $catalogue->addResource($r);
+ $catalogue->addResource($r);
+ $r1 = $this->getMockBuilder('Symfony\Component\Config\Resource\ResourceInterface')->getMock();
+ $r1->expects($this->any())->method('__toString')->willReturn('r1');
+ $catalogue->addResource($r1);
+
+ $this->assertEquals([$r, $r1], $catalogue->getResources());
+ }
+
+ public function testMetadataDelete()
+ {
+ $catalogue = new MessageCatalogue('en');
+ $this->assertEquals([], $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', []);
+ $this->assertEquals([], $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(['messages' => ['a' => 'b']], $cat1->getMetadata('', ''), 'Cat1 contains messages metadata.');
+
+ $cat2 = new MessageCatalogue('en');
+ $cat2->setMetadata('b', 'c', 'domain');
+ $this->assertEquals(['domain' => ['b' => 'c']], $cat2->getMetadata('', ''), 'Cat2 contains domain metadata.');
+
+ $cat1->addCatalogue($cat2);
+ $this->assertEquals(['messages' => ['a' => 'b'], 'domain' => ['b' => 'c']], $cat1->getMetadata('', ''), 'Cat1 contains merged metadata.');
+ }
+}
diff --git a/vendor/symfony/translation/Tests/MessageSelectorTest.php b/vendor/symfony/translation/Tests/MessageSelectorTest.php
new file mode 100644
index 0000000..f099716
--- /dev/null
+++ b/vendor/symfony/translation/Tests/MessageSelectorTest.php
@@ -0,0 +1,140 @@
+
+ *
+ * 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;
+
+/**
+ * @group legacy
+ */
+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 [
+ ['{0} There are no apples|{1} There is one apple', 2],
+ ['{1} There is one apple|]1,Inf] There are %count% apples', 0],
+ ['{1} There is one apple|]2,Inf] There are %count% apples', 2],
+ ['{0} There are no apples|There is one apple', 2],
+ ];
+ }
+
+ public function getChooseTests()
+ {
+ return [
+ ['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
+ ['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
+ ['There are no apples', '{0}There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
+
+ ['There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1],
+
+ ['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
+ ['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf]There are %count% apples', 10],
+ ['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
+
+ ['There are %count% apples', 'There is one apple|There are %count% apples', 0],
+ ['There is one apple', 'There is one apple|There are %count% apples', 1],
+ ['There are %count% apples', 'There is one apple|There are %count% apples', 10],
+
+ ['There are %count% apples', 'one: There is one apple|more: There are %count% apples', 0],
+ ['There is one apple', 'one: There is one apple|more: There are %count% apples', 1],
+ ['There are %count% apples', 'one: There is one apple|more: There are %count% apples', 10],
+
+ ['There are no apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 0],
+ ['There is one apple', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 1],
+ ['There are %count% apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 10],
+
+ ['', '{0}|{1} There is one apple|]1,Inf] There are %count% apples', 0],
+ ['', '{0} There are no apples|{1}|]1,Inf] There are %count% apples', 1],
+
+ // Indexed only tests which are Gettext PoFile* compatible strings.
+ ['There are %count% apples', 'There is one apple|There are %count% apples', 0],
+ ['There is one apple', 'There is one apple|There are %count% apples', 1],
+ ['There are %count% apples', 'There is one apple|There are %count% apples', 2],
+
+ // Tests for float numbers
+ ['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],
+ ['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],
+ ['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],
+ ['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],
+ ['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],
+ ['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
+ ["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
+ ["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],
+ ["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
+ ['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
+ ['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
+ ['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
+ ["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
+ ['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
+ ['', '|', 1],
+ // Empty plural set (3 plural forms) from a .PO file
+ ['', '||', 1],
+ ];
+ }
+}
diff --git a/vendor/symfony/translation/Tests/PluralizationRulesTest.php b/vendor/symfony/translation/Tests/PluralizationRulesTest.php
new file mode 100644
index 0000000..696c92b
--- /dev/null
+++ b/vendor/symfony/translation/Tests/PluralizationRulesTest.php
@@ -0,0 +1,124 @@
+
+ *
+ * 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
+ *
+ * @group legacy
+ */
+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 [
+ ['1', ['ay', 'bo', 'cgg', 'dz', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky']],
+ ['2', ['nl', 'fr', 'en', 'de', 'de_GE', 'hy', 'hy_AM']],
+ ['3', ['be', 'bs', 'cs', 'hr']],
+ ['4', ['cy', 'mt', 'sl']],
+ ['6', ['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 [
+ ['1', ['fa']],
+ ['2', ['jbo']],
+ ['3', ['cbs']],
+ ['4', ['gd', 'kw']],
+ ['5', ['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 = [];
+ foreach ($langCodes as $langCode) {
+ for ($count = 0; $count < 200; ++$count) {
+ $plural = PluralizationRules::get($count, $langCode);
+ $matrix[$langCode][$count] = $plural;
+ }
+ }
+
+ return $matrix;
+ }
+}
diff --git a/vendor/symfony/translation/Tests/TranslatorCacheTest.php b/vendor/symfony/translation/Tests/TranslatorCacheTest.php
new file mode 100644
index 0000000..5d437ff
--- /dev/null
+++ b/vendor/symfony/translation/Tests/TranslatorCacheTest.php
@@ -0,0 +1,318 @@
+
+ *
+ * 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().'/sf_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, [$msgid => 'OK'], $locale);
+ $translator->addResource($format, [$msgid.'+intl' => 'OK'], $locale, 'messages+intl-icu');
+ $translator->trans($msgid);
+ $translator->trans($msgid.'+intl', [], 'messages+intl-icu');
+
+ // 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, [$msgid => 'OK'], $locale);
+ $translator->addResource($format, [$msgid.'+intl' => 'OK'], $locale, 'messages+intl-icu');
+ $this->assertEquals('OK', $translator->trans($msgid), '-> caching does not work in '.($debug ? 'debug' : 'production'));
+ $this->assertEquals('OK', $translator->trans($msgid.'+intl', [], 'messages+intl-icu'));
+ }
+
+ 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, []);
+ $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')
+ ->willReturn($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 usable 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, [$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, [$msgid => 'FAIL'], $locale);
+ $translator->trans($msgid);
+
+ // Now the first translator must still have a usable cache.
+ $translator = new Translator($locale, null, $this->tmpDir, $debug);
+ $translator->addLoader($format, $this->createFailingLoader());
+ $translator->addResource($format, [$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(['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(['b']);
+
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foo (a)'], 'a');
+ $translator->addResource('array', ['bar' => 'bar (b)'], 'b');
+
+ $this->assertEquals('bar (b)', $translator->trans('bar'));
+
+ // Remove fallback locale
+ $translator->setFallbackLocales([]);
+ $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', ['foo' => 'foo (a)'], 'a');
+ $translator->addResource('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 behavior.
+ */
+
+ /*
+ * 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(['b']);
+
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foo (a)'], 'a');
+ $translator->addResource('array', ['foo' => 'foo (b)'], 'b');
+ $translator->addResource('array', ['bar' => 'bar (b)'], 'b');
+ $translator->addResource('array', ['baz' => 'baz (b)'], 'b', 'messages+intl-icu');
+
+ $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(['b']);
+
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foo (a)'], 'a');
+ $translator->addResource('array', ['foo' => 'foo (b)'], 'b');
+ $translator->addResource('array', ['bar' => 'bar (b)'], 'b');
+ $translator->addResource('array', ['baz' => 'baz (b)'], 'b', 'messages+intl-icu');
+
+ $catalogue = $translator->getCatalogue('a');
+ $this->assertFalse($catalogue->defines('bar'));
+
+ $fallback = $catalogue->getFallbackCatalogue();
+ $this->assertTrue($fallback->defines('foo'));
+ $this->assertTrue($fallback->defines('baz', 'messages+intl-icu'));
+ }
+
+ public function testRefreshCacheWhenResourcesAreNoLongerFresh()
+ {
+ $resource = $this->getMockBuilder('Symfony\Component\Config\Resource\SelfCheckingResourceInterface')->getMock();
+ $loader = $this->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock();
+ $resource->method('isFresh')->willReturn(false);
+ $loader
+ ->expects($this->exactly(2))
+ ->method('load')
+ ->willReturn($this->getCatalogue('fr', [], [$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 = [])
+ {
+ $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 [[true], [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 '';
+ }
+}
diff --git a/vendor/symfony/translation/Tests/TranslatorTest.php b/vendor/symfony/translation/Tests/TranslatorTest.php
new file mode 100644
index 0000000..51c4a0a
--- /dev/null
+++ b/vendor/symfony/translation/Tests/TranslatorTest.php
@@ -0,0 +1,612 @@
+
+ *
+ * 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', ['foo' => 'foofoo'], $locale, 'domain-a');
+ $translator->addResource('loader-b', ['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', ['foo' => 'foofoo'], 'en');
+ $translator->addResource('array', ['bar' => 'foobar'], 'fr');
+
+ // force catalogue loading
+ $translator->trans('bar');
+
+ $translator->setFallbackLocales(['fr']);
+ $this->assertEquals('foobar', $translator->trans('bar'));
+ }
+
+ public function testSetFallbackLocalesMultiple()
+ {
+ $translator = new Translator('en');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foo (en)'], 'en');
+ $translator->addResource('array', ['bar' => 'bar (fr)'], 'fr');
+
+ // force catalogue loading
+ $translator->trans('bar');
+
+ $translator->setFallbackLocales(['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(['fr', $locale]);
+ }
+
+ /**
+ * @dataProvider getValidLocalesTests
+ */
+ public function testSetFallbackValidLocales($locale)
+ {
+ $translator = new Translator($locale);
+ $translator->setFallbackLocales(['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(['en']);
+
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('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', ['foo' => 'foofoo'], $locale);
+ }
+
+ /**
+ * @dataProvider getValidLocalesTests
+ */
+ public function testAddResourceValidLocales($locale)
+ {
+ $translator = new Translator('fr');
+ $translator->addResource('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(['en']);
+
+ $translator->addResource('array', ['foo' => 'foofoo'], 'en');
+ $this->assertEquals('foofoo', $translator->trans('foo'));
+
+ $translator->addResource('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', [], 'resources'));
+ }
+
+ public function testTransWithIcuFallbackLocale()
+ {
+ $translator = new Translator('en_GB');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foofoo'], 'en_GB');
+ $translator->addResource('array', ['bar' => 'foobar'], 'en_001');
+ $translator->addResource('array', ['baz' => 'foobaz'], 'en');
+ $this->assertSame('foofoo', $translator->trans('foo'));
+ $this->assertSame('foobar', $translator->trans('bar'));
+ $this->assertSame('foobaz', $translator->trans('baz'));
+ }
+
+ public function testTransWithIcuVariantFallbackLocale()
+ {
+ $translator = new Translator('en_GB_scouse');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foofoo'], 'en_GB_scouse');
+ $translator->addResource('array', ['bar' => 'foobar'], 'en_GB');
+ $translator->addResource('array', ['baz' => 'foobaz'], 'en_001');
+ $translator->addResource('array', ['qux' => 'fooqux'], 'en');
+ $this->assertSame('foofoo', $translator->trans('foo'));
+ $this->assertSame('foobar', $translator->trans('bar'));
+ $this->assertSame('foobaz', $translator->trans('baz'));
+ $this->assertSame('fooqux', $translator->trans('qux'));
+ }
+
+ public function testTransWithIcuRootFallbackLocale()
+ {
+ $translator = new Translator('az_Cyrl');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foofoo'], 'az_Cyrl');
+ $translator->addResource('array', ['bar' => 'foobar'], 'az');
+ $this->assertSame('foofoo', $translator->trans('foo'));
+ $this->assertSame('bar', $translator->trans('bar'));
+ }
+
+ public function testTransWithFallbackLocaleBis()
+ {
+ $translator = new Translator('en_US');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foofoo'], 'en_US');
+ $translator->addResource('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', ['foo' => 'foo (en_US)'], 'en_US');
+ $translator->addResource('array', ['bar' => 'bar (en)'], 'en');
+
+ $translator->setFallbackLocales(['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(['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', ['foo' => 'foofoo'], 'en');
+
+ $translator->trans('foo');
+ }
+
+ public function testNestedFallbackCatalogueWhenUsingMultipleLocales()
+ {
+ $translator = new Translator('fr');
+ $translator->setFallbackLocales(['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', []));
+
+ $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', [(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', ['foo' => 'foofoo'], 'en');
+
+ $translator->trans('foo', [], '', $locale);
+ }
+
+ /**
+ * @dataProvider getValidLocalesTests
+ */
+ public function testTransValidLocale($locale)
+ {
+ $translator = new Translator($locale);
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['test' => 'OK'], $locale);
+
+ $this->assertEquals('OK', $translator->trans('test'));
+ $this->assertEquals('OK', $translator->trans('test', [], 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, [], '', 'fr'));
+ }
+
+ /**
+ * @dataProvider getTransChoiceTests
+ * @group legacy
+ */
+ public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain)
+ {
+ $translator = new Translator('en');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', [(string) $id => $translation], $locale, $domain);
+
+ $this->assertEquals($expected, $translator->transChoice($id, $number, $parameters, $domain, $locale));
+ }
+
+ /**
+ * @dataProvider getInvalidLocalesTests
+ * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException
+ * @group legacy
+ */
+ public function testTransChoiceInvalidLocale($locale)
+ {
+ $translator = new Translator('en');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foofoo'], 'en');
+
+ $translator->transChoice('foo', 1, [], '', $locale);
+ }
+
+ /**
+ * @dataProvider getValidLocalesTests
+ * @group legacy
+ */
+ public function testTransChoiceValidLocale($locale)
+ {
+ $translator = new Translator('en');
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'foofoo'], 'en');
+
+ $translator->transChoice('foo', 1, [], '', $locale);
+ // no assertion. this method just asserts that no exception is thrown
+ $this->addToAssertionCount(1);
+ }
+
+ public function getTransFileTests()
+ {
+ return [
+ ['csv', 'CsvFileLoader'],
+ ['ini', 'IniFileLoader'],
+ ['mo', 'MoFileLoader'],
+ ['po', 'PoFileLoader'],
+ ['php', 'PhpFileLoader'],
+ ['ts', 'QtFileLoader'],
+ ['xlf', 'XliffFileLoader'],
+ ['yml', 'YamlFileLoader'],
+ ['json', 'JsonFileLoader'],
+ ];
+ }
+
+ public function getTransTests()
+ {
+ return [
+ ['Symfony est super !', 'Symfony is great!', 'Symfony est super !', [], 'fr', ''],
+ ['Symfony est awesome !', 'Symfony is %what%!', 'Symfony est %what% !', ['%what%' => 'awesome'], 'fr', ''],
+ ['Symfony est super !', new StringClass('Symfony is great!'), 'Symfony est super !', [], 'fr', ''],
+ ];
+ }
+
+ public function getFlattenedTransTests()
+ {
+ $messages = [
+ 'symfony' => [
+ 'is' => [
+ 'great' => 'Symfony est super!',
+ ],
+ ],
+ 'foo' => [
+ 'bar' => [
+ 'baz' => 'Foo Bar Baz',
+ ],
+ 'baz' => 'Foo Baz',
+ ],
+ ];
+
+ return [
+ ['Symfony est super!', $messages, 'symfony.is.great'],
+ ['Foo Bar Baz', $messages, 'foo.bar.baz'],
+ ['Foo Baz', $messages, 'foo.baz'],
+ ];
+ }
+
+ public function getTransChoiceTests()
+ {
+ return [
+ ['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, [], 'fr', ''],
+ ['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, [], 'fr', ''],
+ ['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, [], 'fr', ''],
+
+ ['Il y a 0 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 0, [], 'fr', ''],
+ ['Il y a 1 pomme', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 1, [], 'fr', ''],
+ ['Il y a 10 pommes', 'There is one apple|There is %count% apples', 'Il y a %count% pomme|Il y a %count% pommes', 10, [], 'fr', ''],
+
+ ['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, [], 'fr', ''],
+ ['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, [], 'fr', ''],
+ ['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, [], 'fr', ''],
+
+ ['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, [], 'fr', ''],
+ ['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, [], 'fr', ''],
+ ['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, [], 'fr', ''],
+
+ ['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, [], 'fr', ''],
+
+ // Override %count% with a custom value
+ ['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 quelques pommes', 2, ['%count%' => 'quelques'], 'fr', ''],
+ ];
+ }
+
+ public function getInvalidLocalesTests()
+ {
+ return [
+ ['fr FR'],
+ ['français'],
+ ['fr+en'],
+ ['utf#8'],
+ ['fr&en'],
+ ['fr~FR'],
+ [' fr'],
+ ['fr '],
+ ['fr*'],
+ ['fr/FR'],
+ ['fr\\FR'],
+ ];
+ }
+
+ public function getValidLocalesTests()
+ {
+ return [
+ [''],
+ [null],
+ ['fr'],
+ ['francais'],
+ ['FR'],
+ ['frFR'],
+ ['fr-FR'],
+ ['fr_FR'],
+ ['fr.FR'],
+ ['fr-FR.UTF8'],
+ ['sr@latin'],
+ ];
+ }
+
+ /**
+ * @requires extension intl
+ */
+ public function testIntlFormattedDomain()
+ {
+ $translator = new Translator('en');
+ $translator->addLoader('array', new ArrayLoader());
+
+ $translator->addResource('array', ['some_message' => 'Hello %name%'], 'en');
+ $this->assertSame('Hello Bob', $translator->trans('some_message', ['%name%' => 'Bob']));
+
+ $translator->addResource('array', ['some_message' => 'Hi {name}'], 'en', 'messages+intl-icu');
+ $this->assertSame('Hi Bob', $translator->trans('some_message', ['%name%' => 'Bob']));
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testTransChoiceFallback()
+ {
+ $translator = new Translator('ru');
+ $translator->setFallbackLocales(['en']);
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['some_message2' => 'one thing|%count% things'], 'en');
+
+ $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, ['%count%' => 10]));
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testTransChoiceFallbackBis()
+ {
+ $translator = new Translator('ru');
+ $translator->setFallbackLocales(['en_US', 'en']);
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['some_message2' => 'one thing|%count% things'], 'en_US');
+
+ $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, ['%count%' => 10]));
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testTransChoiceFallbackWithNoTranslation()
+ {
+ $translator = new Translator('ru');
+ $translator->setFallbackLocales(['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, ['%count%' => 10]));
+ }
+}
+
+class StringClass
+{
+ protected $str;
+
+ public function __construct($str)
+ {
+ $this->str = $str;
+ }
+
+ public function __toString()
+ {
+ return $this->str;
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Util/ArrayConverterTest.php b/vendor/symfony/translation/Tests/Util/ArrayConverterTest.php
new file mode 100644
index 0000000..b033541
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Util/ArrayConverterTest.php
@@ -0,0 +1,74 @@
+
+ *
+ * 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 [
+ [
+ // input
+ [
+ 'foo1' => 'bar',
+ 'foo.bar' => 'value',
+ ],
+ // expected output
+ [
+ 'foo1' => 'bar',
+ 'foo' => ['bar' => 'value'],
+ ],
+ ],
+ [
+ // input
+ [
+ 'foo.bar' => 'value1',
+ 'foo.bar.test' => 'value2',
+ ],
+ // expected output
+ [
+ 'foo' => [
+ 'bar' => 'value1',
+ 'bar.test' => 'value2',
+ ],
+ ],
+ ],
+ [
+ // input
+ [
+ 'foo.level2.level3.level4' => 'value1',
+ 'foo.level2' => 'value2',
+ 'foo.bar' => 'value3',
+ ],
+ // expected output
+ [
+ 'foo' => [
+ 'level2' => 'value2',
+ 'level2.level3.level4' => 'value1',
+ 'bar' => 'value3',
+ ],
+ ],
+ ],
+ ];
+ }
+}
diff --git a/vendor/symfony/translation/Tests/Writer/TranslationWriterTest.php b/vendor/symfony/translation/Tests/Writer/TranslationWriterTest.php
new file mode 100644
index 0000000..d3b6754
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Writer/TranslationWriterTest.php
@@ -0,0 +1,69 @@
+
+ *
+ * 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
+{
+ 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('en'), 'test');
+ }
+
+ /**
+ * @group legacy
+ */
+ 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 = [])
+ {
+ }
+}
+
+class BackupDumper implements DumperInterface
+{
+ public $backup = true;
+
+ public function dump(MessageCatalogue $messages, $options = [])
+ {
+ }
+
+ public function setBackup($backup)
+ {
+ $this->backup = $backup;
+ }
+}
diff --git a/vendor/symfony/translation/Tests/fixtures/empty-translation.mo b/vendor/symfony/translation/Tests/fixtures/empty-translation.mo
new file mode 100644
index 0000000..ed01000
Binary files /dev/null and b/vendor/symfony/translation/Tests/fixtures/empty-translation.mo differ
diff --git a/vendor/symfony/translation/Tests/fixtures/empty-translation.po b/vendor/symfony/translation/Tests/fixtures/empty-translation.po
new file mode 100644
index 0000000..ff6f22a
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/empty-translation.po
@@ -0,0 +1,3 @@
+msgid "foo"
+msgstr ""
+
diff --git a/vendor/symfony/translation/Tests/fixtures/empty.csv b/vendor/symfony/translation/Tests/fixtures/empty.csv
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/empty.ini b/vendor/symfony/translation/Tests/fixtures/empty.ini
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/empty.json b/vendor/symfony/translation/Tests/fixtures/empty.json
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/empty.mo b/vendor/symfony/translation/Tests/fixtures/empty.mo
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/empty.po b/vendor/symfony/translation/Tests/fixtures/empty.po
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/empty.xlf b/vendor/symfony/translation/Tests/fixtures/empty.xlf
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/empty.yml b/vendor/symfony/translation/Tests/fixtures/empty.yml
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/encoding.xlf b/vendor/symfony/translation/Tests/fixtures/encoding.xlf
new file mode 100644
index 0000000..0a88f92
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/encoding.xlf
@@ -0,0 +1,16 @@
+
+
+
+
+
+ foo
+ br
+ bz
+
+
+ bar
+ f
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/escaped-id-plurals.po b/vendor/symfony/translation/Tests/fixtures/escaped-id-plurals.po
new file mode 100644
index 0000000..c412aa2
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/escaped-id-plurals.po
@@ -0,0 +1,10 @@
+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\""
diff --git a/vendor/symfony/translation/Tests/fixtures/escaped-id.po b/vendor/symfony/translation/Tests/fixtures/escaped-id.po
new file mode 100644
index 0000000..308eadd
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/escaped-id.po
@@ -0,0 +1,8 @@
+msgid ""
+msgstr ""
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: en\n"
+
+msgid "escaped \"foo\""
+msgstr "escaped \"bar\""
diff --git a/vendor/symfony/translation/Tests/fixtures/extractor/resource.format.engine b/vendor/symfony/translation/Tests/fixtures/extractor/resource.format.engine
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/extractor/this.is.a.template.format.engine b/vendor/symfony/translation/Tests/fixtures/extractor/this.is.a.template.format.engine
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/symfony/translation/Tests/fixtures/extractor/translation.html.php b/vendor/symfony/translation/Tests/fixtures/extractor/translation.html.php
new file mode 100644
index 0000000..5085eab
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/extractor/translation.html.php
@@ -0,0 +1,59 @@
+This template is used for translation message extraction tests
+trans('single-quoted key'); ?>
+trans('double-quoted key'); ?>
+trans(<<
+trans(<<<'EOF'
+nowdoc key
+EOF
+); ?>
+trans(
+ "double-quoted key with whitespace and escaped \$\n\" sequences"
+); ?>
+trans(
+ 'single-quoted key with whitespace and nonescaped \$\n\' sequences'
+); ?>
+trans(<<
+trans(<<<'EOF'
+nowdoc key with whitespace and nonescaped \$\n sequences
+EOF
+); ?>
+
+trans('single-quoted key with "quote mark at the end"'); ?>
+
+transChoice(
+ '{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples',
+ 10,
+ ['%count%' => 10]
+); ?>
+
+trans('concatenated'.' message'.<<
+
+trans('other-domain-test-no-params-short-array', [], 'not_messages'); ?>
+
+trans('other-domain-test-no-params-long-array', [], 'not_messages'); ?>
+
+trans('other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>
+
+trans('other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>
+
+transChoice('other-domain-test-trans-choice-short-array-%count%', 10, ['%count%' => 10], 'not_messages'); ?>
+
+transChoice('other-domain-test-trans-choice-long-array-%count%', 10, ['%count%' => 10], 'not_messages'); ?>
+
+trans('typecast', ['a' => (int) '123'], 'not_messages'); ?>
+transChoice('msg1', 10 + 1, [], 'not_messages'); ?>
+transChoice('msg2', ceil(4.5), [], 'not_messages'); ?>
+
+trans('default domain', [], null); ?>
diff --git a/vendor/symfony/translation/Tests/fixtures/fuzzy-translations.po b/vendor/symfony/translation/Tests/fixtures/fuzzy-translations.po
new file mode 100644
index 0000000..04d4047
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/fuzzy-translations.po
@@ -0,0 +1,10 @@
+#, php-format
+msgid "foo1"
+msgstr "bar1"
+
+#, fuzzy, php-format
+msgid "foo2"
+msgstr "fuzzy bar2"
+
+msgid "foo3"
+msgstr "bar3"
diff --git a/vendor/symfony/translation/Tests/fixtures/invalid-xml-resources.xlf b/vendor/symfony/translation/Tests/fixtures/invalid-xml-resources.xlf
new file mode 100644
index 0000000..7bf6c98
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/invalid-xml-resources.xlf
@@ -0,0 +1,23 @@
+
+
+
+
+
+ foo
+ bar
+
+
+ extra
+
+
+ key
+
+
+
+ test
+ with
+ note
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/malformed.json b/vendor/symfony/translation/Tests/fixtures/malformed.json
new file mode 100644
index 0000000..4563ec6
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/malformed.json
@@ -0,0 +1,3 @@
+{
+ "foo" "bar"
+}
\ No newline at end of file
diff --git a/vendor/symfony/translation/Tests/fixtures/messages.yml b/vendor/symfony/translation/Tests/fixtures/messages.yml
new file mode 100644
index 0000000..d4f82d7
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/messages.yml
@@ -0,0 +1,3 @@
+foo:
+ bar1: value1
+ bar2: value2
diff --git a/vendor/symfony/translation/Tests/fixtures/messages_linear.yml b/vendor/symfony/translation/Tests/fixtures/messages_linear.yml
new file mode 100644
index 0000000..6c1687d
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/messages_linear.yml
@@ -0,0 +1,2 @@
+foo.bar1: value1
+foo.bar2: value2
diff --git a/vendor/symfony/translation/Tests/fixtures/missing-plurals.po b/vendor/symfony/translation/Tests/fixtures/missing-plurals.po
new file mode 100644
index 0000000..3b47fca
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/missing-plurals.po
@@ -0,0 +1,4 @@
+msgid "foo"
+msgid_plural "foos"
+msgstr[3] "bars"
+msgstr[1] "bar"
diff --git a/vendor/symfony/translation/Tests/fixtures/non-valid.xlf b/vendor/symfony/translation/Tests/fixtures/non-valid.xlf
new file mode 100644
index 0000000..734fc97
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/non-valid.xlf
@@ -0,0 +1,11 @@
+
+
+
+
+
+ foo
+ bar
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/non-valid.yml b/vendor/symfony/translation/Tests/fixtures/non-valid.yml
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/non-valid.yml
@@ -0,0 +1 @@
+foo
diff --git a/vendor/symfony/translation/Tests/fixtures/plurals.mo b/vendor/symfony/translation/Tests/fixtures/plurals.mo
new file mode 100644
index 0000000..3945ad9
Binary files /dev/null and b/vendor/symfony/translation/Tests/fixtures/plurals.mo differ
diff --git a/vendor/symfony/translation/Tests/fixtures/plurals.po b/vendor/symfony/translation/Tests/fixtures/plurals.po
new file mode 100644
index 0000000..61d1ba4
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/plurals.po
@@ -0,0 +1,7 @@
+msgid "foo"
+msgid_plural "foos"
+msgstr[0] "bar"
+msgstr[1] "bars"
+
+msgid "{0} no foos|one foo|%count% foos"
+msgstr "{0} no bars|one bar|%count% bars"
diff --git a/vendor/symfony/translation/Tests/fixtures/resname.xlf b/vendor/symfony/translation/Tests/fixtures/resname.xlf
new file mode 100644
index 0000000..4fa5c00
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resname.xlf
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ bar
+
+
+ bar source
+ baz
+
+
+ baz
+ foo
+
+
+ qux source
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resourcebundle/corrupted/resources.dat b/vendor/symfony/translation/Tests/fixtures/resourcebundle/corrupted/resources.dat
new file mode 100644
index 0000000..391250c
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resourcebundle/corrupted/resources.dat
@@ -0,0 +1 @@
+XXX
\ No newline at end of file
diff --git a/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/en.res b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/en.res
new file mode 100644
index 0000000..1fc1436
Binary files /dev/null and b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/en.res differ
diff --git a/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/en.txt b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/en.txt
new file mode 100644
index 0000000..3d9e9ea
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/en.txt
@@ -0,0 +1,3 @@
+en{
+ symfony{"Symfony is great"}
+}
\ No newline at end of file
diff --git a/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/fr.res b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/fr.res
new file mode 100644
index 0000000..f584160
Binary files /dev/null and b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/fr.res differ
diff --git a/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/fr.txt b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/fr.txt
new file mode 100644
index 0000000..182d0a0
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/fr.txt
@@ -0,0 +1,3 @@
+fr{
+ symfony{"Symfony est génial"}
+}
\ No newline at end of file
diff --git a/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/packagelist.txt b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/packagelist.txt
new file mode 100644
index 0000000..c5783ed
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/packagelist.txt
@@ -0,0 +1,2 @@
+en.res
+fr.res
diff --git a/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/resources.dat b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/resources.dat
new file mode 100644
index 0000000..563b0ea
Binary files /dev/null and b/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/resources.dat differ
diff --git a/vendor/symfony/translation/Tests/fixtures/resourcebundle/res/en.res b/vendor/symfony/translation/Tests/fixtures/resourcebundle/res/en.res
new file mode 100644
index 0000000..ad894a9
Binary files /dev/null and b/vendor/symfony/translation/Tests/fixtures/resourcebundle/res/en.res differ
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-2.0+intl-icu.xlf b/vendor/symfony/translation/Tests/fixtures/resources-2.0+intl-icu.xlf
new file mode 100644
index 0000000..6294f16
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-2.0+intl-icu.xlf
@@ -0,0 +1,11 @@
+
+
+
+
+
+ foo
+ bar
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-2.0-clean.xlf b/vendor/symfony/translation/Tests/fixtures/resources-2.0-clean.xlf
new file mode 100644
index 0000000..efa69b2
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-2.0-clean.xlf
@@ -0,0 +1,23 @@
+
+
+
+
+
+ foo
+ bar
+
+
+
+
+ key
+
+
+
+
+
+ key.with.cdata
+ & ]]>
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-2.0-multi-segment-unit.xlf b/vendor/symfony/translation/Tests/fixtures/resources-2.0-multi-segment-unit.xlf
new file mode 100644
index 0000000..d0dc2a8
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-2.0-multi-segment-unit.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+ true
+
+
+ foo
+ foo (translated)
+
+
+ bar
+ bar (translated)
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-2.0.xlf b/vendor/symfony/translation/Tests/fixtures/resources-2.0.xlf
new file mode 100644
index 0000000..166172a
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-2.0.xlf
@@ -0,0 +1,25 @@
+
+
+
+
+
+ Quetzal
+ Quetzal
+
+
+
+
+
+ foo
+ XLIFF 文書を編集、または処理 するアプリケーションです。
+
+
+
+
+ bar
+ XLIFF データ・マネージャ
+
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-clean.xlf b/vendor/symfony/translation/Tests/fixtures/resources-clean.xlf
new file mode 100644
index 0000000..00c8a5c
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-clean.xlf
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+ foo
+ bar
+ baz
+
+
+ key
+
+ baz
+ qux
+
+
+ key.with.cdata
+ & ]]>
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-multi-files.xlf b/vendor/symfony/translation/Tests/fixtures/resources-multi-files.xlf
new file mode 100644
index 0000000..5f45150
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-multi-files.xlf
@@ -0,0 +1,27 @@
+
+
+
+
+
+ foo
+ bar
+
+
+
+
+
+
+ extra
+
+
+ key
+
+
+
+ test
+ with
+ note
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-notes-meta.xlf b/vendor/symfony/translation/Tests/fixtures/resources-notes-meta.xlf
new file mode 100644
index 0000000..7d5bbd4
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-notes-meta.xlf
@@ -0,0 +1,26 @@
+
+
+
+
+
+ new
+ true
+ user login
+
+
+ foo
+ bar
+
+
+
+
+ x_content
+ Fuzzy
+
+
+ baz
+ biz
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-target-attributes.xlf b/vendor/symfony/translation/Tests/fixtures/resources-target-attributes.xlf
new file mode 100644
index 0000000..700d281
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-target-attributes.xlf
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+ foo
+ bar
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources-tool-info.xlf b/vendor/symfony/translation/Tests/fixtures/resources-tool-info.xlf
new file mode 100644
index 0000000..1c2ae95
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources-tool-info.xlf
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+ foo
+ bar
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.csv b/vendor/symfony/translation/Tests/fixtures/resources.csv
new file mode 100644
index 0000000..374b9eb
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.csv
@@ -0,0 +1,4 @@
+"foo"; "bar"
+#"bar"; "foo"
+"incorrect"; "number"; "columns"; "will"; "be"; "ignored"
+"incorrect"
\ No newline at end of file
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.dump.json b/vendor/symfony/translation/Tests/fixtures/resources.dump.json
new file mode 100644
index 0000000..335965d
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.dump.json
@@ -0,0 +1 @@
+{"foo":"\u0022bar\u0022"}
\ No newline at end of file
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.ini b/vendor/symfony/translation/Tests/fixtures/resources.ini
new file mode 100644
index 0000000..4953062
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.ini
@@ -0,0 +1 @@
+foo="bar"
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.json b/vendor/symfony/translation/Tests/fixtures/resources.json
new file mode 100644
index 0000000..8a79687
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.json
@@ -0,0 +1,3 @@
+{
+ "foo": "bar"
+}
\ No newline at end of file
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.mo b/vendor/symfony/translation/Tests/fixtures/resources.mo
new file mode 100644
index 0000000..0a96602
Binary files /dev/null and b/vendor/symfony/translation/Tests/fixtures/resources.mo differ
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.php b/vendor/symfony/translation/Tests/fixtures/resources.php
new file mode 100644
index 0000000..c291398
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.php
@@ -0,0 +1,5 @@
+ 'bar',
+);
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.po b/vendor/symfony/translation/Tests/fixtures/resources.po
new file mode 100644
index 0000000..68e0f2d
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.po
@@ -0,0 +1,24 @@
+msgid ""
+msgstr ""
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: en\n"
+
+msgid "foo"
+msgstr "bar"
+
+msgid "bar"
+msgstr "foo"
+
+# Comment 1
+# Comment 2
+#, fuzzy,another
+#: src/file_1 src/file_2:50
+msgid "foo_bar"
+msgstr "foobar"
+
+# Comment
+#, fuzzy
+#: src/file_1
+msgid "bar_foo"
+msgstr "barfoo"
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.ts b/vendor/symfony/translation/Tests/fixtures/resources.ts
new file mode 100644
index 0000000..29e6a6f
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.ts
@@ -0,0 +1,21 @@
+
+
+
+ resources
+
+ foo
+ bar
+
+
+
+
+ foo_bar
+ foobar
+
+
+
+ bar_foo
+ barfoo
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.xlf b/vendor/symfony/translation/Tests/fixtures/resources.xlf
new file mode 100644
index 0000000..b0e5988
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.xlf
@@ -0,0 +1,23 @@
+
+
+
+
+
+ foo
+ bar
+
+
+ extra
+
+
+ key
+
+
+
+ test
+ with
+ note
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/resources.yml b/vendor/symfony/translation/Tests/fixtures/resources.yml
new file mode 100644
index 0000000..20e9ff3
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/resources.yml
@@ -0,0 +1 @@
+foo: bar
diff --git a/vendor/symfony/translation/Tests/fixtures/valid.csv b/vendor/symfony/translation/Tests/fixtures/valid.csv
new file mode 100644
index 0000000..59882e5
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/valid.csv
@@ -0,0 +1,4 @@
+foo;bar
+bar;"foo
+foo"
+"foo;foo";bar
diff --git a/vendor/symfony/translation/Tests/fixtures/with-attributes.xlf b/vendor/symfony/translation/Tests/fixtures/with-attributes.xlf
new file mode 100644
index 0000000..7873062
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/with-attributes.xlf
@@ -0,0 +1,21 @@
+
+
+
+
+
+ foo
+ bar
+
+
+ extra
+ bar
+
+
+ key
+
+ baz
+ qux
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/withdoctype.xlf b/vendor/symfony/translation/Tests/fixtures/withdoctype.xlf
new file mode 100644
index 0000000..f83e834
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/withdoctype.xlf
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ foo
+ bar
+
+
+
+
diff --git a/vendor/symfony/translation/Tests/fixtures/withnote.xlf b/vendor/symfony/translation/Tests/fixtures/withnote.xlf
new file mode 100644
index 0000000..f98cf7f
--- /dev/null
+++ b/vendor/symfony/translation/Tests/fixtures/withnote.xlf
@@ -0,0 +1,22 @@
+
+
+
+
+
+ foo
+ bar
+ foo
+
+
+ extrasource
+ bar
+
+
+ key
+
+ baz
+ qux
+
+
+
+
diff --git a/vendor/symfony/translation/Translator.php b/vendor/symfony/translation/Translator.php
new file mode 100644
index 0000000..9846c83
--- /dev/null
+++ b/vendor/symfony/translation/Translator.php
@@ -0,0 +1,510 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+use Symfony\Component\Config\ConfigCacheFactory;
+use Symfony\Component\Config\ConfigCacheFactoryInterface;
+use Symfony\Component\Config\ConfigCacheInterface;
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+use Symfony\Component\Translation\Exception\LogicException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Translation\Exception\RuntimeException;
+use Symfony\Component\Translation\Formatter\ChoiceMessageFormatterInterface;
+use Symfony\Component\Translation\Formatter\IntlFormatterInterface;
+use Symfony\Component\Translation\Formatter\MessageFormatter;
+use Symfony\Component\Translation\Formatter\MessageFormatterInterface;
+use Symfony\Component\Translation\Loader\LoaderInterface;
+use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+/**
+ * @author Fabien Potencier
+ */
+class Translator implements LegacyTranslatorInterface, TranslatorInterface, TranslatorBagInterface
+{
+ /**
+ * @var MessageCatalogueInterface[]
+ */
+ protected $catalogues = [];
+
+ /**
+ * @var string
+ */
+ private $locale;
+
+ /**
+ * @var array
+ */
+ private $fallbackLocales = [];
+
+ /**
+ * @var LoaderInterface[]
+ */
+ private $loaders = [];
+
+ /**
+ * @var array
+ */
+ private $resources = [];
+
+ /**
+ * @var MessageFormatterInterface
+ */
+ private $formatter;
+
+ /**
+ * @var string
+ */
+ private $cacheDir;
+
+ /**
+ * @var bool
+ */
+ private $debug;
+
+ /**
+ * @var ConfigCacheFactoryInterface|null
+ */
+ private $configCacheFactory;
+
+ /**
+ * @var array|null
+ */
+ private $parentLocales;
+
+ private $hasIntlFormatter;
+
+ /**
+ * @throws InvalidArgumentException If a locale contains invalid characters
+ */
+ public function __construct(?string $locale, MessageFormatterInterface $formatter = null, string $cacheDir = null, bool $debug = false)
+ {
+ $this->setLocale($locale);
+
+ if (null === $formatter) {
+ $formatter = new MessageFormatter();
+ }
+
+ $this->formatter = $formatter;
+ $this->cacheDir = $cacheDir;
+ $this->debug = $debug;
+ $this->hasIntlFormatter = $formatter instanceof IntlFormatterInterface;
+ }
+
+ public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)
+ {
+ $this->configCacheFactory = $configCacheFactory;
+ }
+
+ /**
+ * Adds a Loader.
+ *
+ * @param string $format The name of the loader (@see addResource())
+ * @param LoaderInterface $loader A LoaderInterface instance
+ */
+ public function addLoader($format, LoaderInterface $loader)
+ {
+ $this->loaders[$format] = $loader;
+ }
+
+ /**
+ * Adds a Resource.
+ *
+ * @param string $format The name of the loader (@see addLoader())
+ * @param mixed $resource The resource name
+ * @param string $locale The locale
+ * @param string $domain The domain
+ *
+ * @throws InvalidArgumentException If the locale contains invalid characters
+ */
+ public function addResource($format, $resource, $locale, $domain = null)
+ {
+ if (null === $domain) {
+ $domain = 'messages';
+ }
+
+ $this->assertValidLocale($locale);
+
+ $this->resources[$locale][] = [$format, $resource, $domain];
+
+ if (\in_array($locale, $this->fallbackLocales)) {
+ $this->catalogues = [];
+ } else {
+ unset($this->catalogues[$locale]);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setLocale($locale)
+ {
+ $this->assertValidLocale($locale);
+ $this->locale = $locale;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLocale()
+ {
+ return $this->locale;
+ }
+
+ /**
+ * Sets the fallback locales.
+ *
+ * @param array $locales The fallback locales
+ *
+ * @throws InvalidArgumentException If a locale contains invalid characters
+ */
+ public function setFallbackLocales(array $locales)
+ {
+ // needed as the fallback locales are linked to the already loaded catalogues
+ $this->catalogues = [];
+
+ foreach ($locales as $locale) {
+ $this->assertValidLocale($locale);
+ }
+
+ $this->fallbackLocales = $locales;
+ }
+
+ /**
+ * Gets the fallback locales.
+ *
+ * @internal since Symfony 4.2
+ *
+ * @return array The fallback locales
+ */
+ public function getFallbackLocales()
+ {
+ return $this->fallbackLocales;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function trans($id, array $parameters = [], $domain = null, $locale = null)
+ {
+ if (null === $domain) {
+ $domain = 'messages';
+ }
+
+ $id = (string) $id;
+ $catalogue = $this->getCatalogue($locale);
+ $locale = $catalogue->getLocale();
+ while (!$catalogue->defines($id, $domain)) {
+ if ($cat = $catalogue->getFallbackCatalogue()) {
+ $catalogue = $cat;
+ $locale = $catalogue->getLocale();
+ } else {
+ break;
+ }
+ }
+
+ if ($this->hasIntlFormatter && $catalogue->defines($id, $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX)) {
+ return $this->formatter->formatIntl($catalogue->get($id, $domain), $locale, $parameters);
+ }
+
+ return $this->formatter->format($catalogue->get($id, $domain), $locale, $parameters);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @deprecated since Symfony 4.2, use the trans() method instead with a %count% parameter
+ */
+ public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
+ {
+ @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->formatter instanceof ChoiceMessageFormatterInterface) {
+ throw new LogicException(sprintf('The formatter "%s" does not support plural translations.', \get_class($this->formatter)));
+ }
+
+ if (null === $domain) {
+ $domain = 'messages';
+ }
+
+ $id = (string) $id;
+ $catalogue = $this->getCatalogue($locale);
+ $locale = $catalogue->getLocale();
+ while (!$catalogue->defines($id, $domain)) {
+ if ($cat = $catalogue->getFallbackCatalogue()) {
+ $catalogue = $cat;
+ $locale = $catalogue->getLocale();
+ } else {
+ break;
+ }
+ }
+
+ if ($this->hasIntlFormatter && $catalogue->defines($id, $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX)) {
+ return $this->formatter->formatIntl($catalogue->get($id, $domain), $locale, ['%count%' => $number] + $parameters);
+ }
+
+ return $this->formatter->choiceFormat($catalogue->get($id, $domain), $number, $locale, $parameters);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCatalogue($locale = null)
+ {
+ if (null === $locale) {
+ $locale = $this->getLocale();
+ } else {
+ $this->assertValidLocale($locale);
+ }
+
+ if (!isset($this->catalogues[$locale])) {
+ $this->loadCatalogue($locale);
+ }
+
+ return $this->catalogues[$locale];
+ }
+
+ /**
+ * Gets the loaders.
+ *
+ * @return array LoaderInterface[]
+ */
+ protected function getLoaders()
+ {
+ return $this->loaders;
+ }
+
+ /**
+ * @param string $locale
+ */
+ protected function loadCatalogue($locale)
+ {
+ if (null === $this->cacheDir) {
+ $this->initializeCatalogue($locale);
+ } else {
+ $this->initializeCacheCatalogue($locale);
+ }
+ }
+
+ /**
+ * @param string $locale
+ */
+ protected function initializeCatalogue($locale)
+ {
+ $this->assertValidLocale($locale);
+
+ try {
+ $this->doLoadCatalogue($locale);
+ } catch (NotFoundResourceException $e) {
+ if (!$this->computeFallbackLocales($locale)) {
+ throw $e;
+ }
+ }
+ $this->loadFallbackCatalogues($locale);
+ }
+
+ private function initializeCacheCatalogue(string $locale): void
+ {
+ if (isset($this->catalogues[$locale])) {
+ /* Catalogue already initialized. */
+ return;
+ }
+
+ $this->assertValidLocale($locale);
+ $cache = $this->getConfigCacheFactory()->cache($this->getCatalogueCachePath($locale),
+ function (ConfigCacheInterface $cache) use ($locale) {
+ $this->dumpCatalogue($locale, $cache);
+ }
+ );
+
+ if (isset($this->catalogues[$locale])) {
+ /* Catalogue has been initialized as it was written out to cache. */
+ return;
+ }
+
+ /* Read catalogue from cache. */
+ $this->catalogues[$locale] = include $cache->getPath();
+ }
+
+ private function dumpCatalogue($locale, ConfigCacheInterface $cache): void
+ {
+ $this->initializeCatalogue($locale);
+ $fallbackContent = $this->getFallbackContent($this->catalogues[$locale]);
+
+ $content = sprintf(<<getAllMessages($this->catalogues[$locale]), true),
+ $fallbackContent
+ );
+
+ $cache->write($content, $this->catalogues[$locale]->getResources());
+ }
+
+ private function getFallbackContent(MessageCatalogue $catalogue): string
+ {
+ $fallbackContent = '';
+ $current = '';
+ $replacementPattern = '/[^a-z0-9_]/i';
+ $fallbackCatalogue = $catalogue->getFallbackCatalogue();
+ while ($fallbackCatalogue) {
+ $fallback = $fallbackCatalogue->getLocale();
+ $fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback));
+ $currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current));
+
+ $fallbackContent .= sprintf(<<<'EOF'
+$catalogue%s = new MessageCatalogue('%s', %s);
+$catalogue%s->addFallbackCatalogue($catalogue%s);
+
+EOF
+ ,
+ $fallbackSuffix,
+ $fallback,
+ var_export($this->getAllMessages($fallbackCatalogue), true),
+ $currentSuffix,
+ $fallbackSuffix
+ );
+ $current = $fallbackCatalogue->getLocale();
+ $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();
+ }
+
+ return $fallbackContent;
+ }
+
+ private function getCatalogueCachePath($locale)
+ {
+ return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->fallbackLocales), true)), 0, 7), '/', '_').'.php';
+ }
+
+ /**
+ * @internal
+ */
+ protected function doLoadCatalogue($locale): void
+ {
+ $this->catalogues[$locale] = new MessageCatalogue($locale);
+
+ if (isset($this->resources[$locale])) {
+ foreach ($this->resources[$locale] as $resource) {
+ if (!isset($this->loaders[$resource[0]])) {
+ throw new RuntimeException(sprintf('The "%s" translation loader is not registered.', $resource[0]));
+ }
+ $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));
+ }
+ }
+ }
+
+ private function loadFallbackCatalogues($locale): void
+ {
+ $current = $this->catalogues[$locale];
+
+ foreach ($this->computeFallbackLocales($locale) as $fallback) {
+ if (!isset($this->catalogues[$fallback])) {
+ $this->initializeCatalogue($fallback);
+ }
+
+ $fallbackCatalogue = new MessageCatalogue($fallback, $this->getAllMessages($this->catalogues[$fallback]));
+ foreach ($this->catalogues[$fallback]->getResources() as $resource) {
+ $fallbackCatalogue->addResource($resource);
+ }
+ $current->addFallbackCatalogue($fallbackCatalogue);
+ $current = $fallbackCatalogue;
+ }
+ }
+
+ protected function computeFallbackLocales($locale)
+ {
+ if (null === $this->parentLocales) {
+ $parentLocales = json_decode(file_get_contents(__DIR__.'/Resources/data/parents.json'), true);
+ }
+
+ $locales = [];
+ foreach ($this->fallbackLocales as $fallback) {
+ if ($fallback === $locale) {
+ continue;
+ }
+
+ $locales[] = $fallback;
+ }
+
+ while ($locale) {
+ $parent = $parentLocales[$locale] ?? null;
+
+ if (!$parent && false !== strrchr($locale, '_')) {
+ $locale = substr($locale, 0, -\strlen(strrchr($locale, '_')));
+ } elseif ('root' !== $parent) {
+ $locale = $parent;
+ } else {
+ $locale = null;
+ }
+
+ if (null !== $locale) {
+ array_unshift($locales, $locale);
+ }
+ }
+
+ return array_unique($locales);
+ }
+
+ /**
+ * Asserts that the locale is valid, throws an Exception if not.
+ *
+ * @param string $locale Locale to tests
+ *
+ * @throws InvalidArgumentException If the locale contains invalid characters
+ */
+ protected function assertValidLocale($locale)
+ {
+ if (1 !== preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) {
+ throw new InvalidArgumentException(sprintf('Invalid "%s" locale.', $locale));
+ }
+ }
+
+ /**
+ * Provides the ConfigCache factory implementation, falling back to a
+ * default implementation if necessary.
+ */
+ private function getConfigCacheFactory(): ConfigCacheFactoryInterface
+ {
+ if (!$this->configCacheFactory) {
+ $this->configCacheFactory = new ConfigCacheFactory($this->debug);
+ }
+
+ return $this->configCacheFactory;
+ }
+
+ private function getAllMessages(MessageCatalogueInterface $catalogue): array
+ {
+ $allMessages = [];
+
+ foreach ($catalogue->all() as $domain => $messages) {
+ if ($intlMessages = $catalogue->all($domain.MessageCatalogue::INTL_DOMAIN_SUFFIX)) {
+ $allMessages[$domain.MessageCatalogue::INTL_DOMAIN_SUFFIX] = $intlMessages;
+ $messages = array_diff_key($messages, $intlMessages);
+ }
+ if ($messages) {
+ $allMessages[$domain] = $messages;
+ }
+ }
+
+ return $allMessages;
+ }
+}
diff --git a/vendor/symfony/translation/TranslatorBagInterface.php b/vendor/symfony/translation/TranslatorBagInterface.php
new file mode 100644
index 0000000..5e49e2d
--- /dev/null
+++ b/vendor/symfony/translation/TranslatorBagInterface.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+
+/**
+ * TranslatorBagInterface.
+ *
+ * @author Abdellatif Ait boudad
+ */
+interface TranslatorBagInterface
+{
+ /**
+ * Gets the catalogue by locale.
+ *
+ * @param string|null $locale The locale or null to use the default
+ *
+ * @return MessageCatalogueInterface
+ *
+ * @throws InvalidArgumentException If the locale contains invalid characters
+ */
+ public function getCatalogue($locale = null);
+}
diff --git a/vendor/symfony/translation/TranslatorInterface.php b/vendor/symfony/translation/TranslatorInterface.php
new file mode 100644
index 0000000..f677d24
--- /dev/null
+++ b/vendor/symfony/translation/TranslatorInterface.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+use Symfony\Contracts\Translation\LocaleAwareInterface;
+
+/**
+ * TranslatorInterface.
+ *
+ * @author Fabien Potencier
+ *
+ * @deprecated since Symfony 4.2, use Symfony\Contracts\Translation\TranslatorInterface instead
+ */
+interface TranslatorInterface extends LocaleAwareInterface
+{
+ /**
+ * Translates the given message.
+ *
+ * @param string $id The message id (may also be an object that can be cast to string)
+ * @param array $parameters An array of parameters for the message
+ * @param string|null $domain The domain for the message or null to use the default
+ * @param string|null $locale The locale or null to use the default
+ *
+ * @return string The translated string
+ *
+ * @throws InvalidArgumentException If the locale contains invalid characters
+ */
+ public function trans($id, array $parameters = [], $domain = null, $locale = null);
+
+ /**
+ * Translates the given choice message by choosing a translation according to a number.
+ *
+ * @param string $id The message id (may also be an object that can be cast to string)
+ * @param int $number The number to use to find the index of the message
+ * @param array $parameters An array of parameters for the message
+ * @param string|null $domain The domain for the message or null to use the default
+ * @param string|null $locale The locale or null to use the default
+ *
+ * @return string The translated string
+ *
+ * @throws InvalidArgumentException If the locale contains invalid characters
+ */
+ public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null);
+
+ /**
+ * Sets the current locale.
+ *
+ * @param string $locale The locale
+ *
+ * @throws InvalidArgumentException If the locale contains invalid characters
+ */
+ public function setLocale($locale);
+
+ /**
+ * Returns the current locale.
+ *
+ * @return string The locale
+ */
+ public function getLocale();
+}
diff --git a/vendor/symfony/translation/Util/ArrayConverter.php b/vendor/symfony/translation/Util/ArrayConverter.php
new file mode 100644
index 0000000..22c602e
--- /dev/null
+++ b/vendor/symfony/translation/Util/ArrayConverter.php
@@ -0,0 +1,99 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Util;
+
+/**
+ * ArrayConverter generates tree like structure from a message catalogue.
+ * e.g. this
+ * 'foo.bar1' => 'test1',
+ * 'foo.bar2' => 'test2'
+ * converts to follows:
+ * foo:
+ * bar1: test1
+ * bar2: test2.
+ *
+ * @author Gennady Telegin
+ */
+class ArrayConverter
+{
+ /**
+ * Converts linear messages array to tree-like array.
+ * For example this array('foo.bar' => 'value') will be converted to ['foo' => ['bar' => 'value']].
+ *
+ * @param array $messages Linear messages array
+ *
+ * @return array Tree-like messages array
+ */
+ public static function expandToTree(array $messages)
+ {
+ $tree = [];
+
+ foreach ($messages as $id => $value) {
+ $referenceToElement = &self::getElementByPath($tree, explode('.', $id));
+
+ $referenceToElement = $value;
+
+ unset($referenceToElement);
+ }
+
+ return $tree;
+ }
+
+ private static function &getElementByPath(array &$tree, array $parts)
+ {
+ $elem = &$tree;
+ $parentOfElem = null;
+
+ foreach ($parts as $i => $part) {
+ if (isset($elem[$part]) && \is_string($elem[$part])) {
+ /* Process next case:
+ * 'foo': 'test1',
+ * 'foo.bar': 'test2'
+ *
+ * $tree['foo'] was string before we found array {bar: test2}.
+ * Treat new element as string too, e.g. add $tree['foo.bar'] = 'test2';
+ */
+ $elem = &$elem[implode('.', \array_slice($parts, $i))];
+ break;
+ }
+ $parentOfElem = &$elem;
+ $elem = &$elem[$part];
+ }
+
+ if ($elem && \is_array($elem) && $parentOfElem) {
+ /* Process next case:
+ * 'foo.bar': 'test1'
+ * 'foo': 'test2'
+ *
+ * $tree['foo'] was array = {bar: 'test1'} before we found string constant `foo`.
+ * Cancel treating $tree['foo'] as array and cancel back it expansion,
+ * e.g. make it $tree['foo.bar'] = 'test1' again.
+ */
+ self::cancelExpand($parentOfElem, $part, $elem);
+ }
+
+ return $elem;
+ }
+
+ private static function cancelExpand(array &$tree, $prefix, array $node)
+ {
+ $prefix .= '.';
+
+ foreach ($node as $id => $value) {
+ if (\is_string($value)) {
+ $tree[$prefix.$id] = $value;
+ } else {
+ self::cancelExpand($tree, $prefix.$id, $value);
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Util/XliffUtils.php b/vendor/symfony/translation/Util/XliffUtils.php
new file mode 100644
index 0000000..3ace285
--- /dev/null
+++ b/vendor/symfony/translation/Util/XliffUtils.php
@@ -0,0 +1,163 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Util;
+
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+
+/**
+ * Provides some utility methods for XLIFF translation files, such as validating
+ * their contents according to the XSD schema.
+ *
+ * @author Fabien Potencier
+ */
+class XliffUtils
+{
+ /**
+ * Gets xliff file version based on the root "version" attribute.
+ *
+ * Defaults to 1.2 for backwards compatibility.
+ *
+ * @throws InvalidArgumentException
+ */
+ public static function getVersionNumber(\DOMDocument $dom): string
+ {
+ /** @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';
+ }
+
+ /**
+ * Validates and parses the given file into a DOMDocument.
+ *
+ * @throws InvalidResourceException
+ */
+ public static function validateSchema(\DOMDocument $dom): array
+ {
+ $xliffVersion = static::getVersionNumber($dom);
+ $internalErrors = libxml_use_internal_errors(true);
+ $disableEntities = libxml_disable_entity_loader(false);
+
+ $isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion));
+ if (!$isValid) {
+ libxml_disable_entity_loader($disableEntities);
+
+ return self::getXmlErrors($internalErrors);
+ }
+
+ libxml_disable_entity_loader($disableEntities);
+
+ $dom->normalizeDocument();
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+
+ return [];
+ }
+
+ public static function getErrorsAsString(array $xmlErrors): string
+ {
+ $errorsAsString = '';
+
+ foreach ($xmlErrors as $error) {
+ $errorsAsString .= sprintf("[%s %s] %s (in %s - line %d, column %d)\n",
+ LIBXML_ERR_WARNING === $error['level'] ? 'WARNING' : 'ERROR',
+ $error['code'],
+ $error['message'],
+ $error['file'],
+ $error['line'],
+ $error['column']
+ );
+ }
+
+ return $errorsAsString;
+ }
+
+ private static function getSchema(string $xliffVersion): string
+ {
+ if ('1.2' === $xliffVersion) {
+ $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-1.2-strict.xsd');
+ $xmlUri = 'http://www.w3.org/2001/xml.xsd';
+ } elseif ('2.0' === $xliffVersion) {
+ $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/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 self::fixXmlLocation($schemaSource, $xmlUri);
+ }
+
+ /**
+ * Internally changes the URI of a dependent xsd to be loaded locally.
+ */
+ private static function fixXmlLocation(string $schemaSource, string $xmlUri): string
+ {
+ $newPath = str_replace('\\', '/', __DIR__).'/../Resources/schemas/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.
+ */
+ private static function getXmlErrors(bool $internalErrors): array
+ {
+ $errors = [];
+ foreach (libxml_get_errors() as $error) {
+ $errors[] = [
+ 'level' => LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
+ 'code' => $error->code,
+ 'message' => trim($error->message),
+ 'file' => $error->file ?: 'n/a',
+ 'line' => $error->line,
+ 'column' => $error->column,
+ ];
+ }
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+
+ return $errors;
+ }
+}
diff --git a/vendor/symfony/translation/Writer/TranslationWriter.php b/vendor/symfony/translation/Writer/TranslationWriter.php
new file mode 100644
index 0000000..a44d24c
--- /dev/null
+++ b/vendor/symfony/translation/Writer/TranslationWriter.php
@@ -0,0 +1,90 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Writer;
+
+use Symfony\Component\Translation\Dumper\DumperInterface;
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+use Symfony\Component\Translation\Exception\RuntimeException;
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * TranslationWriter writes translation messages.
+ *
+ * @author Michel Salib
+ */
+class TranslationWriter implements TranslationWriterInterface
+{
+ private $dumpers = [];
+
+ /**
+ * Adds a dumper to the writer.
+ *
+ * @param string $format The format of the dumper
+ * @param DumperInterface $dumper The dumper
+ */
+ public function addDumper($format, DumperInterface $dumper)
+ {
+ $this->dumpers[$format] = $dumper;
+ }
+
+ /**
+ * 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);
+ }
+ }
+ }
+
+ /**
+ * Obtains the list of supported formats.
+ *
+ * @return array
+ */
+ public function getFormats()
+ {
+ return array_keys($this->dumpers);
+ }
+
+ /**
+ * 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
+ */
+ public function write(MessageCatalogue $catalogue, $format, $options = [])
+ {
+ if (!isset($this->dumpers[$format])) {
+ throw new InvalidArgumentException(sprintf('There is no dumper associated with format "%s".', $format));
+ }
+
+ // get the right dumper
+ $dumper = $this->dumpers[$format];
+
+ if (isset($options['path']) && !is_dir($options['path']) && !@mkdir($options['path'], 0777, true) && !is_dir($options['path'])) {
+ throw new RuntimeException(sprintf('Translation Writer was not able to create directory "%s"', $options['path']));
+ }
+
+ // save
+ $dumper->dump($catalogue, $options);
+ }
+}
diff --git a/vendor/symfony/translation/Writer/TranslationWriterInterface.php b/vendor/symfony/translation/Writer/TranslationWriterInterface.php
new file mode 100644
index 0000000..b07c08e
--- /dev/null
+++ b/vendor/symfony/translation/Writer/TranslationWriterInterface.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Writer;
+
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * TranslationWriter writes translation messages.
+ *
+ * @author Michel Salib
+ */
+interface TranslationWriterInterface
+{
+ /**
+ * 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
+ */
+ public function write(MessageCatalogue $catalogue, $format, $options = []);
+}
diff --git a/vendor/symfony/translation/composer.json b/vendor/symfony/translation/composer.json
new file mode 100644
index 0000000..fd25a4c
--- /dev/null
+++ b/vendor/symfony/translation/composer.json
@@ -0,0 +1,60 @@
+{
+ "name": "symfony/translation",
+ "type": "library",
+ "description": "Symfony Translation Component",
+ "keywords": [],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": "^7.1.3",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/translation-contracts": "^1.1.2"
+ },
+ "require-dev": {
+ "symfony/config": "~3.4|~4.0",
+ "symfony/console": "~3.4|~4.0",
+ "symfony/dependency-injection": "~3.4|~4.0",
+ "symfony/http-kernel": "~3.4|~4.0",
+ "symfony/intl": "~3.4|~4.0",
+ "symfony/service-contracts": "^1.1.2",
+ "symfony/var-dumper": "~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": "<3.4",
+ "symfony/dependency-injection": "<3.4",
+ "symfony/yaml": "<3.4"
+ },
+ "provide": {
+ "symfony/translation-implementation": "1.0"
+ },
+ "suggest": {
+ "symfony/config": "",
+ "symfony/yaml": "",
+ "psr/log-implementation": "To use logging capability in translator"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\Translation\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.3-dev"
+ }
+ }
+}
diff --git a/vendor/symfony/translation/phpunit.xml.dist b/vendor/symfony/translation/phpunit.xml.dist
new file mode 100644
index 0000000..21d3246
--- /dev/null
+++ b/vendor/symfony/translation/phpunit.xml.dist
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Tests
+ ./vendor
+
+
+
+
diff --git a/vendor/windwalker/renderer/.gitignore b/vendor/windwalker/renderer/.gitignore
new file mode 100644
index 0000000..84718b5
--- /dev/null
+++ b/vendor/windwalker/renderer/.gitignore
@@ -0,0 +1,11 @@
+# Development system files #
+.*
+!/.gitignore
+!/.travis.yml
+
+# Composer #
+vendor/*
+composer.lock
+
+# Test #
+phpunit.xml
diff --git a/vendor/windwalker/renderer/.travis.yml b/vendor/windwalker/renderer/.travis.yml
new file mode 100644
index 0000000..7b69eda
--- /dev/null
+++ b/vendor/windwalker/renderer/.travis.yml
@@ -0,0 +1,16 @@
+language: php
+
+sudo: false
+dist: trusty
+
+php:
+ - 7.1
+ - 7.2
+ - 7.3
+
+
+before_script:
+ - composer update --dev
+
+script:
+ - phpunit --configuration phpunit.travis.xml
diff --git a/vendor/windwalker/renderer/AbstractEngineRenderer.php b/vendor/windwalker/renderer/AbstractEngineRenderer.php
new file mode 100644
index 0000000..53aa9f3
--- /dev/null
+++ b/vendor/windwalker/renderer/AbstractEngineRenderer.php
@@ -0,0 +1,42 @@
+setPaths($paths);
+
+ $this->config = new Structure($this->config);
+
+ $this->config->load($config);
+ }
+
+ /**
+ * Method to escape output.
+ *
+ * @param string $output The output to escape.
+ *
+ * @return string The escaped output.
+ *
+ * @see ViewInterface::escape()
+ * @since 2.0
+ */
+ public function escape($output)
+ {
+ // Escape the output.
+ return htmlspecialchars((string) $output, ENT_COMPAT, 'UTF-8');
+ }
+
+ /**
+ * finFile
+ *
+ * @param string $file
+ * @param string $ext
+ *
+ * @return string
+ */
+ public function findFile($file, $ext = '')
+ {
+ $paths = clone $this->getPaths();
+
+ $file = str_replace('.', '/', $file);
+
+ $ext = $ext ? '.' . trim($ext, '.') : '';
+
+ foreach ($paths as $path) {
+ $filePath = $path . '/' . $file . $ext;
+
+ if (is_file($filePath)) {
+ return realpath($filePath);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * has
+ *
+ * @param string $file
+ * @param string $ext
+ *
+ * @return bool
+ *
+ * @since 3.5.2
+ */
+ public function has(string $file, string $ext = ''): bool
+ {
+ return $this->findFile($file, $ext) !== null;
+ }
+
+ /**
+ * getPaths
+ *
+ * @return \SplPriorityQueue
+ */
+ public function getPaths()
+ {
+ return $this->paths;
+ }
+
+ /**
+ * setPaths
+ *
+ * @param \SplPriorityQueue $paths
+ *
+ * @return AbstractRenderer Return self to support chaining.
+ */
+ public function setPaths($paths)
+ {
+ if (!($paths instanceof \SplPriorityQueue)) {
+ $priority = new \SplPriorityQueue();
+
+ foreach ((array) $paths as $i => $path) {
+ $priority->insert($path, 100 - ($i * 10));
+ }
+
+ $paths = $priority;
+ }
+
+ $this->paths = $paths;
+
+ return $this;
+ }
+
+ /**
+ * addPath
+ *
+ * @param string $path
+ * @param integer $priority
+ *
+ * @return static
+ */
+ public function addPath($path, $priority = 100)
+ {
+ $this->paths->insert($path, $priority);
+
+ return $this;
+ }
+
+ /**
+ * dumpPaths
+ *
+ * @return array
+ */
+ public function dumpPaths()
+ {
+ $paths = clone $this->paths;
+
+ $return = [];
+
+ foreach ($paths as $path) {
+ $return[] = $path;
+ }
+
+ return $return;
+ }
+
+ /**
+ * __get
+ *
+ * @param string $name
+ *
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ if ($name === 'config') {
+ return $this->$name;
+ }
+
+ throw new \UnexpectedValueException('Property ' . $name . ' not extists.');
+ }
+}
diff --git a/vendor/windwalker/renderer/Blade/BladeExtending.php b/vendor/windwalker/renderer/Blade/BladeExtending.php
new file mode 100644
index 0000000..ebd9ebe
--- /dev/null
+++ b/vendor/windwalker/renderer/Blade/BladeExtending.php
@@ -0,0 +1,59 @@
+directive($name, $closure);
+
+ return;
+ }
+
+ // For 4.x before
+ $blade->extend(
+ function ($view, BladeCompiler $compiler) use ($name, $closure) {
+ $pattern = $compiler->createMatcher($name);
+
+ return preg_replace_callback(
+ $pattern,
+ function ($matches) use ($closure) {
+ if (empty($matches[2])) {
+ return $matches[0];
+ }
+
+ return $matches[1] . $closure($matches[2]);
+ },
+ $view
+ );
+ }
+ );
+
+ return;
+ }
+}
diff --git a/vendor/windwalker/renderer/Blade/GlobalContainer.php b/vendor/windwalker/renderer/Blade/GlobalContainer.php
new file mode 100644
index 0000000..dbcb370
--- /dev/null
+++ b/vendor/windwalker/renderer/Blade/GlobalContainer.php
@@ -0,0 +1,282 @@
+getEngine()->make($file, (array) $data)->render();
+ }
+
+ /**
+ * Method to get property Blade
+ *
+ * @param bool $new
+ *
+ * @return BladeEnvironment
+ */
+ public function getEngine($new = false)
+ {
+ if (!$this->engine || $new) {
+ $this->engine = new BladeEnvironment($this->getResolver(), $this->getFinder(), $this->getDispatcher());
+
+ /** @var BladeCompiler $bladeCompiler */
+ $bladeCompiler = $this->getCompiler()->getCompiler();
+
+ foreach (GlobalContainer::getCompilers() as $name => $callback) {
+ BladeExtending::extend($bladeCompiler, $name, $callback);
+ }
+
+ foreach ($this->getCustomCompilers() as $name => $callback) {
+ BladeExtending::extend($bladeCompiler, $name, $callback);
+ }
+
+ foreach (GlobalContainer::getExtensions() as $name => $callback) {
+ $bladeCompiler->extend($callback);
+ }
+
+ // B/C for 4.* and 5.*
+ if (($rawTags = GlobalContainer::getRawTags()) && is_callable([$bladeCompiler, 'setRawTags'])) {
+ $bladeCompiler->setRawTags($rawTags[0], $rawTags[1]);
+ }
+
+ if ($tags = GlobalContainer::getContentTags()) {
+ $bladeCompiler->setContentTags($tags[0], $tags[1]);
+ }
+
+ if ($tags = GlobalContainer::getEscapedTags()) {
+ $bladeCompiler->setEscapedContentTags($tags[0], $tags[1]);
+ }
+ }
+
+ return $this->engine;
+ }
+
+ /**
+ * Method to set property blade
+ *
+ * @param BladeEnvironment $blade
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setEngine($blade)
+ {
+ if (!($blade instanceof BladeEnvironment)) {
+ throw new \InvalidArgumentException('Engine object should be Illuminate\View\Environment.');
+ }
+
+ $this->engine = $blade;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Filesystem
+ *
+ * @return Filesystem
+ */
+ public function getFilesystem()
+ {
+ if (!$this->filesystem) {
+ $this->filesystem = new Filesystem();
+ }
+
+ return $this->filesystem;
+ }
+
+ /**
+ * Method to set property filesystem
+ *
+ * @param Filesystem $filesystem
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setFilesystem($filesystem)
+ {
+ $this->filesystem = $filesystem;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Finder
+ *
+ * @return FileViewFinder
+ */
+ public function getFinder()
+ {
+ if (!$this->finder) {
+ $this->finder = new FileViewFinder($this->getFilesystem(), $this->dumpPaths());
+ }
+
+ return $this->finder;
+ }
+
+ /**
+ * Method to set property finder
+ *
+ * @param FileViewFinder $finder
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setFinder($finder)
+ {
+ $this->finder = $finder;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Resolver
+ *
+ * @return EngineResolver
+ */
+ public function getResolver()
+ {
+ if (!$this->resolver) {
+ $self = $this;
+
+ $this->resolver = new EngineResolver();
+
+ $this->resolver->register(
+ 'blade',
+ function () use ($self) {
+ return $self->getCompiler();
+ }
+ );
+ }
+
+ return $this->resolver;
+ }
+
+ /**
+ * Method to set property resolver
+ *
+ * @param EngineResolver $resolver
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setResolver($resolver)
+ {
+ $this->resolver = $resolver;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Dispatcher
+ *
+ * @return Dispatcher
+ */
+ public function getDispatcher()
+ {
+ if (!$this->dispatcher) {
+ $this->dispatcher = new Dispatcher();
+ }
+
+ return $this->dispatcher;
+ }
+
+ /**
+ * Method to set property dispatcher
+ *
+ * @param Dispatcher $dispatcher
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setDispatcher($dispatcher)
+ {
+ $this->dispatcher = $dispatcher;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Compiler
+ *
+ * @return CompilerEngine
+ */
+ public function getCompiler()
+ {
+ if (!$this->compiler) {
+ $cachePath = $this->config->get('cache_path') ?: GlobalContainer::getCachePath();
+
+ if (!$cachePath) {
+ throw new \InvalidArgumentException('Please set cache_path into config.');
+ }
+
+ if (!is_dir($cachePath)) {
+ mkdir($cachePath, 0755, true);
+ }
+
+ $this->compiler = new CompilerEngine(new BladeCompiler($this->getFilesystem(), $cachePath));
+ }
+
+ return $this->compiler;
+ }
+
+ /**
+ * Method to set property compiler
+ *
+ * @param CompilerEngine $compiler
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setCompiler($compiler)
+ {
+ $this->compiler = $compiler;
+
+ return $this;
+ }
+
+ /**
+ * addCustomCompiler
+ *
+ * @param string $name
+ * @param callable $compiler
+ *
+ * @return static
+ */
+ public function addCustomCompiler($name, $compiler)
+ {
+ if (!is_callable($compiler)) {
+ throw new \InvalidArgumentException('Compiler should be callable.');
+ }
+
+ $this->customCompilers[$name] = $compiler;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property CustomCompiler
+ *
+ * @return \callable[]
+ */
+ public function getCustomCompilers()
+ {
+ return $this->customCompilers;
+ }
+
+ /**
+ * Method to set property customCompiler
+ *
+ * @param \callable[] $customCompilers
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setCustomCompilers(array $customCompilers)
+ {
+ $this->customCompilers = $customCompilers;
+
+ return $this;
+ }
+}
diff --git a/vendor/windwalker/renderer/Edge/GlobalContainer.php b/vendor/windwalker/renderer/Edge/GlobalContainer.php
new file mode 100644
index 0000000..23adb48
--- /dev/null
+++ b/vendor/windwalker/renderer/Edge/GlobalContainer.php
@@ -0,0 +1,247 @@
+getName()] = $extension;
+ }
+
+ /**
+ * getExtension
+ *
+ * @param string $name
+ *
+ * @return \Twig_ExtensionInterface
+ */
+ public static function getExtension($name)
+ {
+ if (!empty(static::$extensions[$name])) {
+ return static::$extensions[$name];
+ }
+
+ return null;
+ }
+
+ /**
+ * removeExtension
+ *
+ * @param string $name
+ *
+ * @return void
+ */
+ public static function removeExtension($name)
+ {
+ if (isset(static::$extensions[$name])) {
+ unset(static::$extensions[$name]);
+ }
+ }
+
+ /**
+ * Method to get property Extensions
+ *
+ * @return EdgeExtensionInterface[]
+ */
+ public static function getExtensions()
+ {
+ return static::$extensions;
+ }
+
+ /**
+ * Method to set property extensions
+ *
+ * @param EdgeExtensionInterface[] $extensions
+ *
+ * @return void
+ */
+ public static function setExtensions(array $extensions)
+ {
+ static::$extensions = $extensions;
+ }
+
+ /**
+ * setGlobal
+ *
+ * @param string $name
+ * @param mixed $value
+ *
+ * @return void
+ */
+ public static function addGlobal($name, $value)
+ {
+ static::$globals[$name] = $value;
+ }
+
+ /**
+ * getGlobal
+ *
+ * @param string $name
+ *
+ * @return mixed
+ */
+ public static function getGlobal($name)
+ {
+ if (array_key_exists($name, static::$globals)) {
+ return static::$globals[$name];
+ }
+
+ return null;
+ }
+
+ /**
+ * removeGlobal
+ *
+ * @param string $name
+ *
+ * @return void
+ */
+ public static function removeGlobal($name)
+ {
+ if (isset(static::$globals[$name])) {
+ unset(static::$globals[$name]);
+ }
+ }
+
+ /**
+ * Method to get property Globals
+ *
+ * @return array
+ */
+ public static function getGlobals()
+ {
+ return static::$globals;
+ }
+
+ /**
+ * Method to set property globals
+ *
+ * @param array $globals
+ *
+ * @return void
+ */
+ public static function setGlobals(array $globals)
+ {
+ static::$globals = $globals;
+ }
+
+ /**
+ * Method to get property RawTags
+ *
+ * @return array
+ */
+ public static function getRawTags()
+ {
+ return static::$rawTags;
+ }
+
+ /**
+ * Method to set property rawTags
+ *
+ * @param string $start
+ * @param string $end
+ */
+ public static function setRawTags($start, $end)
+ {
+ static::$rawTags = [$start, $end];
+ }
+
+ /**
+ * Method to get property ContentTags
+ *
+ * @return array
+ */
+ public static function getContentTags()
+ {
+ return static::$contentTags;
+ }
+
+ /**
+ * Method to set property contentTags
+ *
+ * @param string $start
+ * @param string $end
+ */
+ public static function setContentTags($start, $end)
+ {
+ static::$contentTags = [$start, $end];
+ }
+
+ /**
+ * Method to get property EscapedTags
+ *
+ * @return array
+ */
+ public static function getEscapedTags()
+ {
+ return static::$escapedTags;
+ }
+
+ /**
+ * Method to set property escapedTags
+ *
+ * @param string $start
+ * @param string $end
+ */
+ public static function setEscapedTags($start, $end)
+ {
+ static::$escapedTags = [$start, $end];
+ }
+}
diff --git a/vendor/windwalker/renderer/EdgeRenderer.php b/vendor/windwalker/renderer/EdgeRenderer.php
new file mode 100644
index 0000000..7ef4ec7
--- /dev/null
+++ b/vendor/windwalker/renderer/EdgeRenderer.php
@@ -0,0 +1,275 @@
+engine || $new) {
+ $this->loader = null;
+ $this->compiler = null;
+ $this->cache = null;
+
+ $edge = new Edge($this->getLoader(), $this->getCompiler(), $this->getCache());
+
+ foreach (GlobalContainer::getExtensions() as $name => $extension) {
+ $edge->addExtension($extension, $name);
+ }
+
+ foreach ($this->getExtensions() as $name => $extension) {
+ $edge->addExtension($extension, $name);
+ }
+
+ foreach (GlobalContainer::getGlobals() as $key => $value) {
+ $edge->addGlobal($key, $value);
+ }
+
+ $this->engine = $edge;
+ }
+
+ return $this->engine;
+ }
+
+ /**
+ * Method to set property engine
+ *
+ * @param Edge $engine
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setEngine($engine)
+ {
+ if (!$this->engine instanceof Edge) {
+ throw new \InvalidArgumentException('Engine should be instance of Edge');
+ }
+
+ $this->engine = $engine;
+
+ return $this;
+ }
+
+ /**
+ * render
+ *
+ * @param string $file
+ * @param array $data
+ *
+ * @return string
+ * @throws \Windwalker\Edge\Exception\EdgeException
+ */
+ public function render($file, $data = [])
+ {
+ if ($data instanceof \Traversable) {
+ $data = iterator_to_array($data);
+ }
+
+ if (is_object($data)) {
+ $data = get_object_vars($data);
+ }
+
+ return $this->getEngine(true)->render($file, (array) $data);
+ }
+
+ /**
+ * finFile
+ *
+ * @param string $file
+ * @param string $ext
+ *
+ * @return string
+ */
+ public function findFile($file, $ext = '')
+ {
+ try {
+ return $this->getEngine()->getLoader()->find($file);
+ } catch (LayoutNotFoundException $e) {
+ return null;
+ }
+ }
+
+ /**
+ * Method to get property Compiler
+ *
+ * @return EdgeCompilerInterface
+ */
+ public function getCompiler()
+ {
+ if (!$this->compiler) {
+ $this->compiler = new EdgeCompiler();
+ }
+
+ return $this->compiler;
+ }
+
+ /**
+ * Method to set property compiler
+ *
+ * @param EdgeCompilerInterface $compiler
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setCompiler($compiler)
+ {
+ $this->compiler = $compiler;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Loader
+ *
+ * @return EdgeLoaderInterface
+ */
+ public function getLoader()
+ {
+ if (!$this->loader) {
+ $this->loader = new EdgeFileLoader($this->dumpPaths());
+ }
+
+ return $this->loader;
+ }
+
+ /**
+ * Method to set property loader
+ *
+ * @param EdgeLoaderInterface $loader
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setLoader($loader)
+ {
+ $this->loader = $loader;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Cache
+ *
+ * @return EdgeCacheInterface
+ */
+ public function getCache()
+ {
+ if (!$this->cache) {
+ if ($this->config->exists('cache_path')) {
+ $this->cache = new EdgeFileCache($this->config->get('cache_path'));
+ } else {
+ $this->cache = new EdgeArrayCache();
+ }
+ }
+
+ return $this->cache;
+ }
+
+ /**
+ * Method to set property cache
+ *
+ * @param EdgeCacheInterface $cache
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setCache($cache)
+ {
+ $this->cache = $cache;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Extensions
+ *
+ * @return EdgeExtensionInterface[]
+ */
+ public function getExtensions()
+ {
+ return $this->extensions;
+ }
+
+ /**
+ * Method to set property extensions
+ *
+ * @param EdgeExtensionInterface[] $extensions
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setExtensions($extensions)
+ {
+ $this->extensions = $extensions;
+
+ return $this;
+ }
+
+ /**
+ * addExtension
+ *
+ * @param EdgeExtensionInterface $extension
+ * @param string $name
+ *
+ * @return static
+ */
+ public function addExtension(EdgeExtensionInterface $extension, $name = null)
+ {
+ $this->extensions[$name ?: $extension->getName()] = $extension;
+
+ return $this;
+ }
+}
diff --git a/vendor/windwalker/renderer/MustacheRenderer.php b/vendor/windwalker/renderer/MustacheRenderer.php
new file mode 100644
index 0000000..9b47c5e
--- /dev/null
+++ b/vendor/windwalker/renderer/MustacheRenderer.php
@@ -0,0 +1,135 @@
+getEngine();
+
+ $path = $this->findFile($file);
+
+ $engine->setLoader($this->getLoader(dirname($path)));
+
+ return $engine->render($file, $data);
+ }
+
+ /**
+ * findFile
+ *
+ * @param string $file
+ * @param string $ext
+ *
+ * @return string
+ */
+ public function findFile($file, $ext = '')
+ {
+ $ext = $ext ?: $this->config->get('extension', 'mustache');
+
+ return parent::findFile($file, $ext);
+ }
+
+ /**
+ * Method to get property Engine
+ *
+ * @param boolean $new
+ *
+ * @return \Mustache_Engine
+ */
+ public function getEngine($new = false)
+ {
+ if (!$this->engine || $new) {
+ $this->engine = new \Mustache_Engine($this->config->get('options', []));
+ }
+
+ return $this->engine;
+ }
+
+ /**
+ * Method to set property engine
+ *
+ * @param \Mustache_Engine $engine
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setEngine($engine)
+ {
+ if (!($engine instanceof \Mustache_Engine)) {
+ throw new \InvalidArgumentException('Engine object should be Mustache_Engine');
+ }
+
+ $this->engine = $engine;
+
+ return $this;
+ }
+
+ /**
+ * Method to get property Loader
+ *
+ * @param string $path
+ *
+ * @return \Mustache_Loader
+ */
+ public function getLoader($path = null)
+ {
+ if (!$this->loader) {
+ $options = [
+ // 'extension' => '.html'
+ ];
+
+ $options = array_merge($options, (array) $this->config->get('loader_options', []));
+
+ $this->loader = new \Mustache_Loader_FilesystemLoader($path, $options);
+ }
+
+ return $this->loader;
+ }
+
+ /**
+ * Method to set property loader
+ *
+ * @param \Mustache_Loader $loader
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setLoader($loader)
+ {
+ $this->loader = $loader;
+
+ return $this;
+ }
+}
diff --git a/vendor/windwalker/renderer/PhpRenderer.php b/vendor/windwalker/renderer/PhpRenderer.php
new file mode 100644
index 0000000..bcf378d
--- /dev/null
+++ b/vendor/windwalker/renderer/PhpRenderer.php
@@ -0,0 +1,314 @@
+data = $__data = (array) $__data;
+
+ $this->prepareData($__data);
+
+ $__filePath = $this->findFile($file);
+
+ if (!$__filePath) {
+ $__paths = $this->dumpPaths();
+
+ $__paths = "\n " . implode(" |\n ", $__paths);
+
+ throw new \UnexpectedValueException(sprintf('File: %s not found. Paths in queue: %s', $file, $__paths));
+ }
+
+ foreach ($__data as $key => $value) {
+ if ($key === 'data') {
+ $key = '_data';
+ }
+
+ $$key = $value;
+ }
+
+ unset($__data);
+
+ // Start an output buffer.
+ ob_start();
+
+ // Load the layout.
+ include $__filePath;
+
+ // Get the layout contents.
+ $output = ob_get_clean();
+
+ // Handler extend
+ if (!$this->extend) {
+ return $output;
+ }
+
+ /** @var $parent phpRenderer */
+ $parent = $this->createSelf();
+
+ foreach ($this->block as $name => $block) {
+ $parent->setBlock($name, $block);
+ }
+
+ $output = $parent->render($this->extend, $this->data);
+
+ return $output;
+ }
+
+ /**
+ * finFile
+ *
+ * @param string $file
+ * @param string $ext
+ *
+ * @return string
+ */
+ public function findFile($file, $ext = 'php')
+ {
+ return parent::findFile($file, $ext);
+ }
+
+ /**
+ * load
+ *
+ * @param string $file
+ * @param array $data
+ *
+ * @return string
+ */
+ public function load($file, $data = null)
+ {
+ $data = array_merge($this->data, (array) $data);
+
+ $renderer = $this->createSelf();
+
+ return $renderer->render($file, $data);
+ }
+
+ /**
+ * prepareData
+ *
+ * @param array &$data
+ *
+ * @return void
+ */
+ protected function prepareData(&$data)
+ {
+ }
+
+ /**
+ * getParent
+ *
+ * @return mixed|null
+ */
+ public function parent()
+ {
+ if (!$this->extend) {
+ return null;
+ }
+
+ if (!$this->parent) {
+ $this->parent = $this->createSelf();
+
+ $this->parent->render($this->extend, $this->data);
+ }
+
+ return $this->parent->getBlock($this->currentBlock);
+ }
+
+ /**
+ * createSelf
+ *
+ * @return static
+ */
+ protected function createSelf()
+ {
+ return new static($this->paths, $this->config);
+ }
+
+ /**
+ * extend
+ *
+ * @param string $name
+ *
+ * @return void
+ *
+ * @throws \LogicException
+ */
+ public function extend($name)
+ {
+ if ($this->extend) {
+ throw new \LogicException('Please just extend one file.');
+ }
+
+ $this->extend = $name;
+ }
+
+ /**
+ * getBlock
+ *
+ * @param string $name
+ *
+ * @return mixed
+ */
+ public function getBlock($name)
+ {
+ return !empty($this->block[$name]) ? $this->block[$name] : null;
+ }
+
+ /**
+ * setBlock
+ *
+ * @param string $name
+ * @param string $content
+ *
+ * @return PhpRenderer Return self to support chaining.
+ */
+ public function setBlock($name, $content = '')
+ {
+ $this->block[$name] = $content;
+
+ return $this;
+ }
+
+ /**
+ * setBlock
+ *
+ * @param string $name
+ *
+ * @return void
+ */
+ public function block($name)
+ {
+ $this->currentBlock = $name;
+
+ $this->getBlockQueue()->push($name);
+
+ // Start an output buffer.
+ ob_start();
+ }
+
+ /**
+ * endblock
+ *
+ * @return void
+ */
+ public function endblock()
+ {
+ $name = $this->getBlockQueue()->pop();
+
+ // If this block name not exists on parent level, we just echo inner content.
+ if (!empty($this->block[$name])) {
+ ob_get_clean();
+
+ echo $this->block[$name];
+
+ return;
+ }
+
+ // Get the layout contents.
+ echo $this->block[$name] = ob_get_clean();
+ }
+
+ /**
+ * getBlockQueue
+ *
+ * @return \SplQueue
+ */
+ public function getBlockQueue()
+ {
+ if (!$this->blockQueue) {
+ $this->blockQueue = new \SplStack();
+ }
+
+ return $this->blockQueue;
+ }
+
+ /**
+ * reset
+ *
+ * @return static
+ */
+ public function reset()
+ {
+ $this->file = null;
+ $this->extend = null;
+ $this->parent = null;
+ $this->data = null;
+ $this->block = [];
+ $this->blockQueue = null;
+ $this->currentBlock = null;
+
+ return $this;
+ }
+}
diff --git a/vendor/windwalker/renderer/PlatesRenderer.php b/vendor/windwalker/renderer/PlatesRenderer.php
new file mode 100644
index 0000000..0aa124a
--- /dev/null
+++ b/vendor/windwalker/renderer/PlatesRenderer.php
@@ -0,0 +1,144 @@
+engine || $new) {
+ $this->engine = new PlatesEngine(
+ dirname($this->config->get('path.found')),
+ ltrim($this->config->get('extension', '.tpl'), '.')
+ );
+
+ foreach ($this->folders as $namespace => $folder) {
+ $this->engine->addFolder($namespace, $folder['folder'], $folder['fallback']);
+ }
+
+ foreach ($this->extensions as $extension) {
+ $this->engine->loadExtension($extension);
+ }
+ }
+
+ return $this->engine;
+ }
+
+ /**
+ * Method to set property engine
+ *
+ * @param PlatesEngine $engine
+ *
+ * @return static Return self to support chaining.
+ */
+ public function setEngine($engine)
+ {
+ if (!($engine instanceof PlatesEngine)) {
+ throw new \InvalidArgumentException('Engine object should be Mustache_Engine');
+ }
+
+ $this->engine = $engine;
+
+ return $this;
+ }
+
+ /**
+ * render
+ *
+ * @param string $file
+ * @param array $data
+ *
+ * @return string
+ */
+ public function render($file, $data = [])
+ {
+ $path = $this->findFile($file);
+
+ $this->config->set('path.found', $path);
+
+ return $this->getEngine()->render($file, $data);
+ }
+
+ /**
+ * findFile
+ *
+ * @param string $file
+ * @param string $ext
+ *
+ * @return string
+ */
+ public function findFile($file, $ext = '')
+ {
+ $ext = $ext ?: $this->config->get('extension', 'tpl');
+
+ return parent::findFile($file, $ext);
+ }
+
+ /**
+ * addExtension
+ *
+ * @param ExtensionInterface $extension
+ *
+ * @return static
+ */
+ public function addExtension(ExtensionInterface $extension)
+ {
+ $this->extensions[] = $extension;
+
+ return $this;
+ }
+
+ /**
+ * addFolder
+ *
+ * @param string $namespace
+ * @param string $folder
+ * @param boolean $fallback
+ *
+ * @return static
+ */
+ public function addFolder($namespace, $folder, $fallback = false)
+ {
+ $this->folders[$namespace] = [
+ 'folder' => $folder,
+ 'fallback' => $fallback,
+ ];
+
+ return $this;
+ }
+}
diff --git a/vendor/windwalker/renderer/README.md b/vendor/windwalker/renderer/README.md
new file mode 100644
index 0000000..a999aa6
--- /dev/null
+++ b/vendor/windwalker/renderer/README.md
@@ -0,0 +1,371 @@
+# Windwalker Renderer
+
+Windwalker Renderer is a simple template engine loader to load file for engines to render.
+
+## Installation via Composer
+
+Add this to the require block in your `composer.json`.
+
+``` json
+{
+ "require": {
+ "windwalker/renderer": "~3.0"
+ }
+}
+```
+
+## Support Engines
+
+- [PHP](#getting-started)
+- [Twig](#twig-renderer)
+- [Blade](#blade-renderer)
+- [Edge](#edge-renderer) (A Blade compitable engine without dependencies)
+- [Mustache](#mustache-renderer)
+- [Plates](#plates-renderer)
+
+## Getting Started
+
+``` php
+use Windwalker\Renderer\PhpRenderer;
+
+$config = array();
+
+$renderer = new PhpRenderer(__DIR__ . '/file/path', $config);
+
+$data = array('title' => 'foo');
+
+echo $renderer->render('template', $data);
+```
+
+### In `template.php`
+
+This is a simple php engine to help us render template.
+
+``` php
+
escape($title); ?>
+```
+
+### Include Sub Template
+
+Use `load()` to load other template file as a block. The first argument is file path, the second argument is new data
+to merge with original data.
+
+``` php
+echo $this->load('sub.template', array('bar' => 'baz'));
+```
+
+Example to load `foo/article.php`:
+
+``` php
+
escape($title); ?>
+
+articles as $article): ?>
+ load('foo.article', array('bar' => 'baz')); ?>
+
+```
+
+### Extends Parent Template
+
+In Windwalker Renderer, there is a powerful function like Twig or Blade, we provide `extend()` method to extends
+parent template. (`extends` in php is a reserved string, so we can only use `extend`)
+
+For example, this is the parent `_global/html.php` template:
+
+``` php
+
+
+
+ block('title');?>Homeendblock(); ?>
+
+
+
+ block('body');?>
+
Home page
+ endblock(); ?>
+
+
+
+```
+
+And we can extends it in our View:
+
+``` php
+extend('_global.html');
+?>
+
+block('title');?>Articleendblock(); ?>
+
+block('body');?>
+
+
Article
+
FOO
+
+endblock(); ?>
+```
+
+The result will be:
+
+``` html
+
+
+
+ Article
+
+
+
+
+
Article
+
FOO
+
+
+
+
+```
+
+### Show Parent
+
+We can echo parent data in a block:
+
+``` php
+block('body');?>
+ parent(); ?>
+
+
Article
+
FOO
+
+endblock(); ?>
+```
+
+Result:
+
+``` html
+
Home page
+
+
Article
+
FOO
+
+```
+
+## Add More Paths to Search
+
+We create 3 paths by `SplPriorityQueue`, that make theme path is priority to others, so we can override view templates
+ by theme, and view can also override system template.
+
+
+``` php
+$paths = new \SplPriorityQueue;
+
+$paths->insert('path/to/system', 100);
+$paths->insert('path/to/view', 200);
+$paths->insert('path/to/theme', 300);
+
+$renderer = new PhpRenderer($paths);
+
+$renderer->render('foo', $data);
+```
+
+## Twig Renderer
+
+[Twig](http://twig.sensiolabs.org/) Renderer help us render files by twig engine.
+
+``` php
+use Windwalker\Renderer\TwigRenderer;
+
+$renderer = new TwigRenderer($paths);
+
+$renderer->render('foo', $data);
+```
+
+### Set custom Twig instance or Loader.
+
+``` php
+$renderer->setEngine(new \Twig_Environment);
+$renderer->setLoader(new MyTwigLoader);
+```
+
+### Add Twig Extensions
+
+``` php
+$renderer->addExtension(new MyTwigExtension);
+```
+
+### Debug Mode
+
+Set debug config when construct:
+
+``` php
+$renderer = new TwigRenderer($paths, array('debug' => true));
+```
+
+## Blade Renderer
+
+Blade is a powerful php template engine which created by Laravel. We integrate it in our Renderer that eveyone can use it without Laravel.
+
+Add this line to your composer require block and run `composer update`:
+
+``` json
+"illuminate/view" : "4.*"
+```
+
+Create Blade Renderer:
+
+``` php
+use Windwalker\Renderer\BladeRenderer;
+
+$renderer = new BladeRenderer($paths, array('cache_path' => __DIR__ . '/cache'));
+
+$renderer->render('foo', $data);
+```
+
+The file name must suffix with `.blade.php`.
+
+### Add Custom Compilers
+
+``` php
+$renderer = new BladeRenderer($paths, array('cache_path' => __DIR__ . '/cache'));
+
+$renderer->addCustomCompiler('datetime', function($expression)
+{
+ return "format('m/d/Y H:i'); ?>";
+});
+```
+
+More about Blade engine please see [Laravel Document](http://laravel.com/docs/4.2/templates#blade-templating).
+
+## Edge Renderer
+
+Edge is a Blade compatible template engine which created to support Windwalker itself.
+
+``` php
+$renderer = new EdgeRenderer;
+
+// Ad custom extensions
+$renderer->addExtension(new MyEdgeExtension);
+
+echo $renderer->render('layout.main', $data);
+```
+
+Cache files:
+
+``` php
+$renderer = new EdgeRenderer($paths, array('cache_path' => __DIR__ . '/cache'));
+echo $renderer->render('layout.main', $data);
+```
+
+See [Windwalker Edge](https://github.com/ventoviro/windwalker-edge)
+
+## Mustache Renderer
+
+We also provide [Mustache](http://mustache.github.io/) Renderer.
+
+Add this line to your composer require block and run `composer update`:
+
+``` json
+"mustache/mustache" : "2.*"
+```
+
+Create Mustache Renderer:
+
+``` php
+use Windwalker\Renderer\MustacheRenderer;
+
+class Chris
+{
+ public $name = "Chris";
+ public $value = 10000;
+
+ public function taxed_value()
+ {
+ return $this->value - ($this->value * 0.4);
+ }
+
+ public $in_ca = true;
+}
+
+$renderer = new MustacheRenderer($paths);
+
+$renderer->render('foo', new Chris)
+```
+
+The file is `foo.mustache`:
+
+``` mustache
+Hello {{name}}
+You have just won ${{value}}!
+{{#in_ca}}
+Well, ${{taxed_value}}, after taxes.
+{{/in_ca}}
+```
+
+Abd the output:
+
+``` html
+Hello Chris
+You have just won $10000!
+Well, $6000, after taxes.
+```
+
+### Loader
+
+``` php
+$renderer->setLoader(new \Mustache_Loader_FilesystemLoader($path, $options));
+```
+
+### Config
+
+We can change the file extension name and many other configs, please see [Mustache PHP Document](https://github.com/bobthecow/mustache.php/wiki).
+
+## Plates Renderer
+
+``` php
+use Windwalker\Renderer\PlatesRenderer;
+
+$renderer = new PlatesRenderer;
+
+echo $renderer->render('flower.sakura', array('foo' => 'bar'));
+```
+
+See: [Plates](http://platesphp.com/)
+
+## Use Cases
+
+Renderer has many use cases, one of often usage is that integrating it with view object as engine and loader.
+
+``` php
+class View
+{
+ public function __construct($data = array(), RendererInterface $renderer = null)
+ {
+ $this->data = $data;
+ $this->renderer = $renderer ? : new PhpRenderer;
+ }
+
+ public function render($layout)
+ {
+ // Do some stuff...
+
+ return $this->renderer->render($layout, $this->data);
+ }
+}
+```
+
+Or be a layout widget:
+
+``` php
+class Widget extends PhpRenderer
+{
+ public function __construct($config = array())
+ {
+ $paths = array(
+ 'path/of/theme/widget',
+ 'path/of/system/widget'
+ );
+
+ parent::__construct($paths, $config);
+ }
+}
+
+// Call this class everywhere
+echo (new Widget)->render('foo', array('bar' => 'baz'));
+```
diff --git a/vendor/windwalker/renderer/RendererInterface.php b/vendor/windwalker/renderer/RendererInterface.php
new file mode 100644
index 0000000..a6d041c
--- /dev/null
+++ b/vendor/windwalker/renderer/RendererInterface.php
@@ -0,0 +1,34 @@
+instance = new BladeRenderer(static::$path, ['cache_path' => __DIR__ . '/cache']);
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @return void
+ */
+ protected function tearDown(): void
+ {
+ Filesystem::delete(__DIR__ . '/cache');
+ }
+
+ /**
+ * Destructor
+ */
+ public function __destruct()
+ {
+ Filesystem::delete(__DIR__ . '/cache');
+ }
+
+ /**
+ * Method to test render().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::render
+ */
+ public function testRender()
+ {
+ $html = $this->instance->render('hello');
+
+ $expect = <<
+
+ This is the master sidebar.
+
+
This is appended to the master sidebar.
+
+
This is my body content.
+
+
+
+HTML;
+
+ $this->assertHtmlFormatEquals($expect, $html);
+ }
+
+ /**
+ * testAddCompilers
+ *
+ * @return void
+ */
+ public function testAddCompilers()
+ {
+ $this->instance->addCustomCompiler(
+ 'upper',
+ function ($expression) {
+ return "";
+ }
+ );
+
+ $expect = <<
+
+ This is the master sidebar.
+
+
This is appended to the master sidebar.
+
+
THIS IS MY BODY CONTENT.
+
+
+
+HTML;
+
+ $html = $this->instance->render('compiler');
+
+ $this->assertHtmlFormatEquals($expect, $html);
+ }
+
+ /**
+ * Method to test getBlade().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::getEngine
+ */
+ public function testGetBlade()
+ {
+ $this->assertInstanceOf(Factory::class, $this->instance->getEngine());
+ }
+
+ /**
+ * Method to test setBlade().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::setEngine
+ * @TODO Implement testSetBlade().
+ */
+ public function testSetBlade()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getFilesystem().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::getFilesystem
+ */
+ public function testGetFilesystem()
+ {
+ $this->assertInstanceOf(\Illuminate\Filesystem\Filesystem::class, $this->instance->getFilesystem());
+ }
+
+ /**
+ * Method to test setFilesystem().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::setFilesystem
+ * @TODO Implement testSetFilesystem().
+ */
+ public function testSetFilesystem()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getFinder().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::getFinder
+ */
+ public function testGetFinder()
+ {
+ $this->assertInstanceOf('Illuminate\View\FileViewFinder', $this->instance->getFinder());
+ }
+
+ /**
+ * Method to test setFinder().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::setFinder
+ * @TODO Implement testSetFinder().
+ */
+ public function testSetFinder()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getResolver().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::getResolver
+ */
+ public function testGetResolver()
+ {
+ $this->assertInstanceOf('Illuminate\View\Engines\EngineResolver', $this->instance->getResolver());
+ }
+
+ /**
+ * Method to test setResolver().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::setResolver
+ */
+ public function testSetResolver()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getDispatcher().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::getDispatcher
+ */
+ public function testGetDispatcher()
+ {
+ $this->assertInstanceOf('Illuminate\Events\Dispatcher', $this->instance->getDispatcher());
+ }
+
+ /**
+ * Method to test setDispatcher().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::setDispatcher
+ * @TODO Implement testSetDispatcher().
+ */
+ public function testSetDispatcher()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getCompiler().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::getCompiler
+ */
+ public function testGetCompiler()
+ {
+ $this->assertInstanceOf('Illuminate\View\Engines\CompilerEngine', $this->instance->getCompiler());
+ }
+
+ /**
+ * Method to test setCompiler().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\BladeRenderer::setCompiler
+ * @TODO Implement testSetCompiler().
+ */
+ public function testSetCompiler()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+}
diff --git a/vendor/windwalker/renderer/Test/MustacheRendererTest.php b/vendor/windwalker/renderer/Test/MustacheRendererTest.php
new file mode 100644
index 0000000..971b18f
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/MustacheRendererTest.php
@@ -0,0 +1,183 @@
+instance = new MustacheRenderer(static::$path);
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @return void
+ */
+ protected function tearDown(): void
+ {
+ }
+
+ /**
+ * Method to test render().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\MustacheRenderer::render
+ */
+ public function testRender()
+ {
+ $html = $this->instance->render('hello', new Chris());
+
+ $expect = <<assertDomStringEqualsDomString($expect, $html);
+ }
+
+ /**
+ * Method to test getEngine().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\MustacheRenderer::getEngine
+ * @TODO Implement testGetEngine().
+ */
+ public function testGetEngine()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test setEngine().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\MustacheRenderer::setEngine
+ * @TODO Implement testSetEngine().
+ */
+ public function testSetEngine()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getLoader().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\MustacheRenderer::getLoader
+ * @TODO Implement testGetLoader().
+ */
+ public function testGetLoader()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test setLoader().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\MustacheRenderer::setLoader
+ * @TODO Implement testSetLoader().
+ */
+ public function testSetLoader()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+}
+/**
+ * The Chris class.
+ *
+ * @since 2.0
+ */
+class Chris
+{
+ /**
+ * Property name.
+ *
+ * @var string
+ */
+ public $name = "Chris";
+
+ /**
+ * Property value.
+ *
+ * @var int
+ */
+ public $value = 10000;
+
+ /**
+ * taxed_value
+ *
+ * @return int
+ */
+ public function taxed_value()
+ {
+ return $this->value - ($this->value * 0.4);
+ }
+
+ /**
+ * Property in_ca.
+ *
+ * @var bool
+ */
+ public $in_ca = true;
+}
diff --git a/vendor/windwalker/renderer/Test/PhpRendererTest.php b/vendor/windwalker/renderer/Test/PhpRendererTest.php
new file mode 100644
index 0000000..806a560
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/PhpRendererTest.php
@@ -0,0 +1,354 @@
+instance = new PhpRenderer(static::$path);
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @return void
+ */
+ protected function tearDown(): void
+ {
+ }
+
+ /**
+ * Method to test render().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\PhpRenderer::render
+ */
+ public function testRender()
+ {
+ $html = $this->instance->render('default');
+
+ $expect = <<
+ Default
+
+HTML;
+
+ $this->assertDomStringEqualsDomString($expect, $html);
+ }
+
+ /**
+ * Method to test findFile().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\PhpRenderer::findFile
+ */
+ public function testFindFile()
+ {
+ $file = $this->instance->findFile('flower');
+
+ $this->assertEquals(realpath(static::$path . '/flower.php'), $file);
+
+ $file = $this->instance->findFile('foo/bar');
+
+ $this->assertEquals(realpath(static::$path . '/foo/bar.php'), $file);
+ }
+
+ /**
+ * Method to test extend().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\PhpRenderer::extend
+ */
+ public function testRenderTopLevelBlock()
+ {
+ $html = $this->instance->render('extend1');
+
+ $expect = <<
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur eleifend, ante vitae vestibulum tempus
+
+HTML;
+
+ $this->assertDomStringEqualsDomString($expect, $html);
+ }
+
+ /**
+ * Method to test extend().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\PhpRenderer::extend
+ */
+ public function testExtend()
+ {
+ $html = $this->instance->render('foo/extend2');
+
+ $expect = <<
+Lorem ipsum dolor sit amet,
+Vivamus tincidunt consectetur finibus.
+Curabitur eleifend, ante vitae vestibulum tempus
+
+HTML;
+
+ $this->assertDomStringEqualsDomString($expect, $html);
+
+ $this->instance->reset();
+
+ // Render twice
+ $html = $this->instance->render('foo/extend3');
+
+ $expect = <<
+Lorem ipsum dolor sit amet,
+Sed tempor urna quis varius luctus.
+Curabitur eleifend, ante vitae vestibulum tempus
+
+HTML;
+
+ $this->assertDomStringEqualsDomString($expect, $html);
+ }
+
+ /**
+ * testExtendMultiLevels
+ *
+ * @return void
+ */
+ public function testExtendMultiLevels()
+ {
+ $html = $this->instance->render('foo/extend3');
+
+ $expect = <<
+Lorem ipsum dolor sit amet,
+Sed tempor urna quis varius luctus.
+Curabitur eleifend, ante vitae vestibulum tempus
+
+HTML;
+
+ $this->assertDomStringEqualsDomString($expect, $html);
+ }
+
+ /**
+ * testExtendWithParent
+ *
+ * @return void
+ */
+ public function testExtendWithParent()
+ {
+ $html = $this->instance->render('foo/extend-with-parent');
+
+ $expect = <<
+Lorem ipsum dolor sit amet,
+Vivamus tincidunt consectetur finibus.
+Sed tempor urna quis varius luctus.
+Curabitur eleifend, ante vitae vestibulum tempus
+
+HTML;
+
+ $this->assertDomStringEqualsDomString($expect, $html);
+ }
+
+ /**
+ * testLoad
+ *
+ * @return void
+ */
+ public function testLoad()
+ {
+ $html = $this->instance->render('include1');
+
+ $expect = <<
+
diff --git a/vendor/windwalker/renderer/Test/Tmpl/php/default.php b/vendor/windwalker/renderer/Test/Tmpl/php/default.php
new file mode 100644
index 0000000..b998200
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Tmpl/php/default.php
@@ -0,0 +1,12 @@
+
+
+ Default
+
diff --git a/vendor/windwalker/renderer/Test/Tmpl/php/extend1.php b/vendor/windwalker/renderer/Test/Tmpl/php/extend1.php
new file mode 100644
index 0000000..7d5f138
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Tmpl/php/extend1.php
@@ -0,0 +1,16 @@
+
+
+ Lorem ipsum dolor sit amet,
+ block('sakura'); ?>
+ consectetur adipiscing elit.
+ endBlock(); ?>
+ Curabitur eleifend, ante vitae vestibulum tempus
+
diff --git a/vendor/windwalker/renderer/Test/Tmpl/php/foo/data2.php b/vendor/windwalker/renderer/Test/Tmpl/php/foo/data2.php
new file mode 100644
index 0000000..3d264a0
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Tmpl/php/foo/data2.php
@@ -0,0 +1,11 @@
+
+
+load('foo/data3', ['content' => 'Morbi suscipit ante massa']); ?>
diff --git a/vendor/windwalker/renderer/Test/Tmpl/php/foo/data2_local.php b/vendor/windwalker/renderer/Test/Tmpl/php/foo/data2_local.php
new file mode 100644
index 0000000..665ce1c
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Tmpl/php/foo/data2_local.php
@@ -0,0 +1,12 @@
+
+
+load('foo/data3_local', ['content' => 'Morbi suscipit ante massa']); ?>
diff --git a/vendor/windwalker/renderer/Test/Tmpl/php/foo/data3.php b/vendor/windwalker/renderer/Test/Tmpl/php/foo/data3.php
new file mode 100644
index 0000000..e5a1361
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Tmpl/php/foo/data3.php
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/vendor/windwalker/renderer/Test/Tmpl/php/foo/data3_local.php b/vendor/windwalker/renderer/Test/Tmpl/php/foo/data3_local.php
new file mode 100644
index 0000000..79e69c1
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Tmpl/php/foo/data3_local.php
@@ -0,0 +1,13 @@
+
+
(default) Nulla sed libero sem. Praesent ac dignissim risus.
+
+ {% include 'foo.bar' %}
+{% endblock %}
diff --git a/vendor/windwalker/renderer/Test/Tmpl/twig/ext-test.twig b/vendor/windwalker/renderer/Test/Tmpl/twig/ext-test.twig
new file mode 100644
index 0000000..0d33247
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Tmpl/twig/ext-test.twig
@@ -0,0 +1,7 @@
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
Suspendisse finibus fermentum massa ut tempus. Sed in pulvinar dolor.
+
+
{{ olive }}
+
{{ flower() }}
+
{{ 'Tony Stark' | armor }}
+
diff --git a/vendor/windwalker/renderer/Test/Tmpl/twig/foo/bar.twig b/vendor/windwalker/renderer/Test/Tmpl/twig/foo/bar.twig
new file mode 100644
index 0000000..e8036f5
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Tmpl/twig/foo/bar.twig
@@ -0,0 +1,3 @@
+
+ (foo/bar) Phasellus vitae bibendum neque, quis suscipit urna. Fusce eu odio ante.
+
\ No newline at end of file
diff --git a/vendor/windwalker/renderer/Test/Twig/GlobalContainerTest.php b/vendor/windwalker/renderer/Test/Twig/GlobalContainerTest.php
new file mode 100644
index 0000000..517d413
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/Twig/GlobalContainerTest.php
@@ -0,0 +1,196 @@
+render('ext-test.twig');
+
+ $expect = <<Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
Suspendisse finibus fermentum massa ut tempus. Sed in pulvinar dolor.
+
+
peace
+
sakura
+
Iron Man
+
+HTML;
+
+ $this->assertHtmlFormatEquals($expect, $html);
+
+ GlobalContainer::removeExtension('stub');
+ }
+
+ /**
+ * Method to test getExtension().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::getExtension
+ * @TODO Implement testGetExtension().
+ */
+ public function testGetExtension()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test removeExtension().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::removeExtension
+ * @TODO Implement testRemoveExtension().
+ */
+ public function testRemoveExtension()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getExtensions().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::getExtensions
+ * @TODO Implement testGetExtensions().
+ */
+ public function testGetExtensions()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test setExtensions().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::setExtensions
+ * @TODO Implement testSetExtensions().
+ */
+ public function testSetExtensions()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test addGlobal().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::addGlobal
+ * @TODO Implement testAddGlobal().
+ */
+ public function testAddGlobal()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getGlobal().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::getGlobal
+ * @TODO Implement testGetGlobal().
+ */
+ public function testGetGlobal()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test removeGlobal().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::removeGlobal
+ * @TODO Implement testRemoveGlobal().
+ */
+ public function testRemoveGlobal()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test getGlobals().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::getGlobals
+ * @TODO Implement testGetGlobals().
+ */
+ public function testGetGlobals()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+
+ /**
+ * Method to test setGlobals().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\Twig\GlobalContainer::setGlobals
+ * @TODO Implement testSetGlobals().
+ */
+ public function testSetGlobals()
+ {
+ // Remove the following lines when you implement this test.
+ $this->markTestIncomplete(
+ 'This test has not been implemented yet.'
+ );
+ }
+}
diff --git a/vendor/windwalker/renderer/Test/TwigRendererTest.php b/vendor/windwalker/renderer/Test/TwigRendererTest.php
new file mode 100644
index 0000000..392f5ca
--- /dev/null
+++ b/vendor/windwalker/renderer/Test/TwigRendererTest.php
@@ -0,0 +1,208 @@
+instance = new TwigRenderer(static::$path);
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ *
+ * @return void
+ */
+ protected function tearDown(): void
+ {
+ }
+
+ /**
+ * Method to test render().
+ *
+ * @return void
+ *
+ * @covers \Windwalker\Renderer\TwigRenderer::render
+ */
+ public function testRender()
+ {
+ $html = $this->instance->render('default');
+
+ $expect = <<
+
(_global/global) Lorem ipsum dolor sit amet
+
(default) Nulla sed libero sem. Praesent ac dignissim risus.
+
(foo/bar) Phasellus vitae bibendum neque, quis suscipit urna. Fusce eu odio ante.
+
(_global/global) Suspendisse finibus fermentum massa ut tempus.