+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Formatter;
+
+/**
+ * Formats ICU message patterns.
+ *
+ * @author Nicolas Grekas
+ */
+interface IntlFormatterInterface
+{
+ /**
+ * Formats a localized message using rules defined by ICU MessageFormat.
+ *
+ * @see http://icu-project.org/apiref/icu4c/classMessageFormat.html#details
+ */
+ public function formatIntl(string $message, string $locale, array $parameters = []): string;
+}
diff --git a/vendor/symfony/translation/IdentityTranslator.php b/vendor/symfony/translation/IdentityTranslator.php
new file mode 100644
index 0000000..b15792a
--- /dev/null
+++ b/vendor/symfony/translation/IdentityTranslator.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;
+
+use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
+use Symfony\Contracts\Translation\TranslatorTrait;
+
+/**
+ * IdentityTranslator does not translate anything.
+ *
+ * @author Fabien Potencier
+ */
+class IdentityTranslator implements LegacyTranslatorInterface, TranslatorInterface
+{
+ use TranslatorTrait;
+
+ private $selector;
+
+ /**
+ * @param MessageSelector|null $selector The message selector for pluralization
+ */
+ public function __construct(MessageSelector $selector = null)
+ {
+ $this->selector = $selector;
+
+ if (__CLASS__ !== \get_class($this)) {
+ @trigger_error(sprintf('Calling "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
+ }
+ }
+
+ /**
+ * {@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->selector) {
+ return strtr($this->selector->choose((string) $id, $number, $locale ?: $this->getLocale()), $parameters);
+ }
+
+ return $this->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
+ }
+
+ private function getPluralizationRule(int $number, string $locale): int
+ {
+ return PluralizationRules::get($number, $locale, false);
+ }
+}
diff --git a/vendor/symfony/translation/Interval.php b/vendor/symfony/translation/Interval.php
new file mode 100644
index 0000000..a0e484d
--- /dev/null
+++ b/vendor/symfony/translation/Interval.php
@@ -0,0 +1,112 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2, use IdentityTranslator instead.', Interval::class), E_USER_DEPRECATED);
+
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+
+/**
+ * Tests if a given number belongs to a given math interval.
+ *
+ * An interval can represent a finite set of numbers:
+ *
+ * {1,2,3,4}
+ *
+ * An interval can represent numbers between two numbers:
+ *
+ * [1, +Inf]
+ * ]-1,2[
+ *
+ * The left delimiter can be [ (inclusive) or ] (exclusive).
+ * The right delimiter can be [ (exclusive) or ] (inclusive).
+ * Beside numbers, you can use -Inf and +Inf for the infinite.
+ *
+ * @author Fabien Potencier
+ *
+ * @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
+ * @deprecated since Symfony 4.2, use IdentityTranslator instead
+ */
+class Interval
+{
+ /**
+ * Tests if the given number is in the math interval.
+ *
+ * @param int $number A number
+ * @param string $interval An interval
+ *
+ * @return bool
+ *
+ * @throws InvalidArgumentException
+ */
+ public static function test($number, $interval)
+ {
+ $interval = trim($interval);
+
+ if (!preg_match('/^'.self::getIntervalRegexp().'$/x', $interval, $matches)) {
+ throw new InvalidArgumentException(sprintf('"%s" is not a valid interval.', $interval));
+ }
+
+ if ($matches[1]) {
+ foreach (explode(',', $matches[2]) as $n) {
+ if ($number == $n) {
+ return true;
+ }
+ }
+ } else {
+ $leftNumber = self::convertNumber($matches['left']);
+ $rightNumber = self::convertNumber($matches['right']);
+
+ return
+ ('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
+ && (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
+ ;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a Regexp that matches valid intervals.
+ *
+ * @return string A Regexp (without the delimiters)
+ */
+ public static function getIntervalRegexp()
+ {
+ return <<[\[\]])
+ \s*
+ (?P-Inf|\-?\d+(\.\d+)?)
+ \s*,\s*
+ (?P\+?Inf|\-?\d+(\.\d+)?)
+ \s*
+ (?P[\[\]])
+EOF;
+ }
+
+ private static function convertNumber($number)
+ {
+ if ('-Inf' === $number) {
+ return log(0);
+ } elseif ('+Inf' === $number || 'Inf' === $number) {
+ return -log(0);
+ }
+
+ return (float) $number;
+ }
+}
diff --git a/vendor/symfony/translation/LICENSE b/vendor/symfony/translation/LICENSE
new file mode 100644
index 0000000..a677f43
--- /dev/null
+++ b/vendor/symfony/translation/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2019 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/symfony/translation/Loader/ArrayLoader.php b/vendor/symfony/translation/Loader/ArrayLoader.php
new file mode 100644
index 0000000..0a6f9f0
--- /dev/null
+++ b/vendor/symfony/translation/Loader/ArrayLoader.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\Loader;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * ArrayLoader loads translations from a PHP array.
+ *
+ * @author Fabien Potencier
+ */
+class ArrayLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ $this->flatten($resource);
+ $catalogue = new MessageCatalogue($locale);
+ $catalogue->add($resource, $domain);
+
+ return $catalogue;
+ }
+
+ /**
+ * Flattens an nested array of translations.
+ *
+ * The scheme used is:
+ * 'key' => ['key2' => ['key3' => 'value']]
+ * Becomes:
+ * 'key.key2.key3' => 'value'
+ *
+ * This function takes an array by reference and will modify it
+ *
+ * @param array &$messages The array that will be flattened
+ * @param array $subnode Current subnode being parsed, used internally for recursive calls
+ * @param string $path Current path being parsed, used internally for recursive calls
+ */
+ private function flatten(array &$messages, array $subnode = null, $path = null)
+ {
+ if (null === $subnode) {
+ $subnode = &$messages;
+ }
+ foreach ($subnode as $key => $value) {
+ if (\is_array($value)) {
+ $nodePath = $path ? $path.'.'.$key : $key;
+ $this->flatten($messages, $value, $nodePath);
+ if (null === $path) {
+ unset($messages[$key]);
+ }
+ } elseif (null !== $path) {
+ $messages[$path.'.'.$key] = $value;
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Loader/CsvFileLoader.php b/vendor/symfony/translation/Loader/CsvFileLoader.php
new file mode 100644
index 0000000..db17bd5
--- /dev/null
+++ b/vendor/symfony/translation/Loader/CsvFileLoader.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\Loader;
+
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+
+/**
+ * CsvFileLoader loads translations from CSV files.
+ *
+ * @author Saša Stamenković
+ */
+class CsvFileLoader extends FileLoader
+{
+ private $delimiter = ';';
+ private $enclosure = '"';
+ private $escape = '\\';
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function loadResource($resource)
+ {
+ $messages = [];
+
+ try {
+ $file = new \SplFileObject($resource, 'rb');
+ } catch (\RuntimeException $e) {
+ throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e);
+ }
+
+ $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY);
+ $file->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
+
+ foreach ($file as $data) {
+ if (false === $data) {
+ continue;
+ }
+
+ if ('#' !== substr($data[0], 0, 1) && isset($data[1]) && 2 === \count($data)) {
+ $messages[$data[0]] = $data[1];
+ }
+ }
+
+ return $messages;
+ }
+
+ /**
+ * Sets the delimiter, enclosure, and escape character for CSV.
+ *
+ * @param string $delimiter Delimiter character
+ * @param string $enclosure Enclosure character
+ * @param string $escape Escape character
+ */
+ public function setCsvControl($delimiter = ';', $enclosure = '"', $escape = '\\')
+ {
+ $this->delimiter = $delimiter;
+ $this->enclosure = $enclosure;
+ $this->escape = $escape;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/FileLoader.php b/vendor/symfony/translation/Loader/FileLoader.php
new file mode 100644
index 0000000..7ec54a3
--- /dev/null
+++ b/vendor/symfony/translation/Loader/FileLoader.php
@@ -0,0 +1,65 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+
+/**
+ * @author Abdellatif Ait boudad
+ */
+abstract class FileLoader extends ArrayLoader
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $messages = $this->loadResource($resource);
+
+ // empty resource
+ if (null === $messages) {
+ $messages = [];
+ }
+
+ // not an array
+ if (!\is_array($messages)) {
+ throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource));
+ }
+
+ $catalogue = parent::load($messages, $locale, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+
+ /**
+ * @param string $resource
+ *
+ * @return array
+ *
+ * @throws InvalidResourceException if stream content has an invalid format
+ */
+ abstract protected function loadResource($resource);
+}
diff --git a/vendor/symfony/translation/Loader/IcuDatFileLoader.php b/vendor/symfony/translation/Loader/IcuDatFileLoader.php
new file mode 100644
index 0000000..7bbf4c2
--- /dev/null
+++ b/vendor/symfony/translation/Loader/IcuDatFileLoader.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\Loader;
+
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * IcuResFileLoader loads translations from a resource bundle.
+ *
+ * @author stealth35
+ */
+class IcuDatFileLoader extends IcuResFileLoader
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource.'.dat')) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource.'.dat')) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ try {
+ $rb = new \ResourceBundle($locale, $resource);
+ } catch (\Exception $e) {
+ $rb = null;
+ }
+
+ if (!$rb) {
+ throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
+ } elseif (intl_is_failure($rb->getErrorCode())) {
+ throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
+ }
+
+ $messages = $this->flatten($rb);
+ $catalogue = new MessageCatalogue($locale);
+ $catalogue->add($messages, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource.'.dat'));
+ }
+
+ return $catalogue;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/IcuResFileLoader.php b/vendor/symfony/translation/Loader/IcuResFileLoader.php
new file mode 100644
index 0000000..005f260
--- /dev/null
+++ b/vendor/symfony/translation/Loader/IcuResFileLoader.php
@@ -0,0 +1,91 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Config\Resource\DirectoryResource;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * IcuResFileLoader loads translations from a resource bundle.
+ *
+ * @author stealth35
+ */
+class IcuResFileLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!is_dir($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ try {
+ $rb = new \ResourceBundle($locale, $resource);
+ } catch (\Exception $e) {
+ $rb = null;
+ }
+
+ if (!$rb) {
+ throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
+ } elseif (intl_is_failure($rb->getErrorCode())) {
+ throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
+ }
+
+ $messages = $this->flatten($rb);
+ $catalogue = new MessageCatalogue($locale);
+ $catalogue->add($messages, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\DirectoryResource')) {
+ $catalogue->addResource(new DirectoryResource($resource));
+ }
+
+ return $catalogue;
+ }
+
+ /**
+ * Flattens an ResourceBundle.
+ *
+ * The scheme used is:
+ * key { key2 { key3 { "value" } } }
+ * Becomes:
+ * 'key.key2.key3' => 'value'
+ *
+ * This function takes an array by reference and will modify it
+ *
+ * @param \ResourceBundle $rb The ResourceBundle that will be flattened
+ * @param array $messages Used internally for recursive calls
+ * @param string $path Current path being parsed, used internally for recursive calls
+ *
+ * @return array the flattened ResourceBundle
+ */
+ protected function flatten(\ResourceBundle $rb, array &$messages = [], $path = null)
+ {
+ foreach ($rb as $key => $value) {
+ $nodePath = $path ? $path.'.'.$key : $key;
+ if ($value instanceof \ResourceBundle) {
+ $this->flatten($value, $messages, $nodePath);
+ } else {
+ $messages[$nodePath] = $value;
+ }
+ }
+
+ return $messages;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/IniFileLoader.php b/vendor/symfony/translation/Loader/IniFileLoader.php
new file mode 100644
index 0000000..11d9b27
--- /dev/null
+++ b/vendor/symfony/translation/Loader/IniFileLoader.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+/**
+ * IniFileLoader loads translations from an ini file.
+ *
+ * @author stealth35
+ */
+class IniFileLoader extends FileLoader
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function loadResource($resource)
+ {
+ return parse_ini_file($resource, true);
+ }
+}
diff --git a/vendor/symfony/translation/Loader/JsonFileLoader.php b/vendor/symfony/translation/Loader/JsonFileLoader.php
new file mode 100644
index 0000000..5267212
--- /dev/null
+++ b/vendor/symfony/translation/Loader/JsonFileLoader.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\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+
+/**
+ * JsonFileLoader loads translations from an json file.
+ *
+ * @author singles
+ */
+class JsonFileLoader extends FileLoader
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function loadResource($resource)
+ {
+ $messages = [];
+ if ($data = file_get_contents($resource)) {
+ $messages = json_decode($data, true);
+
+ if (0 < $errorCode = json_last_error()) {
+ throw new InvalidResourceException(sprintf('Error parsing JSON - %s', $this->getJSONErrorMessage($errorCode)));
+ }
+ }
+
+ return $messages;
+ }
+
+ /**
+ * Translates JSON_ERROR_* constant into meaningful message.
+ *
+ * @param int $errorCode Error code returned by json_last_error() call
+ *
+ * @return string Message string
+ */
+ private function getJSONErrorMessage($errorCode)
+ {
+ switch ($errorCode) {
+ case JSON_ERROR_DEPTH:
+ return 'Maximum stack depth exceeded';
+ case JSON_ERROR_STATE_MISMATCH:
+ return 'Underflow or the modes mismatch';
+ case JSON_ERROR_CTRL_CHAR:
+ return 'Unexpected control character found';
+ case JSON_ERROR_SYNTAX:
+ return 'Syntax error, malformed JSON';
+ case JSON_ERROR_UTF8:
+ return 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ default:
+ return 'Unknown error';
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Loader/LoaderInterface.php b/vendor/symfony/translation/Loader/LoaderInterface.php
new file mode 100644
index 0000000..1785402
--- /dev/null
+++ b/vendor/symfony/translation/Loader/LoaderInterface.php
@@ -0,0 +1,38 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * LoaderInterface is the interface implemented by all translation loaders.
+ *
+ * @author Fabien Potencier
+ */
+interface LoaderInterface
+{
+ /**
+ * Loads a locale.
+ *
+ * @param mixed $resource A resource
+ * @param string $locale A locale
+ * @param string $domain The domain
+ *
+ * @return MessageCatalogue A MessageCatalogue instance
+ *
+ * @throws NotFoundResourceException when the resource cannot be found
+ * @throws InvalidResourceException when the resource cannot be loaded
+ */
+ public function load($resource, $locale, $domain = 'messages');
+}
diff --git a/vendor/symfony/translation/Loader/MoFileLoader.php b/vendor/symfony/translation/Loader/MoFileLoader.php
new file mode 100644
index 0000000..d344c6e
--- /dev/null
+++ b/vendor/symfony/translation/Loader/MoFileLoader.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\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+
+/**
+ * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
+ */
+class MoFileLoader extends FileLoader
+{
+ /**
+ * Magic used for validating the format of a MO file as well as
+ * detecting if the machine used to create that file was little endian.
+ */
+ const MO_LITTLE_ENDIAN_MAGIC = 0x950412de;
+
+ /**
+ * Magic used for validating the format of a MO file as well as
+ * detecting if the machine used to create that file was big endian.
+ */
+ const MO_BIG_ENDIAN_MAGIC = 0xde120495;
+
+ /**
+ * The size of the header of a MO file in bytes.
+ */
+ const MO_HEADER_SIZE = 28;
+
+ /**
+ * Parses machine object (MO) format, independent of the machine's endian it
+ * was created on. Both 32bit and 64bit systems are supported.
+ *
+ * {@inheritdoc}
+ */
+ protected function loadResource($resource)
+ {
+ $stream = fopen($resource, 'r');
+
+ $stat = fstat($stream);
+
+ if ($stat['size'] < self::MO_HEADER_SIZE) {
+ throw new InvalidResourceException('MO stream content has an invalid format.');
+ }
+ $magic = unpack('V1', fread($stream, 4));
+ $magic = hexdec(substr(dechex(current($magic)), -8));
+
+ if (self::MO_LITTLE_ENDIAN_MAGIC == $magic) {
+ $isBigEndian = false;
+ } elseif (self::MO_BIG_ENDIAN_MAGIC == $magic) {
+ $isBigEndian = true;
+ } else {
+ throw new InvalidResourceException('MO stream content has an invalid format.');
+ }
+
+ // formatRevision
+ $this->readLong($stream, $isBigEndian);
+ $count = $this->readLong($stream, $isBigEndian);
+ $offsetId = $this->readLong($stream, $isBigEndian);
+ $offsetTranslated = $this->readLong($stream, $isBigEndian);
+ // sizeHashes
+ $this->readLong($stream, $isBigEndian);
+ // offsetHashes
+ $this->readLong($stream, $isBigEndian);
+
+ $messages = [];
+
+ for ($i = 0; $i < $count; ++$i) {
+ $pluralId = null;
+ $translated = null;
+
+ fseek($stream, $offsetId + $i * 8);
+
+ $length = $this->readLong($stream, $isBigEndian);
+ $offset = $this->readLong($stream, $isBigEndian);
+
+ if ($length < 1) {
+ continue;
+ }
+
+ fseek($stream, $offset);
+ $singularId = fread($stream, $length);
+
+ if (false !== strpos($singularId, "\000")) {
+ list($singularId, $pluralId) = explode("\000", $singularId);
+ }
+
+ fseek($stream, $offsetTranslated + $i * 8);
+ $length = $this->readLong($stream, $isBigEndian);
+ $offset = $this->readLong($stream, $isBigEndian);
+
+ if ($length < 1) {
+ continue;
+ }
+
+ fseek($stream, $offset);
+ $translated = fread($stream, $length);
+
+ if (false !== strpos($translated, "\000")) {
+ $translated = explode("\000", $translated);
+ }
+
+ $ids = ['singular' => $singularId, 'plural' => $pluralId];
+ $item = compact('ids', 'translated');
+
+ if (!empty($item['ids']['singular'])) {
+ $id = $item['ids']['singular'];
+ if (isset($item['ids']['plural'])) {
+ $id .= '|'.$item['ids']['plural'];
+ }
+ $messages[$id] = stripcslashes(implode('|', (array) $item['translated']));
+ }
+ }
+
+ fclose($stream);
+
+ return array_filter($messages);
+ }
+
+ /**
+ * Reads an unsigned long from stream respecting endianness.
+ *
+ * @param resource $stream
+ */
+ private function readLong($stream, bool $isBigEndian): int
+ {
+ $result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
+ $result = current($result);
+
+ return (int) substr($result, -8);
+ }
+}
diff --git a/vendor/symfony/translation/Loader/PhpFileLoader.php b/vendor/symfony/translation/Loader/PhpFileLoader.php
new file mode 100644
index 0000000..a0050e8
--- /dev/null
+++ b/vendor/symfony/translation/Loader/PhpFileLoader.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+/**
+ * PhpFileLoader loads translations from PHP files returning an array of translations.
+ *
+ * @author Fabien Potencier
+ */
+class PhpFileLoader extends FileLoader
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function loadResource($resource)
+ {
+ return require $resource;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/PoFileLoader.php b/vendor/symfony/translation/Loader/PoFileLoader.php
new file mode 100644
index 0000000..5e460fb
--- /dev/null
+++ b/vendor/symfony/translation/Loader/PoFileLoader.php
@@ -0,0 +1,149 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+/**
+ * @copyright Copyright (c) 2010, Union of RAD https://github.com/UnionOfRAD/lithium
+ * @copyright Copyright (c) 2012, Clemens Tolboom
+ */
+class PoFileLoader extends FileLoader
+{
+ /**
+ * Parses portable object (PO) format.
+ *
+ * From https://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
+ * we should be able to parse files having:
+ *
+ * white-space
+ * # translator-comments
+ * #. extracted-comments
+ * #: reference...
+ * #, flag...
+ * #| msgid previous-untranslated-string
+ * msgid untranslated-string
+ * msgstr translated-string
+ *
+ * extra or different lines are:
+ *
+ * #| msgctxt previous-context
+ * #| msgid previous-untranslated-string
+ * msgctxt context
+ *
+ * #| msgid previous-untranslated-string-singular
+ * #| msgid_plural previous-untranslated-string-plural
+ * msgid untranslated-string-singular
+ * msgid_plural untranslated-string-plural
+ * msgstr[0] translated-string-case-0
+ * ...
+ * msgstr[N] translated-string-case-n
+ *
+ * The definition states:
+ * - white-space and comments are optional.
+ * - msgid "" that an empty singleline defines a header.
+ *
+ * This parser sacrifices some features of the reference implementation the
+ * differences to that implementation are as follows.
+ * - No support for comments spanning multiple lines.
+ * - Translator and extracted comments are treated as being the same type.
+ * - Message IDs are allowed to have other encodings as just US-ASCII.
+ *
+ * Items with an empty id are ignored.
+ *
+ * {@inheritdoc}
+ */
+ protected function loadResource($resource)
+ {
+ $stream = fopen($resource, 'r');
+
+ $defaults = [
+ 'ids' => [],
+ 'translated' => null,
+ ];
+
+ $messages = [];
+ $item = $defaults;
+ $flags = [];
+
+ while ($line = fgets($stream)) {
+ $line = trim($line);
+
+ if ('' === $line) {
+ // Whitespace indicated current item is done
+ if (!\in_array('fuzzy', $flags)) {
+ $this->addMessage($messages, $item);
+ }
+ $item = $defaults;
+ $flags = [];
+ } elseif ('#,' === substr($line, 0, 2)) {
+ $flags = array_map('trim', explode(',', substr($line, 2)));
+ } elseif ('msgid "' === substr($line, 0, 7)) {
+ // We start a new msg so save previous
+ // TODO: this fails when comments or contexts are added
+ $this->addMessage($messages, $item);
+ $item = $defaults;
+ $item['ids']['singular'] = substr($line, 7, -1);
+ } elseif ('msgstr "' === substr($line, 0, 8)) {
+ $item['translated'] = substr($line, 8, -1);
+ } elseif ('"' === $line[0]) {
+ $continues = isset($item['translated']) ? 'translated' : 'ids';
+
+ if (\is_array($item[$continues])) {
+ end($item[$continues]);
+ $item[$continues][key($item[$continues])] .= substr($line, 1, -1);
+ } else {
+ $item[$continues] .= substr($line, 1, -1);
+ }
+ } elseif ('msgid_plural "' === substr($line, 0, 14)) {
+ $item['ids']['plural'] = substr($line, 14, -1);
+ } elseif ('msgstr[' === substr($line, 0, 7)) {
+ $size = strpos($line, ']');
+ $item['translated'][(int) substr($line, 7, 1)] = substr($line, $size + 3, -1);
+ }
+ }
+ // save last item
+ if (!\in_array('fuzzy', $flags)) {
+ $this->addMessage($messages, $item);
+ }
+ fclose($stream);
+
+ return $messages;
+ }
+
+ /**
+ * Save a translation item to the messages.
+ *
+ * A .po file could contain by error missing plural indexes. We need to
+ * fix these before saving them.
+ */
+ private function addMessage(array &$messages, array $item)
+ {
+ if (!empty($item['ids']['singular'])) {
+ $id = stripcslashes($item['ids']['singular']);
+ if (isset($item['ids']['plural'])) {
+ $id .= '|'.stripcslashes($item['ids']['plural']);
+ }
+
+ $translated = (array) $item['translated'];
+ // PO are by definition indexed so sort by index.
+ ksort($translated);
+ // Make sure every index is filled.
+ end($translated);
+ $count = key($translated);
+ // Fill missing spots with '-'.
+ $empties = array_fill(0, $count + 1, '-');
+ $translated += $empties;
+ ksort($translated);
+
+ $messages[$id] = stripcslashes(implode('|', $translated));
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Loader/QtFileLoader.php b/vendor/symfony/translation/Loader/QtFileLoader.php
new file mode 100644
index 0000000..2d4a4c0
--- /dev/null
+++ b/vendor/symfony/translation/Loader/QtFileLoader.php
@@ -0,0 +1,77 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Config\Util\XmlUtils;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * QtFileLoader loads translations from QT Translations XML files.
+ *
+ * @author Benjamin Eberlei
+ */
+class QtFileLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ try {
+ $dom = XmlUtils::loadFile($resource);
+ } catch (\InvalidArgumentException $e) {
+ throw new InvalidResourceException(sprintf('Unable to load "%s".', $resource), $e->getCode(), $e);
+ }
+
+ $internalErrors = libxml_use_internal_errors(true);
+ libxml_clear_errors();
+
+ $xpath = new \DOMXPath($dom);
+ $nodes = $xpath->evaluate('//TS/context/name[text()="'.$domain.'"]');
+
+ $catalogue = new MessageCatalogue($locale);
+ if (1 == $nodes->length) {
+ $translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message');
+ foreach ($translations as $translation) {
+ $translationValue = (string) $translation->getElementsByTagName('translation')->item(0)->nodeValue;
+
+ if (!empty($translationValue)) {
+ $catalogue->set(
+ (string) $translation->getElementsByTagName('source')->item(0)->nodeValue,
+ $translationValue,
+ $domain
+ );
+ }
+ $translation = $translation->nextSibling;
+ }
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+ }
+
+ libxml_use_internal_errors($internalErrors);
+
+ return $catalogue;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/XliffFileLoader.php b/vendor/symfony/translation/Loader/XliffFileLoader.php
new file mode 100644
index 0000000..6e01a71
--- /dev/null
+++ b/vendor/symfony/translation/Loader/XliffFileLoader.php
@@ -0,0 +1,212 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Config\Util\XmlUtils;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\Util\XliffUtils;
+
+/**
+ * XliffFileLoader loads translations from XLIFF files.
+ *
+ * @author Fabien Potencier
+ */
+class XliffFileLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $catalogue = new MessageCatalogue($locale);
+ $this->extract($resource, $catalogue, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+
+ private function extract($resource, MessageCatalogue $catalogue, $domain)
+ {
+ try {
+ $dom = XmlUtils::loadFile($resource);
+ } catch (\InvalidArgumentException $e) {
+ throw new InvalidResourceException(sprintf('Unable to load "%s": %s', $resource, $e->getMessage()), $e->getCode(), $e);
+ }
+
+ $xliffVersion = XliffUtils::getVersionNumber($dom);
+ if ($errors = XliffUtils::validateSchema($dom)) {
+ throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: %s', $resource, XliffUtils::getErrorsAsString($errors)));
+ }
+
+ if ('1.2' === $xliffVersion) {
+ $this->extractXliff1($dom, $catalogue, $domain);
+ }
+
+ if ('2.0' === $xliffVersion) {
+ $this->extractXliff2($dom, $catalogue, $domain);
+ }
+ }
+
+ /**
+ * Extract messages and metadata from DOMDocument into a MessageCatalogue.
+ *
+ * @param \DOMDocument $dom Source to extract messages and metadata
+ * @param MessageCatalogue $catalogue Catalogue where we'll collect messages and metadata
+ * @param string $domain The domain
+ */
+ private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
+ {
+ $xml = simplexml_import_dom($dom);
+ $encoding = strtoupper($dom->encoding);
+
+ $namespace = 'urn:oasis:names:tc:xliff:document:1.2';
+ $xml->registerXPathNamespace('xliff', $namespace);
+
+ foreach ($xml->xpath('//xliff:file') as $file) {
+ $fileAttributes = $file->attributes();
+
+ $file->registerXPathNamespace('xliff', $namespace);
+
+ foreach ($file->xpath('.//xliff:trans-unit') as $translation) {
+ $attributes = $translation->attributes();
+
+ if (!(isset($attributes['resname']) || isset($translation->source))) {
+ continue;
+ }
+
+ $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;
+ // If the xlf file has another encoding specified, try to convert it because
+ // simple_xml will always return utf-8 encoded values
+ $target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding);
+
+ $catalogue->set((string) $source, $target, $domain);
+
+ $metadata = [
+ 'source' => (string) $translation->source,
+ 'file' => [
+ 'original' => (string) $fileAttributes['original'],
+ ],
+ ];
+ if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) {
+ $metadata['notes'] = $notes;
+ }
+
+ if (isset($translation->target) && $translation->target->attributes()) {
+ $metadata['target-attributes'] = [];
+ foreach ($translation->target->attributes() as $key => $value) {
+ $metadata['target-attributes'][$key] = (string) $value;
+ }
+ }
+
+ if (isset($attributes['id'])) {
+ $metadata['id'] = (string) $attributes['id'];
+ }
+
+ $catalogue->setMetadata((string) $source, $metadata, $domain);
+ }
+ }
+ }
+
+ private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
+ {
+ $xml = simplexml_import_dom($dom);
+ $encoding = strtoupper($dom->encoding);
+
+ $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0');
+
+ foreach ($xml->xpath('//xliff:unit') as $unit) {
+ foreach ($unit->segment as $segment) {
+ $source = $segment->source;
+
+ // If the xlf file has another encoding specified, try to convert it because
+ // simple_xml will always return utf-8 encoded values
+ $target = $this->utf8ToCharset((string) (isset($segment->target) ? $segment->target : $source), $encoding);
+
+ $catalogue->set((string) $source, $target, $domain);
+
+ $metadata = [];
+ if (isset($segment->target) && $segment->target->attributes()) {
+ $metadata['target-attributes'] = [];
+ foreach ($segment->target->attributes() as $key => $value) {
+ $metadata['target-attributes'][$key] = (string) $value;
+ }
+ }
+
+ if (isset($unit->notes)) {
+ $metadata['notes'] = [];
+ foreach ($unit->notes->note as $noteNode) {
+ $note = [];
+ foreach ($noteNode->attributes() as $key => $value) {
+ $note[$key] = (string) $value;
+ }
+ $note['content'] = (string) $noteNode;
+ $metadata['notes'][] = $note;
+ }
+ }
+
+ $catalogue->setMetadata((string) $source, $metadata, $domain);
+ }
+ }
+ }
+
+ /**
+ * Convert a UTF8 string to the specified encoding.
+ */
+ private function utf8ToCharset(string $content, string $encoding = null): string
+ {
+ if ('UTF-8' !== $encoding && !empty($encoding)) {
+ return mb_convert_encoding($content, $encoding, 'UTF-8');
+ }
+
+ return $content;
+ }
+
+ private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, string $encoding = null): array
+ {
+ $notes = [];
+
+ if (null === $noteElement) {
+ return $notes;
+ }
+
+ /** @var \SimpleXMLElement $xmlNote */
+ foreach ($noteElement as $xmlNote) {
+ $noteAttributes = $xmlNote->attributes();
+ $note = ['content' => $this->utf8ToCharset((string) $xmlNote, $encoding)];
+ if (isset($noteAttributes['priority'])) {
+ $note['priority'] = (int) $noteAttributes['priority'];
+ }
+
+ if (isset($noteAttributes['from'])) {
+ $note['from'] = (string) $noteAttributes['from'];
+ }
+
+ $notes[] = $note;
+ }
+
+ return $notes;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/YamlFileLoader.php b/vendor/symfony/translation/Loader/YamlFileLoader.php
new file mode 100644
index 0000000..438d7d7
--- /dev/null
+++ b/vendor/symfony/translation/Loader/YamlFileLoader.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\LogicException;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Parser as YamlParser;
+use Symfony\Component\Yaml\Yaml;
+
+/**
+ * YamlFileLoader loads translations from Yaml files.
+ *
+ * @author Fabien Potencier
+ */
+class YamlFileLoader extends FileLoader
+{
+ private $yamlParser;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function loadResource($resource)
+ {
+ if (null === $this->yamlParser) {
+ if (!class_exists('Symfony\Component\Yaml\Parser')) {
+ throw new LogicException('Loading translations from the YAML format requires the Symfony Yaml component.');
+ }
+
+ $this->yamlParser = new YamlParser();
+ }
+
+ try {
+ $messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT);
+ } catch (ParseException $e) {
+ throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $resource), 0, $e);
+ }
+
+ if (null !== $messages && !\is_array($messages)) {
+ throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource));
+ }
+
+ return $messages ?: [];
+ }
+}
diff --git a/vendor/symfony/translation/LoggingTranslator.php b/vendor/symfony/translation/LoggingTranslator.php
new file mode 100644
index 0000000..bcad1ce
--- /dev/null
+++ b/vendor/symfony/translation/LoggingTranslator.php
@@ -0,0 +1,156 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+use Psr\Log\LoggerInterface;
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface;
+use Symfony\Contracts\Translation\LocaleAwareInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+/**
+ * @author Abdellatif Ait boudad
+ */
+class LoggingTranslator implements TranslatorInterface, LegacyTranslatorInterface, TranslatorBagInterface
+{
+ /**
+ * @var TranslatorInterface|TranslatorBagInterface
+ */
+ private $translator;
+
+ private $logger;
+
+ /**
+ * @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
+ */
+ public function __construct($translator, LoggerInterface $logger)
+ {
+ if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
+ throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
+ }
+ if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) {
+ throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', \get_class($translator)));
+ }
+
+ $this->translator = $translator;
+ $this->logger = $logger;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function trans($id, array $parameters = [], $domain = null, $locale = null)
+ {
+ $trans = $this->translator->trans($id, $parameters, $domain, $locale);
+ $this->log($id, $domain, $locale);
+
+ return $trans;
+ }
+
+ /**
+ * {@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->translator instanceof TranslatorInterface) {
+ $trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale);
+ } else {
+ $trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
+ }
+
+ $this->log($id, $domain, $locale);
+
+ return $trans;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setLocale($locale)
+ {
+ $prev = $this->translator->getLocale();
+ $this->translator->setLocale($locale);
+ if ($prev === $locale) {
+ return;
+ }
+
+ $this->logger->debug(sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLocale()
+ {
+ return $this->translator->getLocale();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCatalogue($locale = null)
+ {
+ return $this->translator->getCatalogue($locale);
+ }
+
+ /**
+ * Gets the fallback locales.
+ *
+ * @return array The fallback locales
+ */
+ public function getFallbackLocales()
+ {
+ if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) {
+ return $this->translator->getFallbackLocales();
+ }
+
+ return [];
+ }
+
+ /**
+ * Passes through all unknown calls onto the translator object.
+ */
+ public function __call($method, $args)
+ {
+ return $this->translator->{$method}(...$args);
+ }
+
+ /**
+ * Logs for missing translations.
+ *
+ * @param string $id
+ * @param string|null $domain
+ * @param string|null $locale
+ */
+ private function log($id, $domain, $locale)
+ {
+ if (null === $domain) {
+ $domain = 'messages';
+ }
+
+ $id = (string) $id;
+ $catalogue = $this->translator->getCatalogue($locale);
+ if ($catalogue->defines($id, $domain)) {
+ return;
+ }
+
+ if ($catalogue->has($id, $domain)) {
+ $this->logger->debug('Translation use fallback catalogue.', ['id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()]);
+ } else {
+ $this->logger->warning('Translation not found.', ['id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()]);
+ }
+ }
+}
diff --git a/vendor/symfony/translation/MessageCatalogue.php b/vendor/symfony/translation/MessageCatalogue.php
new file mode 100644
index 0000000..1dc50ea
--- /dev/null
+++ b/vendor/symfony/translation/MessageCatalogue.php
@@ -0,0 +1,303 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+use Symfony\Component\Config\Resource\ResourceInterface;
+use Symfony\Component\Translation\Exception\LogicException;
+
+/**
+ * @author Fabien Potencier
+ */
+class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface
+{
+ private $messages = [];
+ private $metadata = [];
+ private $resources = [];
+ private $locale;
+ private $fallbackCatalogue;
+ private $parent;
+
+ /**
+ * @param string $locale The locale
+ * @param array $messages An array of messages classified by domain
+ */
+ public function __construct(?string $locale, array $messages = [])
+ {
+ $this->locale = $locale;
+ $this->messages = $messages;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLocale()
+ {
+ return $this->locale;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDomains()
+ {
+ $domains = [];
+ $suffixLength = \strlen(self::INTL_DOMAIN_SUFFIX);
+
+ foreach ($this->messages as $domain => $messages) {
+ if (\strlen($domain) > $suffixLength && false !== $i = strpos($domain, self::INTL_DOMAIN_SUFFIX, -$suffixLength)) {
+ $domain = substr($domain, 0, $i);
+ }
+ $domains[$domain] = $domain;
+ }
+
+ return array_values($domains);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function all($domain = null)
+ {
+ if (null !== $domain) {
+ return ($this->messages[$domain.self::INTL_DOMAIN_SUFFIX] ?? []) + ($this->messages[$domain] ?? []);
+ }
+
+ $allMessages = [];
+ $suffixLength = \strlen(self::INTL_DOMAIN_SUFFIX);
+
+ foreach ($this->messages as $domain => $messages) {
+ if (\strlen($domain) > $suffixLength && false !== $i = strpos($domain, self::INTL_DOMAIN_SUFFIX, -$suffixLength)) {
+ $domain = substr($domain, 0, $i);
+ $allMessages[$domain] = $messages + ($allMessages[$domain] ?? []);
+ } else {
+ $allMessages[$domain] = ($allMessages[$domain] ?? []) + $messages;
+ }
+ }
+
+ return $allMessages;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($id, $translation, $domain = 'messages')
+ {
+ $this->add([$id => $translation], $domain);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($id, $domain = 'messages')
+ {
+ if (isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {
+ return true;
+ }
+
+ if (null !== $this->fallbackCatalogue) {
+ return $this->fallbackCatalogue->has($id, $domain);
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function defines($id, $domain = 'messages')
+ {
+ return isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($id, $domain = 'messages')
+ {
+ if (isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {
+ return $this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id];
+ }
+
+ if (isset($this->messages[$domain][$id])) {
+ return $this->messages[$domain][$id];
+ }
+
+ if (null !== $this->fallbackCatalogue) {
+ return $this->fallbackCatalogue->get($id, $domain);
+ }
+
+ return $id;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function replace($messages, $domain = 'messages')
+ {
+ unset($this->messages[$domain], $this->messages[$domain.self::INTL_DOMAIN_SUFFIX]);
+
+ $this->add($messages, $domain);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add($messages, $domain = 'messages')
+ {
+ if (!isset($this->messages[$domain])) {
+ $this->messages[$domain] = $messages;
+ } else {
+ $this->messages[$domain] = array_replace($this->messages[$domain], $messages);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addCatalogue(MessageCatalogueInterface $catalogue)
+ {
+ if ($catalogue->getLocale() !== $this->locale) {
+ throw new LogicException(sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s"', $catalogue->getLocale(), $this->locale));
+ }
+
+ foreach ($catalogue->all() as $domain => $messages) {
+ if ($intlMessages = $catalogue->all($domain.self::INTL_DOMAIN_SUFFIX)) {
+ $this->add($intlMessages, $domain.self::INTL_DOMAIN_SUFFIX);
+ $messages = array_diff_key($messages, $intlMessages);
+ }
+ $this->add($messages, $domain);
+ }
+
+ foreach ($catalogue->getResources() as $resource) {
+ $this->addResource($resource);
+ }
+
+ if ($catalogue instanceof MetadataAwareInterface) {
+ $metadata = $catalogue->getMetadata('', '');
+ $this->addMetadata($metadata);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addFallbackCatalogue(MessageCatalogueInterface $catalogue)
+ {
+ // detect circular references
+ $c = $catalogue;
+ while ($c = $c->getFallbackCatalogue()) {
+ if ($c->getLocale() === $this->getLocale()) {
+ throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
+ }
+ }
+
+ $c = $this;
+ do {
+ if ($c->getLocale() === $catalogue->getLocale()) {
+ throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale()));
+ }
+
+ foreach ($catalogue->getResources() as $resource) {
+ $c->addResource($resource);
+ }
+ } while ($c = $c->parent);
+
+ $catalogue->parent = $this;
+ $this->fallbackCatalogue = $catalogue;
+
+ foreach ($catalogue->getResources() as $resource) {
+ $this->addResource($resource);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFallbackCatalogue()
+ {
+ return $this->fallbackCatalogue;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResources()
+ {
+ return array_values($this->resources);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addResource(ResourceInterface $resource)
+ {
+ $this->resources[$resource->__toString()] = $resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMetadata($key = '', $domain = 'messages')
+ {
+ if ('' == $domain) {
+ return $this->metadata;
+ }
+
+ if (isset($this->metadata[$domain])) {
+ if ('' == $key) {
+ return $this->metadata[$domain];
+ }
+
+ if (isset($this->metadata[$domain][$key])) {
+ return $this->metadata[$domain][$key];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setMetadata($key, $value, $domain = 'messages')
+ {
+ $this->metadata[$domain][$key] = $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteMetadata($key = '', $domain = 'messages')
+ {
+ if ('' == $domain) {
+ $this->metadata = [];
+ } elseif ('' == $key) {
+ unset($this->metadata[$domain]);
+ } else {
+ unset($this->metadata[$domain][$key]);
+ }
+ }
+
+ /**
+ * Adds current values with the new values.
+ *
+ * @param array $values Values to add
+ */
+ private function addMetadata(array $values)
+ {
+ foreach ($values as $domain => $keys) {
+ foreach ($keys as $key => $value) {
+ $this->setMetadata($key, $value, $domain);
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/translation/MessageCatalogueInterface.php b/vendor/symfony/translation/MessageCatalogueInterface.php
new file mode 100644
index 0000000..f3d3f5e
--- /dev/null
+++ b/vendor/symfony/translation/MessageCatalogueInterface.php
@@ -0,0 +1,138 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+use Symfony\Component\Config\Resource\ResourceInterface;
+
+/**
+ * MessageCatalogueInterface.
+ *
+ * @author Fabien Potencier
+ */
+interface MessageCatalogueInterface
+{
+ const INTL_DOMAIN_SUFFIX = '+intl-icu';
+
+ /**
+ * Gets the catalogue locale.
+ *
+ * @return string The locale
+ */
+ public function getLocale();
+
+ /**
+ * Gets the domains.
+ *
+ * @return array An array of domains
+ */
+ public function getDomains();
+
+ /**
+ * Gets the messages within a given domain.
+ *
+ * If $domain is null, it returns all messages.
+ *
+ * @param string $domain The domain name
+ *
+ * @return array An array of messages
+ */
+ public function all($domain = null);
+
+ /**
+ * Sets a message translation.
+ *
+ * @param string $id The message id
+ * @param string $translation The messages translation
+ * @param string $domain The domain name
+ */
+ public function set($id, $translation, $domain = 'messages');
+
+ /**
+ * Checks if a message has a translation.
+ *
+ * @param string $id The message id
+ * @param string $domain The domain name
+ *
+ * @return bool true if the message has a translation, false otherwise
+ */
+ public function has($id, $domain = 'messages');
+
+ /**
+ * Checks if a message has a translation (it does not take into account the fallback mechanism).
+ *
+ * @param string $id The message id
+ * @param string $domain The domain name
+ *
+ * @return bool true if the message has a translation, false otherwise
+ */
+ public function defines($id, $domain = 'messages');
+
+ /**
+ * Gets a message translation.
+ *
+ * @param string $id The message id
+ * @param string $domain The domain name
+ *
+ * @return string The message translation
+ */
+ public function get($id, $domain = 'messages');
+
+ /**
+ * Sets translations for a given domain.
+ *
+ * @param array $messages An array of translations
+ * @param string $domain The domain name
+ */
+ public function replace($messages, $domain = 'messages');
+
+ /**
+ * Adds translations for a given domain.
+ *
+ * @param array $messages An array of translations
+ * @param string $domain The domain name
+ */
+ public function add($messages, $domain = 'messages');
+
+ /**
+ * Merges translations from the given Catalogue into the current one.
+ *
+ * The two catalogues must have the same locale.
+ */
+ public function addCatalogue(self $catalogue);
+
+ /**
+ * Merges translations from the given Catalogue into the current one
+ * only when the translation does not exist.
+ *
+ * This is used to provide default translations when they do not exist for the current locale.
+ */
+ public function addFallbackCatalogue(self $catalogue);
+
+ /**
+ * Gets the fallback catalogue.
+ *
+ * @return self|null A MessageCatalogueInterface instance or null when no fallback has been set
+ */
+ public function getFallbackCatalogue();
+
+ /**
+ * Returns an array of resources loaded to build this collection.
+ *
+ * @return ResourceInterface[] An array of resources
+ */
+ public function getResources();
+
+ /**
+ * Adds a resource for this collection.
+ */
+ public function addResource(ResourceInterface $resource);
+}
diff --git a/vendor/symfony/translation/MessageSelector.php b/vendor/symfony/translation/MessageSelector.php
new file mode 100644
index 0000000..0f0febb
--- /dev/null
+++ b/vendor/symfony/translation/MessageSelector.php
@@ -0,0 +1,98 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2, use IdentityTranslator instead.', MessageSelector::class), E_USER_DEPRECATED);
+
+use Symfony\Component\Translation\Exception\InvalidArgumentException;
+
+/**
+ * MessageSelector.
+ *
+ * @author Fabien Potencier
+ * @author Bernhard Schussek
+ *
+ * @deprecated since Symfony 4.2, use IdentityTranslator instead.
+ */
+class MessageSelector
+{
+ /**
+ * Given a message with different plural translations separated by a
+ * pipe (|), this method returns the correct portion of the message based
+ * on the given number, locale and the pluralization rules in the message
+ * itself.
+ *
+ * The message supports two different types of pluralization rules:
+ *
+ * interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples
+ * indexed: There is one apple|There are %count% apples
+ *
+ * The indexed solution can also contain labels (e.g. one: There is one apple).
+ * This is purely for making the translations more clear - it does not
+ * affect the functionality.
+ *
+ * The two methods can also be mixed:
+ * {0} There are no apples|one: There is one apple|more: There are %count% apples
+ *
+ * @param string $message The message being translated
+ * @param int|float $number The number of items represented for the message
+ * @param string $locale The locale to use for choosing
+ *
+ * @return string
+ *
+ * @throws InvalidArgumentException
+ */
+ public function choose($message, $number, $locale)
+ {
+ $parts = [];
+ if (preg_match('/^\|++$/', $message)) {
+ $parts = explode('|', $message);
+ } elseif (preg_match_all('/(?:\|\||[^\|])++/', $message, $matches)) {
+ $parts = $matches[0];
+ }
+
+ $explicitRules = [];
+ $standardRules = [];
+ foreach ($parts as $part) {
+ $part = trim(str_replace('||', '|', $part));
+
+ if (preg_match('/^(?P'.Interval::getIntervalRegexp().')\s*(?P.*?)$/xs', $part, $matches)) {
+ $explicitRules[$matches['interval']] = $matches['message'];
+ } elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) {
+ $standardRules[] = $matches[1];
+ } else {
+ $standardRules[] = $part;
+ }
+ }
+
+ // try to match an explicit rule, then fallback to the standard ones
+ foreach ($explicitRules as $interval => $m) {
+ if (Interval::test($number, $interval)) {
+ return $m;
+ }
+ }
+
+ $position = PluralizationRules::get($number, $locale);
+
+ if (!isset($standardRules[$position])) {
+ // when there's exactly one rule given, and that rule is a standard
+ // rule, use this rule
+ if (1 === \count($parts) && isset($standardRules[0])) {
+ return $standardRules[0];
+ }
+
+ throw new InvalidArgumentException(sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $message, $locale, $number));
+ }
+
+ return $standardRules[$position];
+ }
+}
diff --git a/vendor/symfony/translation/MetadataAwareInterface.php b/vendor/symfony/translation/MetadataAwareInterface.php
new file mode 100644
index 0000000..e93c6fb
--- /dev/null
+++ b/vendor/symfony/translation/MetadataAwareInterface.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+/**
+ * MetadataAwareInterface.
+ *
+ * @author Fabien Potencier
+ */
+interface MetadataAwareInterface
+{
+ /**
+ * Gets metadata for the given domain and key.
+ *
+ * Passing an empty domain will return an array with all metadata indexed by
+ * domain and then by key. Passing an empty key will return an array with all
+ * metadata for the given domain.
+ *
+ * @param string $key The key
+ * @param string $domain The domain name
+ *
+ * @return mixed The value that was set or an array with the domains/keys or null
+ */
+ public function getMetadata($key = '', $domain = 'messages');
+
+ /**
+ * Adds metadata to a message domain.
+ *
+ * @param string $key The key
+ * @param mixed $value The value
+ * @param string $domain The domain name
+ */
+ public function setMetadata($key, $value, $domain = 'messages');
+
+ /**
+ * Deletes metadata for the given key and domain.
+ *
+ * Passing an empty domain will delete all metadata. Passing an empty key will
+ * delete all metadata for the given domain.
+ *
+ * @param string $key The key
+ * @param string $domain The domain name
+ */
+ public function deleteMetadata($key = '', $domain = 'messages');
+}
diff --git a/vendor/symfony/translation/PluralizationRules.php b/vendor/symfony/translation/PluralizationRules.php
new file mode 100644
index 0000000..77c2760
--- /dev/null
+++ b/vendor/symfony/translation/PluralizationRules.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;
+
+/**
+ * Returns the plural rules for a given locale.
+ *
+ * @author Fabien Potencier
+ *
+ * @deprecated since Symfony 4.2, use IdentityTranslator instead
+ */
+class PluralizationRules
+{
+ private static $rules = [];
+
+ /**
+ * Returns the plural position to use for the given locale and number.
+ *
+ * @param int $number The number
+ * @param string $locale The locale
+ *
+ * @return int The plural position
+ */
+ public static function get($number, $locale/*, bool $triggerDeprecation = true*/)
+ {
+ if (3 > \func_num_args() || func_get_arg(2)) {
+ @trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED);
+ }
+
+ if ('pt_BR' === $locale) {
+ // temporary set a locale for brazilian
+ $locale = 'xbr';
+ }
+
+ if (\strlen($locale) > 3) {
+ $locale = substr($locale, 0, -\strlen(strrchr($locale, '_')));
+ }
+
+ if (isset(self::$rules[$locale])) {
+ $return = self::$rules[$locale]($number);
+
+ if (!\is_int($return) || $return < 0) {
+ return 0;
+ }
+
+ return $return;
+ }
+
+ /*
+ * The plural rules are derived from code of the Zend Framework (2010-09-25),
+ * which is subject to the new BSD license (http://framework.zend.com/license/new-bsd).
+ * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ */
+ switch ($locale) {
+ case 'az':
+ case 'bo':
+ case 'dz':
+ case 'id':
+ case 'ja':
+ case 'jv':
+ case 'ka':
+ case 'km':
+ case 'kn':
+ case 'ko':
+ case 'ms':
+ case 'th':
+ case 'tr':
+ case 'vi':
+ case 'zh':
+ return 0;
+
+ case 'af':
+ case 'bn':
+ case 'bg':
+ case 'ca':
+ case 'da':
+ case 'de':
+ case 'el':
+ case 'en':
+ case 'eo':
+ case 'es':
+ case 'et':
+ case 'eu':
+ case 'fa':
+ case 'fi':
+ case 'fo':
+ case 'fur':
+ case 'fy':
+ case 'gl':
+ case 'gu':
+ case 'ha':
+ case 'he':
+ case 'hu':
+ case 'is':
+ case 'it':
+ case 'ku':
+ case 'lb':
+ case 'ml':
+ case 'mn':
+ case 'mr':
+ case 'nah':
+ case 'nb':
+ case 'ne':
+ case 'nl':
+ case 'nn':
+ case 'no':
+ case 'oc':
+ case 'om':
+ case 'or':
+ case 'pa':
+ case 'pap':
+ case 'ps':
+ case 'pt':
+ case 'so':
+ case 'sq':
+ case 'sv':
+ case 'sw':
+ case 'ta':
+ case 'te':
+ case 'tk':
+ case 'ur':
+ case 'zu':
+ return (1 == $number) ? 0 : 1;
+
+ case 'am':
+ case 'bh':
+ case 'fil':
+ case 'fr':
+ case 'gun':
+ case 'hi':
+ case 'hy':
+ case 'ln':
+ case 'mg':
+ case 'nso':
+ case 'xbr':
+ case 'ti':
+ case 'wa':
+ return ((0 == $number) || (1 == $number)) ? 0 : 1;
+
+ case 'be':
+ case 'bs':
+ case 'hr':
+ case 'ru':
+ case 'sh':
+ case 'sr':
+ case 'uk':
+ return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
+
+ case 'cs':
+ case 'sk':
+ return (1 == $number) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2);
+
+ case 'ga':
+ return (1 == $number) ? 0 : ((2 == $number) ? 1 : 2);
+
+ case 'lt':
+ return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
+
+ case 'sl':
+ return (1 == $number % 100) ? 0 : ((2 == $number % 100) ? 1 : (((3 == $number % 100) || (4 == $number % 100)) ? 2 : 3));
+
+ case 'mk':
+ return (1 == $number % 10) ? 0 : 1;
+
+ case 'mt':
+ return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3));
+
+ case 'lv':
+ return (0 == $number) ? 0 : (((1 == $number % 10) && (11 != $number % 100)) ? 1 : 2);
+
+ case 'pl':
+ return (1 == $number) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2);
+
+ case 'cy':
+ return (1 == $number) ? 0 : ((2 == $number) ? 1 : (((8 == $number) || (11 == $number)) ? 2 : 3));
+
+ case 'ro':
+ return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2);
+
+ case 'ar':
+ return (0 == $number) ? 0 : ((1 == $number) ? 1 : ((2 == $number) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5))));
+
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * Overrides the default plural rule for a given locale.
+ *
+ * @param callable $rule A PHP callable
+ * @param string $locale The locale
+ */
+ public static function set(callable $rule, $locale)
+ {
+ @trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED);
+
+ if ('pt_BR' === $locale) {
+ // temporary set a locale for brazilian
+ $locale = 'xbr';
+ }
+
+ if (\strlen($locale) > 3) {
+ $locale = substr($locale, 0, -\strlen(strrchr($locale, '_')));
+ }
+
+ self::$rules[$locale] = $rule;
+ }
+}
diff --git a/vendor/symfony/translation/README.md b/vendor/symfony/translation/README.md
new file mode 100644
index 0000000..46f3d1f
--- /dev/null
+++ b/vendor/symfony/translation/README.md
@@ -0,0 +1,13 @@
+Translation Component
+=====================
+
+The Translation component provides tools to internationalize your application.
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/translation/index.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/vendor/symfony/translation/Reader/TranslationReader.php b/vendor/symfony/translation/Reader/TranslationReader.php
new file mode 100644
index 0000000..2b98345
--- /dev/null
+++ b/vendor/symfony/translation/Reader/TranslationReader.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\Reader;
+
+use Symfony\Component\Finder\Finder;
+use Symfony\Component\Translation\Loader\LoaderInterface;
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * TranslationReader reads translation messages from translation files.
+ *
+ * @author Michel Salib
+ */
+class TranslationReader implements TranslationReaderInterface
+{
+ /**
+ * Loaders used for import.
+ *
+ * @var array
+ */
+ private $loaders = [];
+
+ /**
+ * Adds a loader to the translation extractor.
+ *
+ * @param string $format The format of the loader
+ */
+ public function addLoader($format, LoaderInterface $loader)
+ {
+ $this->loaders[$format] = $loader;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($directory, MessageCatalogue $catalogue)
+ {
+ if (!is_dir($directory)) {
+ return;
+ }
+
+ foreach ($this->loaders as $format => $loader) {
+ // load any existing translation files
+ $finder = new Finder();
+ $extension = $catalogue->getLocale().'.'.$format;
+ $files = $finder->files()->name('*.'.$extension)->in($directory);
+ foreach ($files as $file) {
+ $domain = substr($file->getFilename(), 0, -1 * \strlen($extension) - 1);
+ $catalogue->addCatalogue($loader->load($file->getPathname(), $catalogue->getLocale(), $domain));
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Reader/TranslationReaderInterface.php b/vendor/symfony/translation/Reader/TranslationReaderInterface.php
new file mode 100644
index 0000000..0b2ad33
--- /dev/null
+++ b/vendor/symfony/translation/Reader/TranslationReaderInterface.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\Reader;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * TranslationReader reads translation messages from translation files.
+ *
+ * @author Tobias Nyholm
+ */
+interface TranslationReaderInterface
+{
+ /**
+ * Reads translation messages from a directory to the catalogue.
+ *
+ * @param string $directory
+ */
+ public function read($directory, MessageCatalogue $catalogue);
+}
diff --git a/vendor/symfony/translation/Resources/bin/translation-status.php b/vendor/symfony/translation/Resources/bin/translation-status.php
new file mode 100644
index 0000000..44918c9
--- /dev/null
+++ b/vendor/symfony/translation/Resources/bin/translation-status.php
@@ -0,0 +1,207 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+$usageInstructions = << false,
+ // NULL = analyze all locales
+ 'locale_to_analyze' => null,
+ // the reference files all the other translations are compared to
+ 'original_files' => [
+ 'src/Symfony/Component/Form/Resources/translations/validators.en.xlf',
+ 'src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf',
+ 'src/Symfony/Component/Validator/Resources/translations/validators.en.xlf',
+ ],
+];
+
+$argc = $_SERVER['argc'];
+$argv = $_SERVER['argv'];
+
+if ($argc > 3) {
+ echo str_replace('translation-status.php', $argv[0], $usageInstructions);
+ exit(1);
+}
+
+foreach (array_slice($argv, 1) as $argumentOrOption) {
+ if (0 === strpos($argumentOrOption, '-')) {
+ $config['verbose_output'] = true;
+ } else {
+ $config['locale_to_analyze'] = $argumentOrOption;
+ }
+}
+
+foreach ($config['original_files'] as $originalFilePath) {
+ if (!file_exists($originalFilePath)) {
+ echo sprintf('The following file does not exist. Make sure that you execute this command at the root dir of the Symfony code repository.%s %s', PHP_EOL, $originalFilePath);
+ exit(1);
+ }
+}
+
+$totalMissingTranslations = 0;
+
+foreach ($config['original_files'] as $originalFilePath) {
+ $translationFilePaths = findTranslationFiles($originalFilePath, $config['locale_to_analyze']);
+ $translationStatus = calculateTranslationStatus($originalFilePath, $translationFilePaths);
+
+ $totalMissingTranslations += array_sum(array_map(function ($translation) {
+ return count($translation['missingKeys']);
+ }, array_values($translationStatus)));
+
+ printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output']);
+}
+
+exit($totalMissingTranslations > 0 ? 1 : 0);
+
+function findTranslationFiles($originalFilePath, $localeToAnalyze)
+{
+ $translations = [];
+
+ $translationsDir = dirname($originalFilePath);
+ $originalFileName = basename($originalFilePath);
+ $translationFileNamePattern = str_replace('.en.', '.*.', $originalFileName);
+
+ $translationFiles = glob($translationsDir.'/'.$translationFileNamePattern, GLOB_NOSORT);
+ sort($translationFiles);
+ foreach ($translationFiles as $filePath) {
+ $locale = extractLocaleFromFilePath($filePath);
+
+ if (null !== $localeToAnalyze && $locale !== $localeToAnalyze) {
+ continue;
+ }
+
+ $translations[$locale] = $filePath;
+ }
+
+ return $translations;
+}
+
+function calculateTranslationStatus($originalFilePath, $translationFilePaths)
+{
+ $translationStatus = [];
+ $allTranslationKeys = extractTranslationKeys($originalFilePath);
+
+ foreach ($translationFilePaths as $locale => $translationPath) {
+ $translatedKeys = extractTranslationKeys($translationPath);
+ $missingKeys = array_diff_key($allTranslationKeys, $translatedKeys);
+
+ $translationStatus[$locale] = [
+ 'total' => count($allTranslationKeys),
+ 'translated' => count($translatedKeys),
+ 'missingKeys' => $missingKeys,
+ ];
+ }
+
+ return $translationStatus;
+}
+
+function printTranslationStatus($originalFilePath, $translationStatus, $verboseOutput)
+{
+ printTitle($originalFilePath);
+ printTable($translationStatus, $verboseOutput);
+ echo PHP_EOL.PHP_EOL;
+}
+
+function extractLocaleFromFilePath($filePath)
+{
+ $parts = explode('.', $filePath);
+
+ return $parts[count($parts) - 2];
+}
+
+function extractTranslationKeys($filePath)
+{
+ $translationKeys = [];
+ $contents = new \SimpleXMLElement(file_get_contents($filePath));
+
+ foreach ($contents->file->body->{'trans-unit'} as $translationKey) {
+ $translationId = (string) $translationKey['id'];
+ $translationKey = (string) $translationKey->source;
+
+ $translationKeys[$translationId] = $translationKey;
+ }
+
+ return $translationKeys;
+}
+
+function printTitle($title)
+{
+ echo $title.PHP_EOL;
+ echo str_repeat('=', strlen($title)).PHP_EOL.PHP_EOL;
+}
+
+function printTable($translations, $verboseOutput)
+{
+ if (0 === count($translations)) {
+ echo 'No translations found';
+
+ return;
+ }
+ $longestLocaleNameLength = max(array_map('strlen', array_keys($translations)));
+
+ foreach ($translations as $locale => $translation) {
+ if ($translation['translated'] > $translation['total']) {
+ textColorRed();
+ } elseif ($translation['translated'] === $translation['total']) {
+ textColorGreen();
+ }
+
+ echo sprintf('| Locale: %-'.$longestLocaleNameLength.'s | Translated: %d/%d', $locale, $translation['translated'], $translation['total']).PHP_EOL;
+
+ textColorNormal();
+
+ if (true === $verboseOutput && count($translation['missingKeys']) > 0) {
+ echo str_repeat('-', 80).PHP_EOL;
+ echo '| Missing Translations:'.PHP_EOL;
+
+ foreach ($translation['missingKeys'] as $id => $content) {
+ echo sprintf('| (id=%s) %s', $id, $content).PHP_EOL;
+ }
+
+ echo str_repeat('-', 80).PHP_EOL;
+ }
+ }
+}
+
+function textColorGreen()
+{
+ echo "\033[32m";
+}
+
+function textColorRed()
+{
+ echo "\033[31m";
+}
+
+function textColorNormal()
+{
+ echo "\033[0m";
+}
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..a951d34
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Command/XliffLintCommandTest.php
@@ -0,0 +1,205 @@
+
+ *
+ * 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->assertStringContainsString('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->assertStringContainsString('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->assertStringContainsString($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->assertStringContainsString('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->assertStringContainsString('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->assertStringContainsString('[OK] All 1 XLIFF files contain valid syntax.', trim($tester->getDisplay()));
+ }
+
+ public function testLintFileNotReadable()
+ {
+ $this->expectException('RuntimeException');
+ $tester = $this->createCommandTester();
+ $filename = $this->createFile();
+ unlink($filename);
+
+ $tester->execute(['filename' => $filename], ['decorated' => false]);
+ }
+
+ public function testGetHelp()
+ {
+ $command = new XliffLintCommand();
+ $expected = <<php %command.full_name% dirname
+ php %command.full_name% dirname --format=json
+
+EOF;
+
+ $this->assertStringContainsString($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(): void
+ {
+ $this->files = [];
+ @mkdir(sys_get_temp_dir().'/translation-xliff-lint-test');
+ }
+
+ protected function tearDown(): void
+ {
+ 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..1a600c8
--- /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(): void
+ {
+ 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..d3de1e2
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DataCollectorTranslatorTest.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;
+
+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',
+ 'fallbackLocale' => null,
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_DEFINED,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ];
+ $expectedMessages[] = [
+ 'id' => 'bar',
+ 'translation' => 'bar (fr)',
+ 'locale' => 'en',
+ 'fallbackLocale' => 'fr',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ];
+ $expectedMessages[] = [
+ 'id' => 'choice',
+ 'translation' => 'choice',
+ 'locale' => 'en',
+ 'fallbackLocale' => null,
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_MISSING,
+ 'parameters' => ['%count%' => 0],
+ 'transChoiceNumber' => 0,
+ ];
+ $expectedMessages[] = [
+ 'id' => 'bar_ru',
+ 'translation' => 'bar (ru)',
+ 'locale' => 'en',
+ 'fallbackLocale' => 'ru',
+ 'domain' => 'messages',
+ 'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
+ 'parameters' => [],
+ 'transChoiceNumber' => null,
+ ];
+ $expectedMessages[] = [
+ 'id' => 'bar_ru',
+ 'translation' => 'bar (ru)',
+ 'locale' => 'en',
+ 'fallbackLocale' => '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',
+ 'fallbackLocale' => null,
+ '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..113536b
--- /dev/null
+++ b/vendor/symfony/translation/Tests/DependencyInjection/TranslationExtractorPassTest.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\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());
+ }
+
+ public function testProcessMissingAlias()
+ {
+ $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
+ $this->expectExceptionMessage('The alias for the tag "translation.extractor" of service "foo.id" must be set.');
+ $container = new ContainerBuilder();
+ $container->register('translation.extractor');
+ $container->register('foo.id')
+ ->addTag('translation.extractor', []);
+
+ $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..37d982c
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Formatter/IntlFormatterTest.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\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..a630a7a
--- /dev/null
+++ b/vendor/symfony/translation/Tests/IdentityTranslatorTest.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;
+
+use Symfony\Component\Translation\IdentityTranslator;
+use Symfony\Contracts\Translation\Test\TranslatorTest;
+
+class IdentityTranslatorTest extends TranslatorTest
+{
+ private $defaultLocale;
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->defaultLocale = \Locale::getDefault();
+ }
+
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+
+ \Locale::setDefault($this->defaultLocale);
+ }
+
+ 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..ea3e4d8
--- /dev/null
+++ b/vendor/symfony/translation/Tests/IntervalTest.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;
+
+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));
+ }
+
+ public function testTestException()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidArgumentException');
+ 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..9537e1f
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/CsvFileLoaderTest.php
@@ -0,0 +1,57 @@
+
+ *
+ * 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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $loader = new CsvFileLoader();
+ $resource = __DIR__.'/../fixtures/not-exists.csv';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadNonLocalResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $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..77db041
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/IcuDatFileLoaderTest.php
@@ -0,0 +1,60 @@
+
+ *
+ * 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
+{
+ public function testLoadInvalidResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $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..99b2f90
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/IcuResFileLoaderTest.php
@@ -0,0 +1,47 @@
+
+ *
+ * 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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $loader = new IcuResFileLoader();
+ $loader->load(__DIR__.'/../fixtures/non-existing.txt', 'en', 'domain1');
+ }
+
+ public function testLoadInvalidResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $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..fd66e20
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/IniFileLoaderTest.php
@@ -0,0 +1,49 @@
+
+ *
+ * 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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $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..d264bb1
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/JsonFileLoaderTest.php
@@ -0,0 +1,58 @@
+
+ *
+ * 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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $loader = new JsonFileLoader();
+ $resource = __DIR__.'/../fixtures/non-existing.json';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testParseException()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $this->expectExceptionMessage('Error parsing JSON - Syntax error, malformed JSON');
+ $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..b4a4a12
--- /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(): void
+ {
+ 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..3fe3a99
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/MoFileLoaderTest.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\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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $loader = new MoFileLoader();
+ $resource = __DIR__.'/../fixtures/non-existing.mo';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadInvalidResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $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..d4da645
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/PhpFileLoaderTest.php
@@ -0,0 +1,46 @@
+
+ *
+ * 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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $loader = new PhpFileLoader();
+ $resource = __DIR__.'/../fixtures/non-existing.php';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadThrowsAnExceptionIfFileNotLocal()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $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..72c4c66
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/PoFileLoaderTest.php
@@ -0,0 +1,120 @@
+
+ *
+ * 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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $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..95981c7
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/QtFileLoaderTest.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\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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $loader = new QtFileLoader();
+ $resource = __DIR__.'/../fixtures/non-existing.ts';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadNonLocalResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $loader = new QtFileLoader();
+ $resource = 'http://domain1.com/resources.ts';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadInvalidResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $loader = new QtFileLoader();
+ $resource = __DIR__.'/../fixtures/invalid-xml-resources.xlf';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadEmptyResource()
+ {
+ $loader = new QtFileLoader();
+ $resource = __DIR__.'/../fixtures/empty.xlf';
+
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $this->expectExceptionMessage(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..79e51f1
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/XliffFileLoaderTest.php
@@ -0,0 +1,317 @@
+
+ *
+ * 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']);
+ }
+
+ public function testLoadInvalidResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $loader = new XliffFileLoader();
+ $loader->load(__DIR__.'/../fixtures/resources.php', 'en', 'domain1');
+ }
+
+ public function testLoadResourceDoesNotValidate()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $loader = new XliffFileLoader();
+ $loader->load(__DIR__.'/../fixtures/non-valid.xlf', 'en', 'domain1');
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $loader = new XliffFileLoader();
+ $resource = __DIR__.'/../fixtures/non-existing.xlf';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadThrowsAnExceptionIfFileNotLocal()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $loader = new XliffFileLoader();
+ $resource = 'http://example.com/resources.xlf';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testDocTypeIsNotAllowed()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $this->expectExceptionMessage('Document types are not allowed.');
+ $loader = new XliffFileLoader();
+ $loader->load(__DIR__.'/../fixtures/withdoctype.xlf', 'en', 'domain1');
+ }
+
+ public function testParseEmptyFile()
+ {
+ $loader = new XliffFileLoader();
+ $resource = __DIR__.'/../fixtures/empty.xlf';
+
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $this->expectExceptionMessage(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..b46fff7
--- /dev/null
+++ b/vendor/symfony/translation/Tests/Loader/YamlFileLoaderTest.php
@@ -0,0 +1,65 @@
+
+ *
+ * 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());
+ }
+
+ public function testLoadNonExistingResource()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $loader = new YamlFileLoader();
+ $resource = __DIR__.'/../fixtures/non-existing.yml';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadThrowsAnExceptionIfFileNotLocal()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $loader = new YamlFileLoader();
+ $resource = 'http://example.com/resources.yml';
+ $loader->load($resource, 'en', 'domain1');
+ }
+
+ public function testLoadThrowsAnExceptionIfNotAnArray()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidResourceException');
+ $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..34f2604
--- /dev/null
+++ b/vendor/symfony/translation/Tests/MessageCatalogueTest.php
@@ -0,0 +1,237 @@
+
+ *
+ * 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());
+ }
+
+ public function testAddFallbackCatalogueWithParentCircularReference()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\LogicException');
+ $main = new MessageCatalogue('en_US');
+ $fallback = new MessageCatalogue('fr_FR');
+
+ $fallback->addFallbackCatalogue($main);
+ $main->addFallbackCatalogue($fallback);
+ }
+
+ public function testAddFallbackCatalogueWithFallbackCircularReference()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\LogicException');
+ $fr = new MessageCatalogue('fr');
+ $en = new MessageCatalogue('en');
+ $es = new MessageCatalogue('es');
+
+ $fr->addFallbackCatalogue($en);
+ $es->addFallbackCatalogue($en);
+ $en->addFallbackCatalogue($fr);
+ }
+
+ public function testAddCatalogueWhenLocaleIsNotTheSameAsTheCurrentOne()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\LogicException');
+ $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..20609dd
--- /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
+ */
+ public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number)
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidArgumentException');
+ $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..ae5c75b
--- /dev/null
+++ b/vendor/symfony/translation/Tests/TranslatorCacheTest.php
@@ -0,0 +1,335 @@
+
+ *
+ * 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\MockObject\MockObject;
+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(): void
+ {
+ $this->tmpDir = sys_get_temp_dir().'/sf_translation';
+ $this->deleteTmpDir();
+ }
+
+ protected function tearDown(): void
+ {
+ $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|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');
+ }
+
+ public function testCachedCatalogueIsReDumpedWhenCacheVaryChange()
+ {
+ $translator = new Translator('a', null, $this->tmpDir, false, []);
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'bar'], 'a', 'messages');
+
+ // Cached catalogue is dumped
+ $this->assertSame('bar', $translator->trans('foo', [], 'messages', 'a'));
+
+ $translator = new Translator('a', null, $this->tmpDir, false, ['vary']);
+ $translator->addLoader('array', new ArrayLoader());
+ $translator->addResource('array', ['foo' => 'ccc'], 'a', 'messages');
+
+ $this->assertSame('ccc', $translator->trans('foo', [], 'messages', 'a'));
+ }
+
+ 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..bfb1faa
--- /dev/null
+++ b/vendor/symfony/translation/Tests/TranslatorTest.php
@@ -0,0 +1,610 @@
+
+ *
+ * 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
+ */
+ public function testConstructorInvalidLocale($locale)
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidArgumentException');
+ 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
+ */
+ public function testSetInvalidLocale($locale)
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidArgumentException');
+ $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
+ */
+ public function testSetFallbackInvalidLocales($locale)
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidArgumentException');
+ $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
+ */
+ public function testAddResourceInvalidLocales($locale)
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidArgumentException');
+ $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
+ */
+ public function testTransWithoutFallbackLocaleFile($format, $loader)
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\NotFoundResourceException');
+ $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'));
+ }
+
+ public function testWhenAResourceHasNoRegisteredLoader()
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\RuntimeException');
+ $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
+ */
+ public function testTransInvalidLocale($locale)
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidArgumentException');
+ $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
+ * @group legacy
+ */
+ public function testTransChoiceInvalidLocale($locale)
+ {
+ $this->expectException('Symfony\Component\Translation\Exception\InvalidArgumentException');
+ $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..d9241d5
--- /dev/null
+++ b/vendor/symfony/translation/Translator.php
@@ -0,0 +1,513 @@
+
+ *
+ * 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;
+
+ private $cacheVary;
+
+ /**
+ * @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, array $cacheVary = [])
+ {
+ $this->setLocale($locale);
+
+ if (null === $formatter) {
+ $formatter = new MessageFormatter();
+ }
+
+ $this->formatter = $formatter;
+ $this->cacheDir = $cacheDir;
+ $this->debug = $debug;
+ $this->cacheVary = $cacheVary;
+ $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 = $this->cacheVary['fallback_locales'] = $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->cacheVary), 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..4cd0ee0
--- /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.6"
+ },
+ "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/version.php b/version.php
index 1d2bbc4..578fc07 100644
--- a/version.php
+++ b/version.php
@@ -17,16 +17,16 @@
/**
* Version information for mfavatar block
*
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @package block_mfavatar
- * @copyright 2015 MoodleFreak.com
+ * @copyright 2015 MFreak.nl
* @author Luuk Verhoeven
**/
-defined('MOODLE_INTERNAL') || die();
-$plugin->release = '1.1.0';
+defined('MOODLE_INTERNAL') || die;
+$plugin->release = '3.8.0';
$plugin->maturity = MATURITY_STABLE;
-$plugin->version = 2017020800; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2013101800; // Requires this Moodle version
-$plugin->component = 'block_mfavatar'; // Full name of the plugin (used for diagnostics)
\ No newline at end of file
+$plugin->version = 2019111400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2018051700; // Requires this Moodle 3.5 version.
+$plugin->component = 'block_mfavatar'; // Full name of the plugin (used for diagnostics).
diff --git a/view.php b/view/view.php
similarity index 73%
rename from view.php
rename to view/view.php
index c7b5017..ee25a53 100644
--- a/view.php
+++ b/view/view.php
@@ -15,33 +15,34 @@
// along with Moodle. If not, see .
/**
- * snapshot view page
+ * Snapshot maker
*
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @package block_mfavatar
- * @copyright 2015 MoodleFreak.com
+ * @copyright 2015 MFreak.nl
* @author Luuk Verhoeven
**/
-require_once(dirname(__FILE__) . '/../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
+require_once(dirname(__FILE__) . '/../../../config.php');
+defined('MOODLE_INTERNAL') || die;
+
require_login();
-$courseid = required_param('courseid', PARAM_INT); // if no courseid is given
-$parentcourse = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+$courseid = required_param('courseid', PARAM_INT);
+$parentcourse = $DB->get_record('course', ['id' => $courseid], '*', MUST_EXIST);
$context = context_course::instance($courseid);
$PAGE->set_course($parentcourse);
-$PAGE->set_url('/blocks/mfavatar/view.php');
+$PAGE->set_url('/blocks/mfavatar/view/view.php');
$PAGE->set_heading($SITE->fullname);
$PAGE->set_pagelayout('incourse');
$PAGE->set_title(get_string('snapshotpage', 'block_mfavatar'));
$PAGE->navbar->add(get_string('snapshotpage', 'block_mfavatar'));
$PAGE->requires->css('/blocks/mfavatar/styles.css');
-block_mfavatar_add_javascript_module();
-
+/** @var block_mfavatar_renderer $renderer **/
$renderer = $PAGE->get_renderer('block_mfavatar');
+$renderer->add_javascript_module();
echo $OUTPUT->header();