[
  {
    "path": ".gitattributes",
    "content": "/Tests export-ignore\n/phpunit.xml.dist export-ignore\n/.git* export-ignore\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "Please do not submit any Pull Requests here. They will be closed.\n---\n\nPlease submit your PR here instead:\nhttps://github.com/symfony/symfony\n\nThis repository is what we call a \"subtree split\": a read-only subset of that main repository.\nWe're looking forward to your PR there!\n"
  },
  {
    "path": ".github/workflows/close-pull-request.yml",
    "content": "name: Close Pull Request\n\non:\n  pull_request_target:\n    types: [opened]\n\njobs:\n  run:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: superbrothers/close-pull-request@v3\n      with:\n        comment: |\n          Thanks for your Pull Request! We love contributions.\n\n          However, you should instead open your PR on the main repository:\n          https://github.com/symfony/symfony\n\n          This repository is what we call a \"subtree split\": a read-only subset of that main repository.\n          We're looking forward to your PR there!\n"
  },
  {
    "path": ".gitignore",
    "content": "vendor/\ncomposer.lock\nphpunit.xml\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\n8.1\n---\n\n * Add support for XLIFF 2.1 and 2.2\n * Add support for XLIFF 2.2 PGS (Plural, Gender, and Select Module)\n * Add `LocaleFallbackProvider`\n\n8.0\n---\n\n * Remove the `$escape` parameter from `CsvFileLoader::setCsvControl()`\n * Make `DataCollectorTranslator` class `final`\n * Remove `ProviderFactoryTestCase`, extend `AbstractProviderFactoryTestCase` instead\n * Remove `TranslatableMessage::__toString()` method, use `trans()` or `getMessage()` instead\n\n7.4\n---\n\n * Make the extractor alias optional\n * Deprecate `TranslatableMessage::__toString`\n * Add `Symfony\\Component\\Translation\\StaticMessage`\n\n7.3\n---\n\n * Add `Translator::addGlobalParameter()` to allow defining global translation parameters\n\n7.2\n---\n\n * Deprecate `ProviderFactoryTestCase`, extend `AbstractProviderFactoryTestCase` instead\n\n   The `testIncompleteDsnException()` test is no longer provided by default. If you make use of it by implementing the `incompleteDsnProvider()` data providers,\n   you now need to use the `IncompleteDsnTestTrait`.\n\n * Make `ProviderFactoryTestCase` and `ProviderTestCase` compatible with PHPUnit 10+\n * Add `lint:translations` command\n * Deprecate passing an escape character to `CsvFileLoader::setCsvControl()`\n * Make Xliff 2.0 attributes in segment element available as `segment-attributes`\n   metadata returned by `XliffFileLoader` and make `XliffFileDumper` write them to the file\n\n7.1\n---\n\n * Mark class `DataCollectorTranslator` as `final`\n\n7.0\n---\n\n * Remove `PhpStringTokenParser`\n * Remove `PhpExtractor` in favor of `PhpAstExtractor`\n\n6.4\n---\n\n * Give current locale to `LocaleSwitcher::runWithLocale()`'s callback\n * Add `--as-tree` option to `translation:pull` command to write YAML messages as a tree-like structure\n * [BC BREAK] Add argument `$buildDir` to `DataCollectorTranslator::warmUp()`\n * Add `DataCollectorTranslatorPass` and `LoggingTranslatorPass`  (moved from `FrameworkBundle`)\n * Add `PhraseTranslationProvider`\n\n6.2.7\n-----\n\n * [BC BREAK] The following data providers for `ProviderFactoryTestCase` are now static:\n   `supportsProvider()`, `createProvider()`, `unsupportedSchemeProvider()`and `incompleteDsnProvider()`\n * [BC BREAK] `ProviderTestCase::toStringProvider()` is now static\n\n6.2\n---\n\n * Deprecate `PhpStringTokenParser`\n * Deprecate `PhpExtractor` in favor of `PhpAstExtractor`\n * Add `PhpAstExtractor` (requires [nikic/php-parser](https://github.com/nikic/php-parser) to be installed)\n\n6.1\n---\n\n * Parameters implementing `TranslatableInterface` are processed\n * Add the file extension to the `XliffFileDumper` constructor\n\n5.4\n---\n\n * Add `github` format & autodetection to render errors as annotations when\n   running the XLIFF linter command in a Github Actions environment.\n * Translation providers are not experimental anymore\n\n5.3\n---\n\n * Add `translation:pull` and `translation:push` commands to manage translations with third-party providers\n * Add `TranslatorBagInterface::getCatalogues` method\n * Add support to load XLIFF string in `XliffFileLoader`\n\n5.2.0\n-----\n\n * added support for calling `trans` with ICU formatted messages\n * added `PseudoLocalizationTranslator`\n * added `TranslatableMessage` objects that represent a message that can be translated\n * added the `t()` function to easily create `TranslatableMessage` objects\n * Added support for extracting messages from `TranslatableMessage` objects\n\n5.1.0\n-----\n\n * added support for `name` attribute on `unit` element from xliff2 to be used as a translation key instead of always the `source` element\n\n5.0.0\n-----\n\n * removed support for using `null` as the locale in `Translator`\n * removed `TranslatorInterface`\n * removed `MessageSelector`\n * removed `ChoiceMessageFormatterInterface`\n * removed `PluralizationRule`\n * removed `Interval`\n * removed `transChoice()` methods, use the trans() method instead with a %count% parameter\n * removed `FileDumper::setBackup()` and `TranslationWriter::disableBackup()`\n * removed `MessageFormatter::choiceFormat()`\n * added argument `$filename` to `PhpExtractor::parseTokens()`\n * removed support for implicit STDIN usage in the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit.\n\n4.4.0\n-----\n\n * deprecated support for using `null` as the locale in `Translator`\n * deprecated accepting STDIN implicitly when using the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit.\n * Marked the `TranslationDataCollector` class as `@final`.\n\n4.3.0\n-----\n\n * Improved Xliff 1.2 loader to load the original file's metadata\n * Added `TranslatorPathsPass`\n\n4.2.0\n-----\n\n * Started using ICU parent locales as fallback locales.\n * allow using the ICU message format using domains with the \"+intl-icu\" suffix\n * deprecated `Translator::transChoice()` in favor of using `Translator::trans()` with a `%count%` parameter\n * deprecated `TranslatorInterface` in favor of `Symfony\\Contracts\\Translation\\TranslatorInterface`\n * deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead\n * Added `IntlFormatter` and `IntlFormatterInterface`\n * added support for multiple files and directories in `XliffLintCommand`\n * Marked `Translator::getFallbackLocales()` and `TranslationDataCollector::getFallbackLocales()` as internal\n\n4.1.0\n-----\n\n * The `FileDumper::setBackup()` method is deprecated.\n * The `TranslationWriter::disableBackup()` method is deprecated.\n * The `XliffFileDumper` will write \"name\" on the \"unit\" node when dumping XLIFF 2.0.\n\n4.0.0\n-----\n\n * removed the backup feature of the `FileDumper` class\n * removed `TranslationWriter::writeTranslations()` method\n * removed support for passing `MessageSelector` instances to the constructor of the `Translator` class\n\n3.4.0\n-----\n\n * Added `TranslationDumperPass`\n * Added `TranslationExtractorPass`\n * Added `TranslatorPass`\n * Added `TranslationReader` and `TranslationReaderInterface`\n * Added `<notes>` section to the Xliff 2.0 dumper.\n * Improved Xliff 2.0 loader to load `<notes>` section.\n * Added `TranslationWriterInterface`\n * Deprecated `TranslationWriter::writeTranslations` in favor of `TranslationWriter::write`\n * added support for adding custom message formatter and decoupling the default one.\n * Added `PhpExtractor`\n * Added `PhpStringTokenParser`\n\n3.2.0\n-----\n\n * Added support for escaping `|` in plural translations with double pipe.\n\n3.1.0\n-----\n\n * Deprecated the backup feature of the file dumper classes.\n\n3.0.0\n-----\n\n * removed `FileDumper::format()` method.\n * Changed the visibility of the locale property in `Translator` from protected to private.\n\n2.8.0\n-----\n\n * deprecated FileDumper::format(), overwrite FileDumper::formatCatalogue() instead.\n * deprecated Translator::getMessages(), rely on TranslatorBagInterface::getCatalogue() instead.\n * added `FileDumper::formatCatalogue` which allows format the catalogue without dumping it into file.\n * added option `json_encoding` to JsonFileDumper\n * added options `as_tree`, `inline` to YamlFileDumper\n * added support for XLIFF 2.0.\n * added support for XLIFF target and tool attributes.\n * added message parameters to DataCollectorTranslator.\n * [DEPRECATION] The `DiffOperation` class has been deprecated and\n   will be removed in Symfony 3.0, since its operation has nothing to do with 'diff',\n   so the class name is misleading. The `TargetOperation` class should be used for\n   this use-case instead.\n\n2.7.0\n-----\n\n * added DataCollectorTranslator for collecting the translated messages.\n\n2.6.0\n-----\n\n * added possibility to cache catalogues\n * added TranslatorBagInterface\n * added LoggingTranslator\n * added Translator::getMessages() for retrieving the message catalogue as an array\n\n2.5.0\n-----\n\n * added relative file path template to the file dumpers\n * added optional backup to the file dumpers\n * changed IcuResFileDumper to extend FileDumper\n\n2.3.0\n-----\n\n * added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues)\n * added Translator::getFallbackLocales()\n * deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method\n\n2.2.0\n-----\n\n * QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3.\n * [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now\n   throws Symfony\\Component\\Translation\\Exception\\NotFoundResourceException when a resource cannot be found\n   and Symfony\\Component\\Translation\\Exception\\InvalidResourceException when a resource is invalid.\n * changed the exception class thrown by some load() methods from \\RuntimeException to \\InvalidArgumentException\n   (IcuDatFileLoader, IcuResFileLoader and QtFileLoader)\n\n2.1.0\n-----\n\n * added support for more than one fallback locale\n * added support for extracting translation messages from templates (Twig and PHP)\n * added dumpers for translation catalogs\n * added support for QT, gettext, and ResourceBundles\n"
  },
  {
    "path": "Catalogue/AbstractOperation.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Catalogue;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\n/**\n * Base catalogues binary operation class.\n *\n * A catalogue binary operation performs operation on\n * source (the left argument) and target (the right argument) catalogues.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n */\nabstract class AbstractOperation implements OperationInterface\n{\n    public const OBSOLETE_BATCH = 'obsolete';\n    public const NEW_BATCH = 'new';\n    public const ALL_BATCH = 'all';\n\n    protected MessageCatalogue $result;\n\n    /**\n     * This array stores 'all', 'new' and 'obsolete' messages for all valid domains.\n     *\n     * The data structure of this array is as follows:\n     *\n     *     [\n     *         'domain 1' => [\n     *             'all' => [...],\n     *             'new' => [...],\n     *             'obsolete' => [...]\n     *         ],\n     *         'domain 2' => [\n     *             'all' => [...],\n     *             'new' => [...],\n     *             'obsolete' => [...]\n     *         ],\n     *         ...\n     *     ]\n     *\n     * @var array The array that stores 'all', 'new' and 'obsolete' messages\n     */\n    protected array $messages;\n\n    private array $domains;\n\n    /**\n     * @throws LogicException\n     */\n    public function __construct(\n        protected MessageCatalogueInterface $source,\n        protected MessageCatalogueInterface $target,\n    ) {\n        if ($source->getLocale() !== $target->getLocale()) {\n            throw new LogicException('Operated catalogues must belong to the same locale.');\n        }\n\n        $this->result = new MessageCatalogue($source->getLocale());\n        $this->messages = [];\n    }\n\n    public function getDomains(): array\n    {\n        if (!isset($this->domains)) {\n            $domains = [];\n            foreach ([$this->source, $this->target] as $catalogue) {\n                foreach ($catalogue->getDomains() as $domain) {\n                    $domains[$domain] = $domain;\n\n                    if ($catalogue->all($domainIcu = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX)) {\n                        $domains[$domainIcu] = $domainIcu;\n                    }\n                }\n            }\n\n            $this->domains = array_values($domains);\n        }\n\n        return $this->domains;\n    }\n\n    public function getMessages(string $domain): array\n    {\n        if (!\\in_array($domain, $this->getDomains(), true)) {\n            throw new InvalidArgumentException(\\sprintf('Invalid domain: \"%s\".', $domain));\n        }\n\n        if (!isset($this->messages[$domain][self::ALL_BATCH])) {\n            $this->processDomain($domain);\n        }\n\n        return $this->messages[$domain][self::ALL_BATCH];\n    }\n\n    public function getNewMessages(string $domain): array\n    {\n        if (!\\in_array($domain, $this->getDomains(), true)) {\n            throw new InvalidArgumentException(\\sprintf('Invalid domain: \"%s\".', $domain));\n        }\n\n        if (!isset($this->messages[$domain][self::NEW_BATCH])) {\n            $this->processDomain($domain);\n        }\n\n        return $this->messages[$domain][self::NEW_BATCH];\n    }\n\n    public function getObsoleteMessages(string $domain): array\n    {\n        if (!\\in_array($domain, $this->getDomains(), true)) {\n            throw new InvalidArgumentException(\\sprintf('Invalid domain: \"%s\".', $domain));\n        }\n\n        if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) {\n            $this->processDomain($domain);\n        }\n\n        return $this->messages[$domain][self::OBSOLETE_BATCH];\n    }\n\n    public function getResult(): MessageCatalogueInterface\n    {\n        foreach ($this->getDomains() as $domain) {\n            if (!isset($this->messages[$domain])) {\n                $this->processDomain($domain);\n            }\n        }\n\n        return $this->result;\n    }\n\n    /**\n     * @param self::*_BATCH $batch\n     */\n    public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BATCH): void\n    {\n        // If MessageFormatter class does not exists, intl domains are not supported.\n        if (!class_exists(\\MessageFormatter::class)) {\n            return;\n        }\n\n        foreach ($this->getDomains() as $domain) {\n            $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n            $messages = match ($batch) {\n                self::OBSOLETE_BATCH => $this->getObsoleteMessages($domain),\n                self::NEW_BATCH => $this->getNewMessages($domain),\n                self::ALL_BATCH => $this->getMessages($domain),\n                default => throw new \\InvalidArgumentException(\\sprintf('$batch argument must be one of [\"%s\", \"%s\", \"%s\"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)),\n            };\n\n            if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) {\n                continue;\n            }\n\n            $result = $this->getResult();\n            $allIntlMessages = $result->all($intlDomain);\n            $currentMessages = array_diff_key($messages, $result->all($domain));\n            $result->replace($currentMessages, $domain);\n            $result->replace($allIntlMessages + $messages, $intlDomain);\n        }\n    }\n\n    /**\n     * Performs operation on source and target catalogues for the given domain and\n     * stores the results.\n     *\n     * @param string $domain The domain which the operation will be performed for\n     */\n    abstract protected function processDomain(string $domain): void;\n}\n"
  },
  {
    "path": "Catalogue/MergeOperation.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Catalogue;\n\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\n/**\n * Merge operation between two catalogues as follows:\n * all = source ∪ target = {x: x ∈ source ∨ x ∈ target}\n * new = all ∖ source = {x: x ∈ target ∧ x ∉ source}\n * obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ source ∧ x ∉ target} = ∅\n * Basically, the result contains messages from both catalogues.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n */\nclass MergeOperation extends AbstractOperation\n{\n    protected function processDomain(string $domain): void\n    {\n        $this->messages[$domain] = [\n            'all' => [],\n            'new' => [],\n            'obsolete' => [],\n        ];\n        $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n\n        foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {\n            if (null === $this->result->getCatalogueMetadata($key, $domain)) {\n                $this->result->setCatalogueMetadata($key, $value, $domain);\n            }\n        }\n\n        foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {\n            if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {\n                $this->result->setCatalogueMetadata($key, $value, $intlDomain);\n            }\n        }\n\n        foreach ($this->source->all($domain) as $id => $message) {\n            $this->messages[$domain]['all'][$id] = $message;\n            $d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;\n            $this->result->add([$id => $message], $d);\n            if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) {\n                $this->result->setMetadata($id, $keyMetadata, $d);\n            }\n        }\n\n        foreach ($this->target->all($domain) as $id => $message) {\n            if (!$this->source->has($id, $domain)) {\n                $this->messages[$domain]['all'][$id] = $message;\n                $this->messages[$domain]['new'][$id] = $message;\n                $d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;\n                $this->result->add([$id => $message], $d);\n                if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) {\n                    $this->result->setMetadata($id, $keyMetadata, $d);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Catalogue/OperationInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Catalogue;\n\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\n/**\n * Represents an operation on catalogue(s).\n *\n * An instance of this interface performs an operation on one or more catalogues and\n * stores intermediate and final results of the operation.\n *\n * The first catalogue in its argument(s) is called the 'source catalogue' or 'source' and\n * the following results are stored:\n *\n * Messages: also called 'all', are valid messages for the given domain after the operation is performed.\n *\n * New Messages: also called 'new' (new = all ∖ source = {x: x ∈ all ∧ x ∉ source}).\n *\n * Obsolete Messages: also called 'obsolete' (obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ all}).\n *\n * Result: also called 'result', is the resulting catalogue for the given domain that holds the same messages as 'all'.\n *\n * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>\n */\ninterface OperationInterface\n{\n    /**\n     * Returns domains affected by operation.\n     */\n    public function getDomains(): array;\n\n    /**\n     * Returns all valid messages ('all') after operation.\n     */\n    public function getMessages(string $domain): array;\n\n    /**\n     * Returns new messages ('new') after operation.\n     */\n    public function getNewMessages(string $domain): array;\n\n    /**\n     * Returns obsolete messages ('obsolete') after operation.\n     */\n    public function getObsoleteMessages(string $domain): array;\n\n    /**\n     * Returns resulting catalogue ('result').\n     */\n    public function getResult(): MessageCatalogueInterface;\n}\n"
  },
  {
    "path": "Catalogue/TargetOperation.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Catalogue;\n\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\n/**\n * Target operation between two catalogues:\n * intersection = source ∩ target = {x: x ∈ source ∧ x ∈ target}\n * all = intersection ∪ (target ∖ intersection) = target\n * new = all ∖ source = {x: x ∈ target ∧ x ∉ source}\n * obsolete = source ∖ all = source ∖ target = {x: x ∈ source ∧ x ∉ target}\n * Basically, the result contains messages from the target catalogue.\n *\n * @author Michael Lee <michael.lee@zerustech.com>\n */\nclass TargetOperation extends AbstractOperation\n{\n    protected function processDomain(string $domain): void\n    {\n        $this->messages[$domain] = [\n            'all' => [],\n            'new' => [],\n            'obsolete' => [],\n        ];\n        $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n\n        foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {\n            if (null === $this->result->getCatalogueMetadata($key, $domain)) {\n                $this->result->setCatalogueMetadata($key, $value, $domain);\n            }\n        }\n\n        foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {\n            if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {\n                $this->result->setCatalogueMetadata($key, $value, $intlDomain);\n            }\n        }\n\n        // For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``,\n        // because doing so will drop messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}\n        //\n        // For 'new' messages, the code can't be simplified as ``array_diff_assoc($this->target->all($domain), $this->source->all($domain));``\n        // because doing so will not exclude messages like {x: x ∈ target ∧ x ∉ source.all ∧ x ∈ source.fallback}\n        //\n        // For 'obsolete' messages, the code can't be simplified as ``array_diff_assoc($this->source->all($domain), $this->target->all($domain))``\n        // because doing so will not exclude messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}\n\n        foreach ($this->source->all($domain) as $id => $message) {\n            if ($this->target->has($id, $domain)) {\n                $this->messages[$domain]['all'][$id] = $message;\n                $d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;\n                $this->result->add([$id => $message], $d);\n                if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) {\n                    $this->result->setMetadata($id, $keyMetadata, $d);\n                }\n            } else {\n                $this->messages[$domain]['obsolete'][$id] = $message;\n            }\n        }\n\n        foreach ($this->target->all($domain) as $id => $message) {\n            if (!$this->source->has($id, $domain)) {\n                $this->messages[$domain]['all'][$id] = $message;\n                $this->messages[$domain]['new'][$id] = $message;\n                $d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;\n                $this->result->add([$id => $message], $d);\n                if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) {\n                    $this->result->setMetadata($id, $keyMetadata, $d);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "CatalogueMetadataAwareInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\n/**\n * This interface is used to get, set, and delete metadata about the Catalogue.\n *\n * @author Hugo Alliaume <hugo@alliau.me>\n */\ninterface CatalogueMetadataAwareInterface\n{\n    /**\n     * Gets catalogue metadata for the given domain and key.\n     *\n     * Passing an empty domain will return an array with all catalogue metadata indexed by\n     * domain and then by key. Passing an empty key will return an array with all\n     * catalogue metadata for the given domain.\n     *\n     * @return mixed The value that was set or an array with the domains/keys or null\n     */\n    public function getCatalogueMetadata(string $key = '', string $domain = 'messages'): mixed;\n\n    /**\n     * Adds catalogue metadata to a message domain.\n     */\n    public function setCatalogueMetadata(string $key, mixed $value, string $domain = 'messages'): void;\n\n    /**\n     * Deletes catalogue metadata for the given key and domain.\n     *\n     * Passing an empty domain will delete all catalogue metadata. Passing an empty key will\n     * delete all metadata for the given domain.\n     */\n    public function deleteCatalogueMetadata(string $key = '', string $domain = 'messages'): void;\n}\n"
  },
  {
    "path": "Command/TranslationLintCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Command;\n\nuse Symfony\\Component\\Console\\Attribute\\AsCommand;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\nuse Symfony\\Component\\Translation\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\Translation\\TranslatorBagInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n/**\n * Lint translations files syntax and outputs encountered errors.\n *\n * @author Hugo Alliaume <hugo@alliau.me>\n */\n#[AsCommand(name: 'lint:translations', description: 'Lint translations files syntax and outputs encountered errors')]\nclass TranslationLintCommand extends Command\n{\n    private SymfonyStyle $io;\n\n    public function __construct(\n        private TranslatorInterface&TranslatorBagInterface $translator,\n        private array $enabledLocales = [],\n    ) {\n        $this->enabledLocales = array_filter($enabledLocales);\n        parent::__construct();\n    }\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if ($input->mustSuggestOptionValuesFor('locale')) {\n            $suggestions->suggestValues($this->enabledLocales);\n        }\n    }\n\n    protected function configure(): void\n    {\n        $this\n            ->setDefinition([\n                new InputOption('locale', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to lint.', $this->enabledLocales),\n            ])\n            ->setHelp(<<<'EOF'\n                The <info>%command.name%</> command lint translations.\n\n                  <info>php %command.full_name%</>\n                EOF\n            );\n    }\n\n    protected function initialize(InputInterface $input, OutputInterface $output): void\n    {\n        $this->io = new SymfonyStyle($input, $output);\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $locales = $input->getOption('locale');\n\n        /** @var array<string, array<string, array<string, \\Throwable>>> $errors */\n        $errors = [];\n        $domainsByLocales = [];\n\n        foreach ($locales as $locale) {\n            $messageCatalogue = $this->translator->getCatalogue($locale);\n\n            foreach ($domainsByLocales[$locale] = $messageCatalogue->getDomains() as $domain) {\n                foreach ($messageCatalogue->all($domain) as $id => $translation) {\n                    try {\n                        $this->translator->trans($id, [], $domain, $messageCatalogue->getLocale());\n                    } catch (ExceptionInterface $e) {\n                        $errors[$locale][$domain][$id] = $e;\n                    }\n                }\n            }\n        }\n\n        if (!$domainsByLocales) {\n            $this->io->error('No translation files were found.');\n\n            return Command::SUCCESS;\n        }\n\n        $this->io->table(\n            ['Locale', 'Domains', 'Valid?'],\n            array_map(\n                static fn (string $locale, array $domains) => [\n                    $locale,\n                    implode(', ', $domains),\n                    !\\array_key_exists($locale, $errors) ? '<info>Yes</>' : '<error>No</>',\n                ],\n                array_keys($domainsByLocales),\n                $domainsByLocales\n            ),\n        );\n\n        if ($errors) {\n            foreach ($errors as $locale => $domains) {\n                foreach ($domains as $domain => $domainsErrors) {\n                    $this->io->section(\\sprintf('Errors for locale \"%s\" and domain \"%s\"', $locale, $domain));\n\n                    foreach ($domainsErrors as $id => $error) {\n                        $this->io->text(\\sprintf('Translation key \"%s\" is invalid:', $id));\n                        $this->io->error($error->getMessage());\n                    }\n                }\n            }\n\n            return Command::FAILURE;\n        }\n\n        $this->io->success('All translations are valid.');\n\n        return Command::SUCCESS;\n    }\n}\n"
  },
  {
    "path": "Command/TranslationPullCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Command;\n\nuse Symfony\\Component\\Console\\Attribute\\AsCommand;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\nuse Symfony\\Component\\Translation\\Catalogue\\TargetOperation;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\Provider\\TranslationProviderCollection;\nuse Symfony\\Component\\Translation\\Reader\\TranslationReaderInterface;\nuse Symfony\\Component\\Translation\\Writer\\TranslationWriterInterface;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\n#[AsCommand(name: 'translation:pull', description: 'Pull translations from a given provider.')]\nfinal class TranslationPullCommand extends Command\n{\n    use TranslationTrait;\n\n    public function __construct(\n        private TranslationProviderCollection $providerCollection,\n        private TranslationWriterInterface $writer,\n        private TranslationReaderInterface $reader,\n        private string $defaultLocale,\n        private array $transPaths = [],\n        private array $enabledLocales = [],\n    ) {\n        $this->enabledLocales = array_filter($enabledLocales);\n        parent::__construct();\n    }\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if ($input->mustSuggestArgumentValuesFor('provider')) {\n            $suggestions->suggestValues($this->providerCollection->keys());\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('domains')) {\n            $provider = $this->providerCollection->get($input->getArgument('provider'));\n\n            if (method_exists($provider, 'getDomains')) {\n                $suggestions->suggestValues($provider->getDomains());\n            }\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('locales')) {\n            $suggestions->suggestValues($this->enabledLocales);\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('format')) {\n            $suggestions->suggestValues(['php', 'xlf', 'xlf12', 'xlf20', 'po', 'mo', 'yml', 'yaml', 'ts', 'csv', 'json', 'ini', 'res']);\n        }\n    }\n\n    protected function configure(): void\n    {\n        $keys = $this->providerCollection->keys();\n        $defaultProvider = 1 === \\count($keys) ? $keys[0] : null;\n\n        $this\n            ->setDefinition([\n                new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to pull translations from.', $defaultProvider),\n                new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with provider ones (it will delete not synchronized messages).'),\n                new InputOption('intl-icu', null, InputOption::VALUE_NONE, 'Associated to --force option, it will write messages in \"%domain%+intl-icu.%locale%.xlf\" files.'),\n                new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'),\n                new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'),\n                new InputOption('format', null, InputOption::VALUE_REQUIRED, 'Override the default output format.', 'xlf12'),\n                new InputOption('as-tree', null, InputOption::VALUE_REQUIRED, 'Write messages as a tree-like structure. Needs --format=yaml. The given value defines the level where to switch to inline YAML'),\n            ])\n            ->setHelp(<<<'EOF'\n                The <info>%command.name%</> command pulls translations from the given provider. Only\n                new translations are pulled, existing ones are not overwritten.\n\n                You can overwrite existing translations (and remove the missing ones on local side) by using the <info>--force</> flag:\n\n                  <info>php %command.full_name% --force provider</>\n\n                Full example:\n\n                  <info>php %command.full_name% provider --force --domains=messages --domains=validators --locales=en</>\n\n                This command pulls all translations associated with the <info>messages</> and <info>validators</> domains for the <info>en</> locale.\n                Local translations for the specified domains and locale are deleted if they're not present on the provider and overwritten if it's the case.\n                Local translations for others domains and locales are ignored.\n                EOF\n            )\n        ;\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $io = new SymfonyStyle($input, $output);\n\n        $provider = $this->providerCollection->get($input->getArgument('provider'));\n        $force = $input->getOption('force');\n        $intlIcu = $input->getOption('intl-icu');\n        $locales = $input->getOption('locales') ?: $this->enabledLocales;\n        $domains = $input->getOption('domains');\n        $format = $input->getOption('format');\n        $asTree = (int) $input->getOption('as-tree');\n        $xliffVersion = '1.2';\n\n        if ($intlIcu && !$force) {\n            $io->note('--intl-icu option only has an effect when used with --force. Here, it will be ignored.');\n        }\n\n        switch ($format) {\n            case 'xlf20': $xliffVersion = '2.0';\n                // no break\n            case 'xlf12': $format = 'xlf';\n        }\n\n        $writeOptions = [\n            'path' => end($this->transPaths),\n            'xliff_version' => $xliffVersion,\n            'default_locale' => $this->defaultLocale,\n            'as_tree' => (bool) $asTree,\n            'inline' => $asTree,\n        ];\n\n        if (!$domains) {\n            $domains = $provider->getDomains();\n        }\n\n        $providerTranslations = $provider->read($domains, $locales);\n\n        if ($force) {\n            foreach ($providerTranslations->getCatalogues() as $catalogue) {\n                $operation = new TargetOperation(new MessageCatalogue($catalogue->getLocale()), $catalogue);\n                if ($intlIcu) {\n                    $operation->moveMessagesToIntlDomainsIfPossible();\n                }\n                $this->writer->write($operation->getResult(), $format, $writeOptions);\n            }\n\n            $io->success(\\sprintf('Local translations has been updated from \"%s\" (for \"%s\" locale(s), and \"%s\" domain(s)).', parse_url($provider, \\PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains)));\n\n            return 0;\n        }\n\n        $localTranslations = $this->readLocalTranslations($locales, $domains, $this->transPaths);\n\n        // Append pulled translations to local ones.\n        $localTranslations->addBag($providerTranslations->diff($localTranslations));\n\n        foreach ($localTranslations->getCatalogues() as $catalogue) {\n            $this->writer->write($catalogue, $format, $writeOptions);\n        }\n\n        $io->success(\\sprintf('New translations from \"%s\" has been written locally (for \"%s\" locale(s), and \"%s\" domain(s)).', parse_url($provider, \\PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains)));\n\n        return 0;\n    }\n}\n"
  },
  {
    "path": "Command/TranslationPushCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Command;\n\nuse Symfony\\Component\\Console\\Attribute\\AsCommand;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\nuse Symfony\\Component\\Translation\\Provider\\FilteringProvider;\nuse Symfony\\Component\\Translation\\Provider\\TranslationProviderCollection;\nuse Symfony\\Component\\Translation\\Reader\\TranslationReaderInterface;\nuse Symfony\\Component\\Translation\\TranslatorBag;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\n#[AsCommand(name: 'translation:push', description: 'Push translations to a given provider.')]\nfinal class TranslationPushCommand extends Command\n{\n    use TranslationTrait;\n\n    public function __construct(\n        private TranslationProviderCollection $providers,\n        private TranslationReaderInterface $reader,\n        private array $transPaths = [],\n        private array $enabledLocales = [],\n    ) {\n        $this->enabledLocales = array_filter($enabledLocales);\n        parent::__construct();\n    }\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if ($input->mustSuggestArgumentValuesFor('provider')) {\n            $suggestions->suggestValues($this->providers->keys());\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('domains')) {\n            $provider = $this->providers->get($input->getArgument('provider'));\n\n            if (method_exists($provider, 'getDomains')) {\n                $domains = $provider->getDomains();\n                $suggestions->suggestValues($domains);\n            }\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('locales')) {\n            $suggestions->suggestValues($this->enabledLocales);\n        }\n    }\n\n    protected function configure(): void\n    {\n        $keys = $this->providers->keys();\n        $defaultProvider = 1 === \\count($keys) ? $keys[0] : null;\n\n        $this\n            ->setDefinition([\n                new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to push translations to.', $defaultProvider),\n                new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with local ones (it will delete not synchronized messages).'),\n                new InputOption('delete-missing', null, InputOption::VALUE_NONE, 'Delete translations available on provider but not locally.'),\n                new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to push.'),\n                new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to push.', $this->enabledLocales),\n            ])\n            ->setHelp(<<<'EOF'\n                The <info>%command.name%</> command pushes translations to the given provider. Only new\n                translations are pushed, existing ones are not overwritten.\n\n                You can overwrite existing translations by using the <info>--force</> flag:\n\n                  <info>php %command.full_name% --force provider</>\n\n                You can delete provider translations which are not present locally by using the <info>--delete-missing</> flag:\n\n                  <info>php %command.full_name% --delete-missing provider</>\n\n                Full example:\n\n                  <info>php %command.full_name% provider --force --delete-missing --domains=messages --domains=validators --locales=en</>\n\n                This command pushes all translations associated with the <info>messages</> and <info>validators</> domains for the <info>en</> locale.\n                Provider translations for the specified domains and locale are deleted if they're not present locally and overwritten if it's the case.\n                Provider translations for others domains and locales are ignored.\n                EOF\n            )\n        ;\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $provider = $this->providers->get($input->getArgument('provider'));\n\n        if (!$this->enabledLocales) {\n            throw new InvalidArgumentException(\\sprintf('You must define \"framework.enabled_locales\" or \"framework.translator.providers.%s.locales\" config key in order to work with translation providers.', parse_url($provider, \\PHP_URL_SCHEME)));\n        }\n\n        $io = new SymfonyStyle($input, $output);\n        $domains = $input->getOption('domains');\n        $locales = $input->getOption('locales');\n        $force = $input->getOption('force');\n        $deleteMissing = $input->getOption('delete-missing');\n\n        if (!$domains && $provider instanceof FilteringProvider) {\n            $domains = $provider->getDomains();\n        }\n\n        // Reading local translations must be done after retrieving the domains from the provider\n        // in order to manage only translations from configured domains\n        $localTranslations = $this->readLocalTranslations($locales, $domains, $this->transPaths);\n\n        if (!$domains) {\n            $domains = $this->getDomainsFromTranslatorBag($localTranslations);\n        }\n\n        if (!$deleteMissing && $force) {\n            $provider->write($localTranslations);\n\n            $io->success(\\sprintf('All local translations has been sent to \"%s\" (for \"%s\" locale(s), and \"%s\" domain(s)).', parse_url($provider, \\PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains)));\n\n            return 0;\n        }\n\n        $providerTranslations = $provider->read($domains, $locales);\n\n        if ($deleteMissing) {\n            $provider->delete($providerTranslations->diff($localTranslations));\n\n            $io->success(\\sprintf('Missing translations on \"%s\" has been deleted (for \"%s\" locale(s), and \"%s\" domain(s)).', parse_url($provider, \\PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains)));\n\n            // Read provider translations again, after missing translations deletion,\n            // to avoid push freshly deleted translations.\n            $providerTranslations = $provider->read($domains, $locales);\n        }\n\n        $translationsToWrite = $localTranslations->diff($providerTranslations);\n\n        if ($force) {\n            $translationsToWrite->addBag($localTranslations->intersect($providerTranslations));\n        }\n\n        $provider->write($translationsToWrite);\n\n        $io->success(\\sprintf('%s local translations has been sent to \"%s\" (for \"%s\" locale(s), and \"%s\" domain(s)).', $force ? 'All' : 'New', parse_url($provider, \\PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains)));\n\n        return 0;\n    }\n\n    private function getDomainsFromTranslatorBag(TranslatorBag $translatorBag): array\n    {\n        $domains = [];\n\n        foreach ($translatorBag->getCatalogues() as $catalogue) {\n            $domains += $catalogue->getDomains();\n        }\n\n        return array_unique($domains);\n    }\n}\n"
  },
  {
    "path": "Command/TranslationTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Command;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\nuse Symfony\\Component\\Translation\\TranslatorBag;\n\n/**\n * @internal\n */\ntrait TranslationTrait\n{\n    private function readLocalTranslations(array $locales, array $domains, array $transPaths): TranslatorBag\n    {\n        $bag = new TranslatorBag();\n\n        foreach ($locales as $locale) {\n            $catalogue = new MessageCatalogue($locale);\n            foreach ($transPaths as $path) {\n                $this->reader->read($path, $catalogue);\n            }\n\n            if ($domains) {\n                foreach ($domains as $domain) {\n                    $bag->addCatalogue($this->filterCatalogue($catalogue, $domain));\n                }\n            } else {\n                $bag->addCatalogue($catalogue);\n            }\n        }\n\n        return $bag;\n    }\n\n    private function filterCatalogue(MessageCatalogue $catalogue, string $domain): MessageCatalogue\n    {\n        $filteredCatalogue = new MessageCatalogue($catalogue->getLocale());\n\n        // extract intl-icu messages only\n        $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n        if ($intlMessages = $catalogue->all($intlDomain)) {\n            $filteredCatalogue->add($intlMessages, $intlDomain);\n        }\n\n        // extract all messages and subtract intl-icu messages\n        if ($messages = array_diff($catalogue->all($domain), $intlMessages)) {\n            $filteredCatalogue->add($messages, $domain);\n        }\n        foreach ($catalogue->getResources() as $resource) {\n            $filteredCatalogue->addResource($resource);\n        }\n\n        if ($metadata = $catalogue->getMetadata('', $intlDomain)) {\n            foreach ($metadata as $k => $v) {\n                $filteredCatalogue->setMetadata($k, $v, $intlDomain);\n            }\n        }\n\n        if ($metadata = $catalogue->getMetadata('', $domain)) {\n            foreach ($metadata as $k => $v) {\n                $filteredCatalogue->setMetadata($k, $v, $domain);\n            }\n        }\n\n        return $filteredCatalogue;\n    }\n}\n"
  },
  {
    "path": "Command/XliffLintCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Command;\n\nuse Symfony\\Component\\Console\\Attribute\\AsCommand;\nuse Symfony\\Component\\Console\\CI\\GithubActionReporter;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Util\\XliffUtils;\n\n/**\n * Validates XLIFF files syntax and outputs encountered errors.\n *\n * @author Grégoire Pineau <lyrixx@lyrixx.info>\n * @author Robin Chalas <robin.chalas@gmail.com>\n * @author Javier Eguiluz <javier.eguiluz@gmail.com>\n */\n#[AsCommand(name: 'lint:xliff', description: 'Lint an XLIFF file and outputs encountered errors')]\nclass XliffLintCommand extends Command\n{\n    private string $format;\n    private bool $displayCorrectFiles;\n    private ?\\Closure $directoryIteratorProvider;\n    private ?\\Closure $isReadableProvider;\n\n    public function __construct(\n        ?string $name = null,\n        ?callable $directoryIteratorProvider = null,\n        ?callable $isReadableProvider = null,\n        private bool $requireStrictFileNames = true,\n    ) {\n        parent::__construct($name);\n\n        $this->directoryIteratorProvider = null === $directoryIteratorProvider ? null : $directoryIteratorProvider(...);\n        $this->isReadableProvider = null === $isReadableProvider ? null : $isReadableProvider(...);\n    }\n\n    protected function configure(): void\n    {\n        $this\n            ->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or \"-\" for reading from STDIN')\n            ->addOption('format', null, InputOption::VALUE_REQUIRED, \\sprintf('The output format (\"%s\")', implode('\", \"', $this->getAvailableFormatOptions())))\n            ->setHelp(<<<EOF\n                The <info>%command.name%</info> command lints an XLIFF file and outputs to STDOUT\n                the first encountered syntax error.\n\n                You can validates XLIFF contents passed from STDIN:\n\n                  <info>cat filename | php %command.full_name% -</info>\n\n                You can also validate the syntax of a file:\n\n                  <info>php %command.full_name% filename</info>\n\n                Or of a whole directory:\n\n                  <info>php %command.full_name% dirname</info>\n\n                The <info>--format</info> option specifies the format of the command output:\n\n                  <info>php %command.full_name% dirname --format=json</info>\n\n                EOF\n            )\n        ;\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $io = new SymfonyStyle($input, $output);\n        $filenames = (array) $input->getArgument('filename');\n        $this->format = $input->getOption('format') ?? (GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt');\n        $this->displayCorrectFiles = $output->isVerbose();\n\n        if (['-'] === $filenames) {\n            return $this->display($io, [$this->validate(file_get_contents('php://stdin'))]);\n        }\n\n        if (!$filenames) {\n            throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');\n        }\n\n        $filesInfo = [];\n        foreach ($filenames as $filename) {\n            if (!$this->isReadable($filename)) {\n                throw new RuntimeException(\\sprintf('File or directory \"%s\" is not readable.', $filename));\n            }\n\n            foreach ($this->getFiles($filename) as $file) {\n                $filesInfo[] = $this->validate(file_get_contents($file), $file);\n            }\n        }\n\n        return $this->display($io, $filesInfo);\n    }\n\n    private function validate(string $content, ?string $file = null): array\n    {\n        $errors = [];\n\n        // Avoid: Warning DOMDocument::loadXML(): Empty string supplied as input\n        if ('' === trim($content)) {\n            return ['file' => $file, 'valid' => true];\n        }\n\n        $internal = libxml_use_internal_errors(true);\n\n        $document = new \\DOMDocument();\n        $document->loadXML($content);\n\n        if (null !== $targetLanguage = $this->getTargetLanguageFromFile($document)) {\n            $normalizedLocalePattern = \\sprintf('(%s|%s)', preg_quote($targetLanguage, '/'), preg_quote(str_replace('-', '_', $targetLanguage), '/'));\n            // strict file names require translation files to be named '____.locale.xlf'\n            // otherwise, both '____.locale.xlf' and 'locale.____.xlf' are allowed\n            // also, the regexp matching must be case-insensitive, as defined for 'target-language' values\n            // http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#target-language\n            $expectedFilenamePattern = $this->requireStrictFileNames ? \\sprintf('/^.*\\.(?i:%s)\\.(?:xlf|xliff)/', $normalizedLocalePattern) : \\sprintf('/^(?:.*\\.(?i:%s)|(?i:%s)\\..*)\\.(?:xlf|xliff)/', $normalizedLocalePattern, $normalizedLocalePattern);\n\n            if (0 === preg_match($expectedFilenamePattern, basename($file))) {\n                $errors[] = [\n                    'line' => -1,\n                    'column' => -1,\n                    'message' => \\sprintf('There is a mismatch between the language included in the file name (\"%s\") and the \"%s\" value used in the \"target-language\" attribute of the file.', basename($file), $targetLanguage),\n                ];\n            }\n        }\n\n        foreach (XliffUtils::validateSchema($document) as $xmlError) {\n            $errors[] = [\n                'line' => $xmlError['line'],\n                'column' => $xmlError['column'],\n                'message' => $xmlError['message'],\n            ];\n        }\n\n        libxml_clear_errors();\n        libxml_use_internal_errors($internal);\n\n        return ['file' => $file, 'valid' => 0 === \\count($errors), 'messages' => $errors];\n    }\n\n    private function display(SymfonyStyle $io, array $files): int\n    {\n        return match ($this->format) {\n            'txt' => $this->displayTxt($io, $files),\n            'json' => $this->displayJson($io, $files),\n            'github' => $this->displayTxt($io, $files, true),\n            default => throw new InvalidArgumentException(\\sprintf('Supported formats are \"%s\".', implode('\", \"', $this->getAvailableFormatOptions()))),\n        };\n    }\n\n    private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false): int\n    {\n        $countFiles = \\count($filesInfo);\n        $erroredFiles = 0;\n        $githubReporter = $errorAsGithubAnnotations ? new GithubActionReporter($io) : null;\n\n        foreach ($filesInfo as $info) {\n            if ($info['valid'] && $this->displayCorrectFiles) {\n                $io->comment('<info>OK</info>'.($info['file'] ? \\sprintf(' in %s', $info['file']) : ''));\n            } elseif (!$info['valid']) {\n                ++$erroredFiles;\n                $io->text('<error> ERROR </error>'.($info['file'] ? \\sprintf(' in %s', $info['file']) : ''));\n                $io->listing(array_map(static function ($error) use ($info, $githubReporter) {\n                    // general document errors have a '-1' line number\n                    $line = -1 === $error['line'] ? null : $error['line'];\n\n                    $githubReporter?->error($error['message'], $info['file'], $line, null !== $line ? $error['column'] : null);\n\n                    return null === $line ? $error['message'] : \\sprintf('Line %d, Column %d: %s', $line, $error['column'], $error['message']);\n                }, $info['messages']));\n            }\n        }\n\n        if (0 === $erroredFiles) {\n            $io->success(\\sprintf('All %d XLIFF files contain valid syntax.', $countFiles));\n        } else {\n            $io->warning(\\sprintf('%d XLIFF files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles));\n        }\n\n        return min($erroredFiles, 1);\n    }\n\n    private function displayJson(SymfonyStyle $io, array $filesInfo): int\n    {\n        $errors = 0;\n\n        array_walk($filesInfo, static function (&$v) use (&$errors) {\n            $v['file'] = (string) $v['file'];\n            if (!$v['valid']) {\n                ++$errors;\n            }\n        });\n\n        $io->writeln(json_encode($filesInfo, \\JSON_PRETTY_PRINT | \\JSON_UNESCAPED_SLASHES));\n\n        return min($errors, 1);\n    }\n\n    /**\n     * @return iterable<\\SplFileInfo>\n     */\n    private function getFiles(string $fileOrDirectory): iterable\n    {\n        if (is_file($fileOrDirectory)) {\n            yield new \\SplFileInfo($fileOrDirectory);\n\n            return;\n        }\n\n        foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {\n            if (!\\in_array($file->getExtension(), ['xlf', 'xliff'], true)) {\n                continue;\n            }\n\n            yield $file;\n        }\n    }\n\n    /**\n     * @return iterable<\\SplFileInfo>\n     */\n    private function getDirectoryIterator(string $directory): iterable\n    {\n        $default = static fn ($directory) => new \\RecursiveIteratorIterator(\n            new \\RecursiveDirectoryIterator($directory, \\FilesystemIterator::SKIP_DOTS | \\FilesystemIterator::FOLLOW_SYMLINKS),\n            \\RecursiveIteratorIterator::LEAVES_ONLY\n        );\n\n        if (null !== $this->directoryIteratorProvider) {\n            return ($this->directoryIteratorProvider)($directory, $default);\n        }\n\n        return $default($directory);\n    }\n\n    private function isReadable(string $fileOrDirectory): bool\n    {\n        $default = static fn ($fileOrDirectory) => is_readable($fileOrDirectory);\n\n        if (null !== $this->isReadableProvider) {\n            return ($this->isReadableProvider)($fileOrDirectory, $default);\n        }\n\n        return $default($fileOrDirectory);\n    }\n\n    private function getTargetLanguageFromFile(\\DOMDocument $xliffContents): ?string\n    {\n        foreach ($xliffContents->getElementsByTagName('file')[0]->attributes ?? [] as $attribute) {\n            if ('target-language' === $attribute->nodeName) {\n                return $attribute->nodeValue;\n            }\n        }\n\n        return null;\n    }\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if ($input->mustSuggestOptionValuesFor('format')) {\n            $suggestions->suggestValues($this->getAvailableFormatOptions());\n        }\n    }\n\n    /** @return string[] */\n    private function getAvailableFormatOptions(): array\n    {\n        return ['txt', 'json', 'github'];\n    }\n}\n"
  },
  {
    "path": "DataCollector/TranslationDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\LateDataCollectorInterface;\nuse Symfony\\Component\\Translation\\DataCollectorTranslator;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n *\n * @final\n */\nclass TranslationDataCollector extends DataCollector implements LateDataCollectorInterface\n{\n    public function __construct(\n        private DataCollectorTranslator $translator,\n    ) {\n    }\n\n    public function lateCollect(): void\n    {\n        $messages = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages());\n\n        $this->data += $this->computeCount($messages);\n        $this->data['messages'] = $messages;\n\n        $this->data = $this->cloneVar($this->data);\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        $this->data['locale'] = $this->translator->getLocale();\n        $this->data['fallback_locales'] = $this->translator->getFallbackLocales();\n        $this->data['global_parameters'] = $this->translator->getGlobalParameters();\n    }\n\n    public function reset(): void\n    {\n        $this->data = [];\n    }\n\n    public function getMessages(): array|Data\n    {\n        return $this->data['messages'] ?? [];\n    }\n\n    public function getCountMissings(): int\n    {\n        return $this->data[DataCollectorTranslator::MESSAGE_MISSING] ?? 0;\n    }\n\n    public function getCountFallbacks(): int\n    {\n        return $this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK] ?? 0;\n    }\n\n    public function getCountDefines(): int\n    {\n        return $this->data[DataCollectorTranslator::MESSAGE_DEFINED] ?? 0;\n    }\n\n    public function getLocale(): ?string\n    {\n        return !empty($this->data['locale']) ? $this->data['locale'] : null;\n    }\n\n    /**\n     * @internal\n     */\n    public function getFallbackLocales(): Data|array\n    {\n        return (isset($this->data['fallback_locales']) && \\count($this->data['fallback_locales']) > 0) ? $this->data['fallback_locales'] : [];\n    }\n\n    /**\n     * @internal\n     */\n    public function getGlobalParameters(): Data|array\n    {\n        return $this->data['global_parameters'] ?? [];\n    }\n\n    public function getName(): string\n    {\n        return 'translation';\n    }\n\n    private function sanitizeCollectedMessages(array $messages): array\n    {\n        $result = [];\n        foreach ($messages as $key => $message) {\n            $messageId = $message['locale'].$message['domain'].$message['id'];\n\n            if (!isset($result[$messageId])) {\n                $message['count'] = 1;\n                $message['parameters'] = !empty($message['parameters']) ? [$message['parameters']] : [];\n                $messages[$key]['translation'] = $this->sanitizeString($message['translation']);\n                $result[$messageId] = $message;\n            } else {\n                if (!empty($message['parameters'])) {\n                    $result[$messageId]['parameters'][] = $message['parameters'];\n                }\n\n                ++$result[$messageId]['count'];\n            }\n\n            unset($messages[$key]);\n        }\n\n        return $result;\n    }\n\n    private function computeCount(array $messages): array\n    {\n        $count = [\n            DataCollectorTranslator::MESSAGE_DEFINED => 0,\n            DataCollectorTranslator::MESSAGE_MISSING => 0,\n            DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK => 0,\n        ];\n\n        foreach ($messages as $message) {\n            ++$count[$message['state']];\n        }\n\n        return $count;\n    }\n\n    private function sanitizeString(string $string, int $length = 80): string\n    {\n        $string = trim(preg_replace('/\\s+/', ' ', $string));\n\n        if (false !== $encoding = mb_detect_encoding($string, null, true)) {\n            if (mb_strlen($string, $encoding) > $length) {\n                return mb_substr($string, 0, $length - 3, $encoding).'...';\n            }\n        } elseif (\\strlen($string) > $length) {\n            return substr($string, 0, $length - 3).'...';\n        }\n\n        return $string;\n    }\n}\n"
  },
  {
    "path": "DataCollectorTranslator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\HttpKernel\\CacheWarmer\\WarmableInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nfinal class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface, WarmableInterface, ResetInterface\n{\n    public const MESSAGE_DEFINED = 0;\n    public const MESSAGE_MISSING = 1;\n    public const MESSAGE_EQUALS_FALLBACK = 2;\n\n    private array $messages = [];\n\n    public function __construct(\n        private TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator,\n    ) {\n    }\n\n    public function reset(): void\n    {\n        $this->messages = [];\n    }\n\n    public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string\n    {\n        $trans = $this->translator->trans($id = (string) $id, $parameters, $domain, $locale);\n        $this->collectMessage($locale, $domain, $id, $trans, $parameters);\n\n        return $trans;\n    }\n\n    public function setLocale(string $locale): void\n    {\n        $this->translator->setLocale($locale);\n    }\n\n    public function getLocale(): string\n    {\n        return $this->translator->getLocale();\n    }\n\n    public function getCatalogue(?string $locale = null): MessageCatalogueInterface\n    {\n        return $this->translator->getCatalogue($locale);\n    }\n\n    public function getCatalogues(): array\n    {\n        return $this->translator->getCatalogues();\n    }\n\n    public function warmUp(string $cacheDir, ?string $buildDir = null): array\n    {\n        if ($this->translator instanceof WarmableInterface) {\n            return $this->translator->warmUp($cacheDir, $buildDir);\n        }\n\n        return [];\n    }\n\n    public function getFallbackLocales(): array\n    {\n        if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) {\n            return $this->translator->getFallbackLocales();\n        }\n\n        return [];\n    }\n\n    public function getGlobalParameters(): array\n    {\n        if ($this->translator instanceof Translator || method_exists($this->translator, 'getGlobalParameters')) {\n            return $this->translator->getGlobalParameters();\n        }\n\n        return [];\n    }\n\n    public function __call(string $method, array $args): mixed\n    {\n        return $this->translator->{$method}(...$args);\n    }\n\n    public function getCollectedMessages(): array\n    {\n        return $this->messages;\n    }\n\n    private function collectMessage(?string $locale, ?string $domain, string $id, string $translation, ?array $parameters = []): void\n    {\n        $domain ??= 'messages';\n\n        $catalogue = $this->translator->getCatalogue($locale);\n        $locale = $catalogue->getLocale();\n        $fallbackLocale = null;\n        if ($catalogue->defines($id, $domain)) {\n            $state = self::MESSAGE_DEFINED;\n        } elseif ($catalogue->has($id, $domain)) {\n            $state = self::MESSAGE_EQUALS_FALLBACK;\n\n            $fallbackCatalogue = $catalogue->getFallbackCatalogue();\n            while ($fallbackCatalogue) {\n                if ($fallbackCatalogue->defines($id, $domain)) {\n                    $fallbackLocale = $fallbackCatalogue->getLocale();\n                    break;\n                }\n                $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();\n            }\n        } else {\n            $state = self::MESSAGE_MISSING;\n        }\n\n        $this->messages[] = [\n            'locale' => $locale,\n            'fallbackLocale' => $fallbackLocale,\n            'domain' => $domain,\n            'id' => $id,\n            'translation' => $translation,\n            'parameters' => $parameters,\n            'state' => $state,\n            'transChoiceNumber' => isset($parameters['%count%']) && is_numeric($parameters['%count%']) ? $parameters['%count%'] : null,\n        ];\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/DataCollectorTranslatorPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\Translation\\TranslatorBagInterface;\n\n/**\n * @author Christian Flothmann <christian.flothmann@sensiolabs.de>\n */\nclass DataCollectorTranslatorPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->has('translator')) {\n            return;\n        }\n\n        $translatorClass = $container->getParameterBag()->resolveValue($container->findDefinition('translator')->getClass());\n\n        if (!is_subclass_of($translatorClass, TranslatorBagInterface::class)) {\n            $container->removeDefinition('translator.data_collector');\n            $container->removeDefinition('data_collector.translation');\n        }\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/LoggingTranslatorPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\TranslatorBagInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass LoggingTranslatorPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasAlias('logger') || !$container->hasAlias('translator')) {\n            return;\n        }\n\n        if (!$container->hasParameter('translator.logging') || !$container->getParameter('translator.logging')) {\n            return;\n        }\n\n        $translatorAlias = $container->getAlias('translator');\n        $definition = $container->getDefinition((string) $translatorAlias);\n        $class = $container->getParameterBag()->resolveValue($definition->getClass());\n\n        if (!$r = $container->getReflectionClass($class)) {\n            throw new InvalidArgumentException(\\sprintf('Class \"%s\" used for service \"%s\" cannot be found.', $class, $translatorAlias));\n        }\n\n        if (!$r->isSubclassOf(TranslatorInterface::class) || !$r->isSubclassOf(TranslatorBagInterface::class)) {\n            return;\n        }\n\n        $container->getDefinition('translator.logging')->setDecoratedService('translator');\n        $warmer = $container->getDefinition('translation.warmer');\n        $subscriberAttributes = $warmer->getTag('container.service_subscriber');\n        $warmer->clearTag('container.service_subscriber');\n\n        foreach ($subscriberAttributes as $k => $v) {\n            if ((!isset($v['id']) || 'translator' !== $v['id']) && (!isset($v['key']) || 'translator' !== $v['key'])) {\n                $warmer->addTag('container.service_subscriber', $v);\n            }\n        }\n        $warmer->addTag('container.service_subscriber', ['key' => 'translator', 'id' => 'translator.logging.inner']);\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/TranslationDumperPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\n\n/**\n * Adds tagged translation.formatter services to translation writer.\n */\nclass TranslationDumperPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('translation.writer')) {\n            return;\n        }\n\n        $definition = $container->getDefinition('translation.writer');\n\n        foreach ($container->findTaggedServiceIds('translation.dumper', true) as $id => $attributes) {\n            $definition->addMethodCall('addDumper', [$attributes[0]['alias'], new Reference($id)]);\n        }\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/TranslationExtractorPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\n\n/**\n * Adds tagged translation.extractor services to translation extractor.\n */\nclass TranslationExtractorPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('translation.extractor')) {\n            return;\n        }\n\n        $definition = $container->getDefinition('translation.extractor');\n\n        foreach ($container->findTaggedServiceIds('translation.extractor', true) as $id => $attributes) {\n            $definition->addMethodCall('addExtractor', [$attributes[0]['alias'] ?? $id, new Reference($id)]);\n        }\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/TranslatorPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\ServiceLocatorTagPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\n\nclass TranslatorPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('translator.default')) {\n            return;\n        }\n\n        $loaders = [];\n        $loaderRefs = [];\n        foreach ($container->findTaggedServiceIds('translation.loader', true) as $id => $attributes) {\n            $loaderRefs[$id] = new Reference($id);\n            $loaders[$id][] = $attributes[0]['alias'];\n            if (isset($attributes[0]['legacy-alias'])) {\n                $loaders[$id][] = $attributes[0]['legacy-alias'];\n            }\n        }\n\n        if ($container->hasDefinition('translation.reader')) {\n            $definition = $container->getDefinition('translation.reader');\n            foreach ($loaders as $id => $formats) {\n                foreach ($formats as $format) {\n                    $definition->addMethodCall('addLoader', [$format, $loaderRefs[$id]]);\n                }\n            }\n        }\n\n        $container\n            ->findDefinition('translator.default')\n            ->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs))\n            ->replaceArgument(3, $loaders)\n        ;\n\n        if ($container->hasDefinition('validator') && $container->hasDefinition('translation.extractor.visitor.constraint')) {\n            $constraintVisitorDefinition = $container->getDefinition('translation.extractor.visitor.constraint');\n            $constraintClassNames = [];\n\n            foreach ($container->getDefinitions() as $definition) {\n                if (!$definition->hasTag('validator.constraint_validator')) {\n                    continue;\n                }\n                // Resolve constraint validator FQCN even if defined as %foo.validator.class% parameter\n                $className = $container->getParameterBag()->resolveValue($definition->getClass());\n                // Extraction of the constraint class name from the Constraint Validator FQCN\n                $constraintClassNames[] = str_replace('Validator', '', substr(strrchr($className, '\\\\'), 1));\n            }\n\n            $constraintVisitorDefinition->setArgument(0, $constraintClassNames);\n        }\n\n        if (!$container->hasParameter('twig.default_path')) {\n            return;\n        }\n\n        $paths = array_keys($container->getDefinition('twig.template_iterator')->getArgument(1));\n        if ($container->hasDefinition('console.command.translation_debug')) {\n            $definition = $container->getDefinition('console.command.translation_debug');\n            $definition->replaceArgument(4, $container->getParameter('twig.default_path'));\n\n            if (\\count($definition->getArguments()) > 6) {\n                $definition->replaceArgument(6, $paths);\n            }\n        }\n        if ($container->hasDefinition('console.command.translation_extract')) {\n            $definition = $container->getDefinition('console.command.translation_extract');\n            $definition->replaceArgument(5, $container->getParameter('twig.default_path'));\n\n            if (\\count($definition->getArguments()) > 7) {\n                $definition->replaceArgument(7, $paths);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DependencyInjection/TranslatorPathsPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\AbstractRecursivePass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Definition;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\DependencyInjection\\ServiceLocator;\nuse Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\TraceableValueResolver;\n\n/**\n * @author Yonel Ceruto <yonelceruto@gmail.com>\n */\nclass TranslatorPathsPass extends AbstractRecursivePass\n{\n    protected bool $skipScalars = true;\n\n    private int $level = 0;\n\n    /**\n     * @var array<string, bool>\n     */\n    private array $paths = [];\n\n    /**\n     * @var array<int, Definition>\n     */\n    private array $definitions = [];\n\n    /**\n     * @var array<string, array<string, bool>>\n     */\n    private array $controllers = [];\n\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('translator')) {\n            return;\n        }\n\n        foreach ($this->findControllerArguments($container) as $controller => $argument) {\n            $id = substr($controller, 0, strpos($controller, ':') ?: \\strlen($controller));\n            if ($container->hasDefinition($id)) {\n                [$locatorRef] = $argument->getValues();\n                $this->controllers[(string) $locatorRef][$container->getDefinition($id)->getClass()] = true;\n            }\n        }\n\n        try {\n            parent::process($container);\n\n            $paths = [];\n            foreach ($this->paths as $class => $_) {\n                if (($r = $container->getReflectionClass($class)) && !$r->isInterface()) {\n                    $paths[] = $r->getFileName();\n                    foreach ($r->getTraits() as $trait) {\n                        $paths[] = $trait->getFileName();\n                    }\n                }\n            }\n            if ($paths) {\n                if ($container->hasDefinition('console.command.translation_debug')) {\n                    $definition = $container->getDefinition('console.command.translation_debug');\n                    $definition->replaceArgument(6, array_merge($definition->getArgument(6), $paths));\n                }\n                if ($container->hasDefinition('console.command.translation_extract')) {\n                    $definition = $container->getDefinition('console.command.translation_extract');\n                    $definition->replaceArgument(7, array_merge($definition->getArgument(7), $paths));\n                }\n            }\n        } finally {\n            $this->level = 0;\n            $this->paths = [];\n            $this->definitions = [];\n        }\n    }\n\n    protected function processValue(mixed $value, bool $isRoot = false): mixed\n    {\n        if ($value instanceof Reference) {\n            if ('translator' === (string) $value) {\n                for ($i = $this->level - 1; $i >= 0; --$i) {\n                    $class = $this->definitions[$i]->getClass();\n\n                    if (ServiceLocator::class === $class) {\n                        if (!isset($this->controllers[$this->currentId ?? ''])) {\n                            continue;\n                        }\n                        foreach ($this->controllers[$this->currentId ?? ''] as $class => $_) {\n                            $this->paths[$class] = true;\n                        }\n                    } else {\n                        $this->paths[$class] = true;\n                    }\n\n                    break;\n                }\n            }\n\n            return $value;\n        }\n\n        if ($value instanceof Definition) {\n            $this->definitions[$this->level++] = $value;\n            $value = parent::processValue($value, $isRoot);\n            unset($this->definitions[--$this->level]);\n\n            return $value;\n        }\n\n        return parent::processValue($value, $isRoot);\n    }\n\n    private function findControllerArguments(ContainerBuilder $container): array\n    {\n        if (!$container->has('argument_resolver.service')) {\n            return [];\n        }\n        $resolverDef = $container->findDefinition('argument_resolver.service');\n\n        if (TraceableValueResolver::class === $resolverDef->getClass()) {\n            $resolverDef = $container->getDefinition($resolverDef->getArgument(0));\n        }\n\n        $argument = $resolverDef->getArgument(0);\n        if ($argument instanceof Reference) {\n            $argument = $container->getDefinition($argument);\n        }\n\n        return $argument->getArgument(0);\n    }\n}\n"
  },
  {
    "path": "Dumper/CsvFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * CsvFileDumper generates a csv formatted string representation of a message catalogue.\n *\n * @author Stealth35\n */\nclass CsvFileDumper extends FileDumper\n{\n    private string $delimiter = ';';\n    private string $enclosure = '\"';\n\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        $handle = fopen('php://memory', 'r+');\n\n        foreach ($messages->all($domain) as $source => $target) {\n            fputcsv($handle, [$source, $target], $this->delimiter, $this->enclosure, '\\\\');\n        }\n\n        rewind($handle);\n        $output = stream_get_contents($handle);\n        fclose($handle);\n\n        return $output;\n    }\n\n    /**\n     * Sets the delimiter and escape character for CSV.\n     */\n    public function setCsvControl(string $delimiter = ';', string $enclosure = '\"'): void\n    {\n        $this->delimiter = $delimiter;\n        $this->enclosure = $enclosure;\n    }\n\n    protected function getExtension(): string\n    {\n        return 'csv';\n    }\n}\n"
  },
  {
    "path": "Dumper/DumperInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * DumperInterface is the interface implemented by all translation dumpers.\n * There is no common option.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\ninterface DumperInterface\n{\n    /**\n     * Dumps the message catalogue.\n     *\n     * @param array $options Options that are used by the dumper\n     */\n    public function dump(MessageCatalogue $messages, array $options = []): void;\n}\n"
  },
  {
    "path": "Dumper/FileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\RuntimeException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * FileDumper is an implementation of DumperInterface that dump a message catalogue to file(s).\n *\n * Options:\n * - path (mandatory): the directory where the files should be saved\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\nabstract class FileDumper implements DumperInterface\n{\n    /**\n     * A template for the relative paths to files.\n     */\n    protected string $relativePathTemplate = '%domain%.%locale%.%extension%';\n\n    /**\n     * Sets the template for the relative paths to files.\n     */\n    public function setRelativePathTemplate(string $relativePathTemplate): void\n    {\n        $this->relativePathTemplate = $relativePathTemplate;\n    }\n\n    public function dump(MessageCatalogue $messages, array $options = []): void\n    {\n        if (!\\array_key_exists('path', $options)) {\n            throw new InvalidArgumentException('The file dumper needs a path option.');\n        }\n\n        // save a file for each domain\n        foreach ($messages->getDomains() as $domain) {\n            $fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale());\n            if (!file_exists($fullpath)) {\n                $directory = \\dirname($fullpath);\n                if (!file_exists($directory) && !@mkdir($directory, 0o777, true)) {\n                    throw new RuntimeException(\\sprintf('Unable to create directory \"%s\".', $directory));\n                }\n            }\n\n            $intlDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX;\n            $intlMessages = $messages->all($intlDomain);\n\n            if ($intlMessages) {\n                $intlPath = $options['path'].'/'.$this->getRelativePath($intlDomain, $messages->getLocale());\n                file_put_contents($intlPath, $this->formatCatalogue($messages, $intlDomain, $options));\n\n                $messages->replace([], $intlDomain);\n\n                try {\n                    if ($messages->all($domain)) {\n                        file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options));\n                    }\n                    continue;\n                } finally {\n                    $messages->replace($intlMessages, $intlDomain);\n                }\n            }\n\n            file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options));\n        }\n    }\n\n    /**\n     * Transforms a domain of a message catalogue to its string representation.\n     */\n    abstract public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string;\n\n    /**\n     * Gets the file extension of the dumper.\n     */\n    abstract protected function getExtension(): string;\n\n    /**\n     * Gets the relative file path using the template.\n     */\n    private function getRelativePath(string $domain, string $locale): string\n    {\n        return strtr($this->relativePathTemplate, [\n            '%domain%' => $domain,\n            '%locale%' => $locale,\n            '%extension%' => $this->getExtension(),\n        ]);\n    }\n}\n"
  },
  {
    "path": "Dumper/IcuResFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue.\n *\n * @author Stealth35\n */\nclass IcuResFileDumper extends FileDumper\n{\n    protected string $relativePathTemplate = '%domain%/%locale%.%extension%';\n\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        $data = $indexes = $resources = '';\n\n        foreach ($messages->all($domain) as $source => $target) {\n            $indexes .= pack('v', \\strlen($data) + 28);\n            $data .= $source.\"\\0\";\n        }\n\n        $data .= $this->writePadding($data);\n\n        $keyTop = $this->getPosition($data);\n\n        foreach ($messages->all($domain) as $source => $target) {\n            $resources .= pack('V', $this->getPosition($data));\n\n            $data .= pack('V', \\strlen($target))\n                .mb_convert_encoding($target.\"\\0\", 'UTF-16LE', 'UTF-8')\n                .$this->writePadding($data)\n            ;\n        }\n\n        $resOffset = $this->getPosition($data);\n\n        $data .= pack('v', \\count($messages->all($domain)))\n            .$indexes\n            .$this->writePadding($data)\n            .$resources\n        ;\n\n        $bundleTop = $this->getPosition($data);\n\n        $root = pack('V7',\n            $resOffset + (2 << 28), // Resource Offset + Resource Type\n            6,                      // Index length\n            $keyTop,                        // Index keys top\n            $bundleTop,                     // Index resources top\n            $bundleTop,                     // Index bundle top\n            \\count($messages->all($domain)), // Index max table length\n            0                               // Index attributes\n        );\n\n        $header = pack('vC2v4C12@32',\n            32,                     // Header size\n            0xDA, 0x27,             // Magic number 1 and 2\n            20, 0, 0, 2,            // Rest of the header, ..., Size of a char\n            0x52, 0x65, 0x73, 0x42, // Data format identifier\n            1, 2, 0, 0,             // Data version\n            1, 4, 0, 0              // Unicode version\n        );\n\n        return $header.$root.$data;\n    }\n\n    private function writePadding(string $data): ?string\n    {\n        $padding = \\strlen($data) % 4;\n\n        return $padding ? str_repeat(\"\\xAA\", 4 - $padding) : null;\n    }\n\n    private function getPosition(string $data): float|int\n    {\n        return (\\strlen($data) + 28) / 4;\n    }\n\n    protected function getExtension(): string\n    {\n        return 'res';\n    }\n}\n"
  },
  {
    "path": "Dumper/IniFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * IniFileDumper generates an ini formatted string representation of a message catalogue.\n *\n * @author Stealth35\n */\nclass IniFileDumper extends FileDumper\n{\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        $output = '';\n\n        foreach ($messages->all($domain) as $source => $target) {\n            $escapeTarget = str_replace('\"', '\\\"', $target);\n            $output .= $source.'=\"'.$escapeTarget.\"\\\"\\n\";\n        }\n\n        return $output;\n    }\n\n    protected function getExtension(): string\n    {\n        return 'ini';\n    }\n}\n"
  },
  {
    "path": "Dumper/JsonFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * JsonFileDumper generates an json formatted string representation of a message catalogue.\n *\n * @author singles\n */\nclass JsonFileDumper extends FileDumper\n{\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        $flags = $options['json_encoding'] ?? \\JSON_PRETTY_PRINT;\n\n        return json_encode($messages->all($domain), $flags);\n    }\n\n    protected function getExtension(): string\n    {\n        return 'json';\n    }\n}\n"
  },
  {
    "path": "Dumper/MoFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\Loader\\MoFileLoader;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * MoFileDumper generates a gettext formatted string representation of a message catalogue.\n *\n * @author Stealth35\n */\nclass MoFileDumper extends FileDumper\n{\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        $sources = $targets = $sourceOffsets = $targetOffsets = '';\n        $offsets = [];\n        $size = 0;\n\n        foreach ($messages->all($domain) as $source => $target) {\n            $offsets[] = array_map('strlen', [$sources, $source, $targets, $target]);\n            $sources .= \"\\0\".$source;\n            $targets .= \"\\0\".$target;\n            ++$size;\n        }\n\n        $header = [\n            'magicNumber' => MoFileLoader::MO_LITTLE_ENDIAN_MAGIC,\n            'formatRevision' => 0,\n            'count' => $size,\n            'offsetId' => MoFileLoader::MO_HEADER_SIZE,\n            'offsetTranslated' => MoFileLoader::MO_HEADER_SIZE + (8 * $size),\n            'sizeHashes' => 0,\n            'offsetHashes' => MoFileLoader::MO_HEADER_SIZE + (16 * $size),\n        ];\n\n        $sourcesSize = \\strlen($sources);\n        $sourcesStart = $header['offsetHashes'] + 1;\n\n        foreach ($offsets as $offset) {\n            $sourceOffsets .= $this->writeLong($offset[1])\n                          .$this->writeLong($offset[0] + $sourcesStart);\n            $targetOffsets .= $this->writeLong($offset[3])\n                          .$this->writeLong($offset[2] + $sourcesStart + $sourcesSize);\n        }\n\n        return implode('', array_map($this->writeLong(...), $header))\n               .$sourceOffsets\n               .$targetOffsets\n               .$sources\n               .$targets;\n    }\n\n    protected function getExtension(): string\n    {\n        return 'mo';\n    }\n\n    private function writeLong(mixed $str): string\n    {\n        return pack('V*', $str);\n    }\n}\n"
  },
  {
    "path": "Dumper/PhpFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * PhpFileDumper generates PHP files from a message catalogue.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\nclass PhpFileDumper extends FileDumper\n{\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        return \"<?php\\n\\nreturn \".var_export($messages->all($domain), true).\";\\n\";\n    }\n\n    protected function getExtension(): string\n    {\n        return 'php';\n    }\n}\n"
  },
  {
    "path": "Dumper/PoFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * PoFileDumper generates a gettext formatted string representation of a message catalogue.\n *\n * @author Stealth35\n */\nclass PoFileDumper extends FileDumper\n{\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        $output = 'msgid \"\"'.\"\\n\";\n        $output .= 'msgstr \"\"'.\"\\n\";\n        $output .= '\"Content-Type: text/plain; charset=UTF-8\\n\"'.\"\\n\";\n        $output .= '\"Content-Transfer-Encoding: 8bit\\n\"'.\"\\n\";\n        $output .= '\"Language: '.$messages->getLocale().'\\n\"'.\"\\n\";\n        $output .= \"\\n\";\n\n        $newLine = false;\n        foreach ($messages->all($domain) as $source => $target) {\n            if ($newLine) {\n                $output .= \"\\n\";\n            } else {\n                $newLine = true;\n            }\n            $metadata = $messages->getMetadata($source, $domain);\n\n            if (isset($metadata['comments'])) {\n                $output .= $this->formatComments($metadata['comments']);\n            }\n            if (isset($metadata['flags'])) {\n                $output .= $this->formatComments(implode(',', (array) $metadata['flags']), ',');\n            }\n            if (isset($metadata['sources'])) {\n                $output .= $this->formatComments(implode(' ', (array) $metadata['sources']), ':');\n            }\n\n            $sourceRules = $this->getStandardRules($source);\n            $targetRules = $this->getStandardRules($target);\n            if (2 == \\count($sourceRules) && [] !== $targetRules) {\n                $output .= \\sprintf('msgid \"%s\"'.\"\\n\", $this->escape($sourceRules[0]));\n                $output .= \\sprintf('msgid_plural \"%s\"'.\"\\n\", $this->escape($sourceRules[1]));\n                foreach ($targetRules as $i => $targetRule) {\n                    $output .= \\sprintf('msgstr[%d] \"%s\"'.\"\\n\", $i, $this->escape($targetRule));\n                }\n            } else {\n                $output .= \\sprintf('msgid \"%s\"'.\"\\n\", $this->escape($source));\n                $output .= \\sprintf('msgstr \"%s\"'.\"\\n\", $this->escape($target));\n            }\n        }\n\n        return $output;\n    }\n\n    private function getStandardRules(string $id): array\n    {\n        // Partly copied from TranslatorTrait::trans.\n        $parts = [];\n        if (preg_match('/^\\|++$/', $id)) {\n            $parts = explode('|', $id);\n        } elseif (preg_match_all('/(?:\\|\\||[^\\|])++/', $id, $matches)) {\n            $parts = $matches[0];\n        }\n\n        $intervalRegexp = <<<'EOF'\n            /^(?P<interval>\n                ({\\s*\n                    (\\-?\\d+(\\.\\d+)?[\\s*,\\s*\\-?\\d+(\\.\\d+)?]*)\n                \\s*})\n\n                    |\n\n                (?P<left_delimiter>[\\[\\]])\n                    \\s*\n                    (?P<left>-Inf|\\-?\\d+(\\.\\d+)?)\n                    \\s*,\\s*\n                    (?P<right>\\+?Inf|\\-?\\d+(\\.\\d+)?)\n                    \\s*\n                (?P<right_delimiter>[\\[\\]])\n            )\\s*(?P<message>.*?)$/xs\n            EOF;\n\n        $standardRules = [];\n        foreach ($parts as $part) {\n            $part = trim(str_replace('||', '|', $part));\n\n            if (preg_match($intervalRegexp, $part)) {\n                // Explicit rule is not a standard rule.\n                return [];\n            }\n\n            $standardRules[] = $part;\n        }\n\n        return $standardRules;\n    }\n\n    protected function getExtension(): string\n    {\n        return 'po';\n    }\n\n    private function escape(string $str): string\n    {\n        return addcslashes($str, \"\\0..\\37\\42\\134\");\n    }\n\n    private function formatComments(string|array $comments, string $prefix = ''): ?string\n    {\n        $output = null;\n\n        foreach ((array) $comments as $comment) {\n            $output .= \\sprintf('#%s %s'.\"\\n\", $prefix, $comment);\n        }\n\n        return $output;\n    }\n}\n"
  },
  {
    "path": "Dumper/QtFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * QtFileDumper generates ts files from a message catalogue.\n *\n * @author Benjamin Eberlei <kontakt@beberlei.de>\n */\nclass QtFileDumper extends FileDumper\n{\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        $dom = new \\DOMDocument('1.0', 'utf-8');\n        $dom->formatOutput = true;\n        $ts = $dom->appendChild($dom->createElement('TS'));\n        $context = $ts->appendChild($dom->createElement('context'));\n        $context->appendChild($dom->createElement('name', $domain));\n\n        foreach ($messages->all($domain) as $source => $target) {\n            $message = $context->appendChild($dom->createElement('message'));\n            $metadata = $messages->getMetadata($source, $domain);\n            if (isset($metadata['sources'])) {\n                foreach ((array) $metadata['sources'] as $location) {\n                    $loc = explode(':', $location, 2);\n                    $location = $message->appendChild($dom->createElement('location'));\n                    $location->setAttribute('filename', $loc[0]);\n                    if (isset($loc[1])) {\n                        $location->setAttribute('line', $loc[1]);\n                    }\n                }\n            }\n            $message->appendChild($dom->createElement('source', $source));\n            $message->appendChild($dom->createElement('translation', $target));\n        }\n\n        return $dom->saveXML();\n    }\n\n    protected function getExtension(): string\n    {\n        return 'ts';\n    }\n}\n"
  },
  {
    "path": "Dumper/XliffFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * XliffFileDumper generates xliff files from a message catalogue.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\nclass XliffFileDumper extends FileDumper\n{\n    public function __construct(\n        private string $extension = 'xlf',\n    ) {\n    }\n\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        $xliffVersion = '1.2';\n        if (\\array_key_exists('xliff_version', $options)) {\n            $xliffVersion = $options['xliff_version'];\n        }\n\n        if (\\array_key_exists('default_locale', $options)) {\n            $defaultLocale = $options['default_locale'];\n        } else {\n            $defaultLocale = \\Locale::getDefault();\n        }\n\n        if ('1.2' === $xliffVersion) {\n            return $this->dumpXliff1($defaultLocale, $messages, $domain, $options);\n        }\n        if ('2.0' === $xliffVersion) {\n            return $this->dumpXliff2($defaultLocale, $messages, $domain);\n        }\n\n        throw new InvalidArgumentException(\\sprintf('No support implemented for dumping XLIFF version \"%s\".', $xliffVersion));\n    }\n\n    protected function getExtension(): string\n    {\n        return $this->extension;\n    }\n\n    private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = []): string\n    {\n        $toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony'];\n        if (\\array_key_exists('tool_info', $options)) {\n            $toolInfo = array_merge($toolInfo, $options['tool_info']);\n        }\n\n        $dom = new \\DOMDocument('1.0', 'utf-8');\n        $dom->formatOutput = true;\n\n        $xliff = $dom->appendChild($dom->createElement('xliff'));\n        $xliff->setAttribute('version', '1.2');\n        $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2');\n\n        $xliffFile = $xliff->appendChild($dom->createElement('file'));\n        $xliffFile->setAttribute('source-language', str_replace('_', '-', $defaultLocale));\n        $xliffFile->setAttribute('target-language', str_replace('_', '-', $messages->getLocale()));\n        $xliffFile->setAttribute('datatype', 'plaintext');\n        $xliffFile->setAttribute('original', 'file.ext');\n\n        $xliffHead = $xliffFile->appendChild($dom->createElement('header'));\n        $xliffTool = $xliffHead->appendChild($dom->createElement('tool'));\n        foreach ($toolInfo as $id => $value) {\n            $xliffTool->setAttribute($id, $value);\n        }\n\n        if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) {\n            $xliffPropGroup = $xliffHead->appendChild($dom->createElement('prop-group'));\n            foreach ($catalogueMetadata as $key => $value) {\n                $xliffProp = $xliffPropGroup->appendChild($dom->createElement('prop'));\n                $xliffProp->setAttribute('prop-type', $key);\n                $xliffProp->appendChild($dom->createTextNode($value));\n            }\n        }\n\n        $xliffBody = $xliffFile->appendChild($dom->createElement('body'));\n        foreach ($messages->all($domain) as $source => $target) {\n            $translation = $dom->createElement('trans-unit');\n\n            $translation->setAttribute('id', strtr(substr(base64_encode(hash('xxh128', $source, true)), 0, 7), '/+', '._'));\n            $translation->setAttribute('resname', $source);\n\n            $s = $translation->appendChild($dom->createElement('source'));\n            $s->appendChild($dom->createTextNode($source));\n\n            // Does the target contain characters requiring a CDATA section?\n            $text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target);\n\n            $targetElement = $dom->createElement('target');\n            $metadata = $messages->getMetadata($source, $domain);\n            if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) {\n                foreach ($metadata['target-attributes'] as $name => $value) {\n                    $targetElement->setAttribute($name, $value);\n                }\n            }\n            $t = $translation->appendChild($targetElement);\n            $t->appendChild($text);\n\n            if ($this->hasMetadataArrayInfo('notes', $metadata)) {\n                foreach ($metadata['notes'] as $note) {\n                    if (!isset($note['content'])) {\n                        continue;\n                    }\n\n                    $n = $translation->appendChild($dom->createElement('note'));\n                    $n->appendChild($dom->createTextNode($note['content']));\n\n                    if (isset($note['priority'])) {\n                        $n->setAttribute('priority', $note['priority']);\n                    }\n\n                    if (isset($note['from'])) {\n                        $n->setAttribute('from', $note['from']);\n                    }\n                }\n            }\n\n            $xliffBody->appendChild($translation);\n        }\n\n        return $dom->saveXML();\n    }\n\n    private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain): string\n    {\n        $dom = new \\DOMDocument('1.0', 'utf-8');\n        $dom->formatOutput = true;\n\n        $xliff = $dom->appendChild($dom->createElement('xliff'));\n        $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:2.0');\n        $xliff->setAttribute('version', '2.0');\n        $xliff->setAttribute('srcLang', str_replace('_', '-', $defaultLocale));\n        $xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale()));\n\n        $xliffFile = $xliff->appendChild($dom->createElement('file'));\n        if (str_ends_with($domain, MessageCatalogue::INTL_DOMAIN_SUFFIX)) {\n            $xliffFile->setAttribute('id', substr($domain, 0, -\\strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX)).'.'.$messages->getLocale());\n        } else {\n            $xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale());\n        }\n\n        if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) {\n            $xliff->setAttribute('xmlns:m', 'urn:oasis:names:tc:xliff:metadata:2.0');\n            $xliffMetadata = $xliffFile->appendChild($dom->createElement('m:metadata'));\n            foreach ($catalogueMetadata as $key => $value) {\n                $xliffMeta = $xliffMetadata->appendChild($dom->createElement('prop'));\n                $xliffMeta->setAttribute('type', $key);\n                $xliffMeta->appendChild($dom->createTextNode($value));\n            }\n        }\n\n        foreach ($messages->all($domain) as $source => $target) {\n            $translation = $dom->createElement('unit');\n            $translation->setAttribute('id', strtr(substr(base64_encode(hash('xxh128', $source, true)), 0, 7), '/+', '._'));\n\n            if (\\strlen($source) <= 80) {\n                $translation->setAttribute('name', $source);\n            }\n\n            $metadata = $messages->getMetadata($source, $domain);\n\n            // Add notes section\n            if ($this->hasMetadataArrayInfo('notes', $metadata) && $metadata['notes']) {\n                $notesElement = $dom->createElement('notes');\n                foreach ($metadata['notes'] as $note) {\n                    $n = $dom->createElement('note');\n                    $n->appendChild($dom->createTextNode($note['content'] ?? ''));\n                    unset($note['content']);\n\n                    foreach ($note as $name => $value) {\n                        $n->setAttribute($name, $value);\n                    }\n                    $notesElement->appendChild($n);\n                }\n                $translation->appendChild($notesElement);\n            }\n\n            $segment = $translation->appendChild($dom->createElement('segment'));\n\n            if ($this->hasMetadataArrayInfo('segment-attributes', $metadata)) {\n                foreach ($metadata['segment-attributes'] as $name => $value) {\n                    $segment->setAttribute($name, $value);\n                }\n            }\n\n            $s = $segment->appendChild($dom->createElement('source'));\n            $s->appendChild($dom->createTextNode($source));\n\n            // Does the target contain characters requiring a CDATA section?\n            $text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target);\n\n            $targetElement = $dom->createElement('target');\n            if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) {\n                foreach ($metadata['target-attributes'] as $name => $value) {\n                    $targetElement->setAttribute($name, $value);\n                }\n            }\n            $t = $segment->appendChild($targetElement);\n            $t->appendChild($text);\n\n            $xliffFile->appendChild($translation);\n        }\n\n        return $dom->saveXML();\n    }\n\n    private function hasMetadataArrayInfo(string $key, ?array $metadata = null): bool\n    {\n        return is_iterable($metadata[$key] ?? null);\n    }\n}\n"
  },
  {
    "path": "Dumper/YamlFileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\Util\\ArrayConverter;\nuse Symfony\\Component\\Yaml\\Yaml;\n\n/**\n * YamlFileDumper generates yaml files from a message catalogue.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\nclass YamlFileDumper extends FileDumper\n{\n    public function __construct(\n        private string $extension = 'yml',\n    ) {\n    }\n\n    public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string\n    {\n        if (!class_exists(Yaml::class)) {\n            throw new LogicException('Dumping translations in the YAML format requires the Symfony Yaml component.');\n        }\n\n        $data = $messages->all($domain);\n\n        if (isset($options['as_tree']) && $options['as_tree']) {\n            $data = ArrayConverter::expandToTree($data);\n        }\n\n        if (isset($options['inline']) && ($inline = (int) $options['inline']) > 0) {\n            return Yaml::dump($data, $inline);\n        }\n\n        return Yaml::dump($data);\n    }\n\n    protected function getExtension(): string\n    {\n        return $this->extension;\n    }\n}\n"
  },
  {
    "path": "Exception/ExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\n/**\n * Exception interface for all exceptions thrown by the component.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface ExceptionInterface extends \\Throwable\n{\n}\n"
  },
  {
    "path": "Exception/IncompleteDsnException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\nclass IncompleteDsnException extends InvalidArgumentException\n{\n    public function __construct(string $message, ?string $dsn = null, ?\\Throwable $previous = null)\n    {\n        if ($dsn) {\n            $message = \\sprintf('Invalid \"%s\" provider DSN: ', $dsn).$message;\n        }\n\n        parent::__construct($message, 0, $previous);\n    }\n}\n"
  },
  {
    "path": "Exception/InvalidArgumentException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\n/**\n * Base InvalidArgumentException for the Translation component.\n *\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass InvalidArgumentException extends \\InvalidArgumentException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "Exception/InvalidResourceException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\n/**\n * Thrown when a resource cannot be loaded.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass InvalidResourceException extends \\InvalidArgumentException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "Exception/LogicException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\n/**\n * Base LogicException for Translation component.\n *\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass LogicException extends \\LogicException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "Exception/MissingRequiredOptionException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\n/**\n * @author Oskar Stark <oskarstark@googlemail.com>\n */\nclass MissingRequiredOptionException extends IncompleteDsnException\n{\n    public function __construct(string $option, ?string $dsn = null, ?\\Throwable $previous = null)\n    {\n        $message = \\sprintf('The option \"%s\" is required but missing.', $option);\n\n        parent::__construct($message, $dsn, $previous);\n    }\n}\n"
  },
  {
    "path": "Exception/NotFoundResourceException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\n/**\n * Thrown when a resource does not exist.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass NotFoundResourceException extends \\InvalidArgumentException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "Exception/ProviderException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ProviderException extends RuntimeException implements ProviderExceptionInterface\n{\n    private string $debug;\n\n    public function __construct(\n        string $message,\n        private ResponseInterface $response,\n        int $code = 0,\n        ?\\Exception $previous = null,\n    ) {\n        $this->debug = $response->getInfo('debug') ?? '';\n\n        parent::__construct($message, $code, $previous);\n    }\n\n    public function getResponse(): ResponseInterface\n    {\n        return $this->response;\n    }\n\n    public function getDebug(): string\n    {\n        return $this->debug;\n    }\n}\n"
  },
  {
    "path": "Exception/ProviderExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface ProviderExceptionInterface extends ExceptionInterface\n{\n    /*\n     * Returns debug info coming from the Symfony\\Contracts\\HttpClient\\ResponseInterface\n     */\n    public function getDebug(): string;\n}\n"
  },
  {
    "path": "Exception/RuntimeException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\n/**\n * Base RuntimeException for the Translation component.\n *\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass RuntimeException extends \\RuntimeException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "Exception/UnsupportedSchemeException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Exception;\n\nuse Symfony\\Component\\Translation\\Bridge;\nuse Symfony\\Component\\Translation\\Provider\\Dsn;\n\nclass UnsupportedSchemeException extends LogicException\n{\n    private const SCHEME_TO_PACKAGE_MAP = [\n        'crowdin' => [\n            'class' => Bridge\\Crowdin\\CrowdinProviderFactory::class,\n            'package' => 'symfony/crowdin-translation-provider',\n        ],\n        'loco' => [\n            'class' => Bridge\\Loco\\LocoProviderFactory::class,\n            'package' => 'symfony/loco-translation-provider',\n        ],\n        'lokalise' => [\n            'class' => Bridge\\Lokalise\\LokaliseProviderFactory::class,\n            'package' => 'symfony/lokalise-translation-provider',\n        ],\n        'phrase' => [\n            'class' => Bridge\\Phrase\\PhraseProviderFactory::class,\n            'package' => 'symfony/phrase-translation-provider',\n        ],\n    ];\n\n    public function __construct(Dsn $dsn, ?string $name = null, array $supported = [])\n    {\n        $provider = $dsn->getScheme();\n        if (false !== $pos = strpos($provider, '+')) {\n            $provider = substr($provider, 0, $pos);\n        }\n        $package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null;\n        if ($package && !class_exists($package['class'])) {\n            parent::__construct(\\sprintf('Unable to synchronize translations via \"%s\" as the provider is not installed. Try running \"composer require %s\".', $provider, $package['package']));\n\n            return;\n        }\n\n        $message = \\sprintf('The \"%s\" scheme is not supported', $dsn->getScheme());\n        if ($name && $supported) {\n            $message .= \\sprintf('; supported schemes for translation provider \"%s\" are: \"%s\"', $name, implode('\", \"', $supported));\n        }\n\n        parent::__construct($message.'.');\n    }\n}\n"
  },
  {
    "path": "Extractor/AbstractFileExtractor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Extractor;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\n\n/**\n * Base class used by classes that extract translation messages from files.\n *\n * @author Marcos D. Sánchez <marcosdsanchez@gmail.com>\n */\nabstract class AbstractFileExtractor\n{\n    protected function extractFiles(string|iterable $resource): iterable\n    {\n        if (is_iterable($resource)) {\n            $files = [];\n            foreach ($resource as $file) {\n                if ($this->canBeExtracted($file)) {\n                    $files[] = $this->toSplFileInfo($file);\n                }\n            }\n        } elseif (is_file($resource)) {\n            $files = $this->canBeExtracted($resource) ? [$this->toSplFileInfo($resource)] : [];\n        } else {\n            $files = $this->extractFromDirectory($resource);\n        }\n\n        return $files;\n    }\n\n    private function toSplFileInfo(string $file): \\SplFileInfo\n    {\n        return new \\SplFileInfo($file);\n    }\n\n    /**\n     * @throws InvalidArgumentException\n     */\n    protected function isFile(string $file): bool\n    {\n        if (!is_file($file)) {\n            throw new InvalidArgumentException(\\sprintf('The \"%s\" file does not exist.', $file));\n        }\n\n        return true;\n    }\n\n    abstract protected function canBeExtracted(string $file): bool;\n\n    abstract protected function extractFromDirectory(string|array $resource): iterable;\n}\n"
  },
  {
    "path": "Extractor/ChainExtractor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Extractor;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * ChainExtractor extracts translation messages from template files.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\nclass ChainExtractor implements ExtractorInterface\n{\n    /**\n     * The extractors.\n     *\n     * @var ExtractorInterface[]\n     */\n    private array $extractors = [];\n\n    /**\n     * Adds a loader to the translation extractor.\n     */\n    public function addExtractor(string $format, ExtractorInterface $extractor): void\n    {\n        $this->extractors[$format] = $extractor;\n    }\n\n    public function setPrefix(string $prefix): void\n    {\n        foreach ($this->extractors as $extractor) {\n            $extractor->setPrefix($prefix);\n        }\n    }\n\n    public function extract(string|iterable $directory, MessageCatalogue $catalogue): void\n    {\n        foreach ($this->extractors as $extractor) {\n            $extractor->extract($directory, $catalogue);\n        }\n    }\n}\n"
  },
  {
    "path": "Extractor/ExtractorInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Extractor;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * Extracts translation messages from a directory or files to the catalogue.\n * New found messages are injected to the catalogue using the prefix.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\ninterface ExtractorInterface\n{\n    /**\n     * Extracts translation messages from files, a file or a directory to the catalogue.\n     *\n     * @param string|iterable<string> $resource Files, a file or a directory\n     */\n    public function extract(string|iterable $resource, MessageCatalogue $catalogue): void;\n\n    /**\n     * Sets the prefix that should be used for new found messages.\n     */\n    public function setPrefix(string $prefix): void;\n}\n"
  },
  {
    "path": "Extractor/PhpAstExtractor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Extractor;\n\nuse PhpParser\\NodeTraverser;\nuse PhpParser\\NodeVisitor;\nuse PhpParser\\Parser;\nuse PhpParser\\ParserFactory;\nuse Symfony\\Component\\Finder\\Finder;\nuse Symfony\\Component\\Translation\\Extractor\\Visitor\\AbstractVisitor;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * PhpAstExtractor extracts translation messages from a PHP AST.\n *\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nfinal class PhpAstExtractor extends AbstractFileExtractor implements ExtractorInterface\n{\n    private Parser $parser;\n\n    public function __construct(\n        /**\n         * @param iterable<AbstractVisitor&NodeVisitor> $visitors\n         */\n        private readonly iterable $visitors,\n        private string $prefix = '',\n    ) {\n        if (!class_exists(ParserFactory::class)) {\n            throw new \\LogicException(\\sprintf('You cannot use \"%s\" as the \"nikic/php-parser\" package is not installed. Try running \"composer require nikic/php-parser\".', static::class));\n        }\n\n        $this->parser = (new ParserFactory())->createForHostVersion();\n    }\n\n    public function extract(iterable|string $resource, MessageCatalogue $catalogue): void\n    {\n        foreach ($this->extractFiles($resource) as $file) {\n            $traverser = new NodeTraverser();\n\n            // This is needed to resolve namespaces in class methods/constants.\n            $nameResolver = new NodeVisitor\\NameResolver();\n            $traverser->addVisitor($nameResolver);\n\n            foreach ($this->visitors as $visitor) {\n                $visitor->initialize($catalogue, $file, $this->prefix);\n                $traverser->addVisitor($visitor);\n            }\n\n            $nodes = $this->parser->parse(file_get_contents($file));\n            $traverser->traverse($nodes);\n        }\n    }\n\n    public function setPrefix(string $prefix): void\n    {\n        $this->prefix = $prefix;\n    }\n\n    protected function canBeExtracted(string $file): bool\n    {\n        return 'php' === pathinfo($file, \\PATHINFO_EXTENSION)\n            && $this->isFile($file)\n            && preg_match('/\\bt\\(|->trans\\(|TranslatableMessage|Symfony\\\\\\\\Component\\\\\\\\Validator\\\\\\\\Constraints/i', file_get_contents($file));\n    }\n\n    protected function extractFromDirectory(array|string $resource): iterable|Finder\n    {\n        if (!class_exists(Finder::class)) {\n            throw new \\LogicException(\\sprintf('You cannot use \"%s\" as the \"symfony/finder\" package is not installed. Try running \"composer require symfony/finder\".', static::class));\n        }\n\n        return (new Finder())->files()->name('*.php')->in($resource);\n    }\n}\n"
  },
  {
    "path": "Extractor/Visitor/AbstractVisitor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Extractor\\Visitor;\n\nuse PhpParser\\Node;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nabstract class AbstractVisitor\n{\n    private MessageCatalogue $catalogue;\n    private \\SplFileInfo $file;\n    private string $messagePrefix;\n\n    public function initialize(MessageCatalogue $catalogue, \\SplFileInfo $file, string $messagePrefix): void\n    {\n        $this->catalogue = $catalogue;\n        $this->file = $file;\n        $this->messagePrefix = $messagePrefix;\n    }\n\n    protected function addMessageToCatalogue(string $message, ?string $domain, int $line): void\n    {\n        $domain ??= 'messages';\n        $this->catalogue->set($message, $this->messagePrefix.$message, $domain);\n        $metadata = $this->catalogue->getMetadata($message, $domain) ?? [];\n        $normalizedFilename = preg_replace('{[\\\\\\\\/]+}', '/', $this->file);\n        $metadata['sources'][] = $normalizedFilename.':'.$line;\n        $this->catalogue->setMetadata($message, $metadata, $domain);\n    }\n\n    protected function getStringArguments(Node\\Expr\\CallLike|Node\\Attribute|Node\\Expr\\New_ $node, int|string $index, bool $indexIsRegex = false): array\n    {\n        if (\\is_string($index)) {\n            return $this->getStringNamedArguments($node, $index, $indexIsRegex);\n        }\n\n        $args = $node instanceof Node\\Expr\\CallLike ? $node->getRawArgs() : $node->args;\n\n        if (!($arg = $args[$index] ?? null) instanceof Node\\Arg) {\n            return [];\n        }\n\n        return (array) $this->getStringValue($arg->value);\n    }\n\n    protected function hasNodeNamedArguments(Node\\Expr\\CallLike|Node\\Attribute|Node\\Expr\\New_ $node): bool\n    {\n        $args = $node instanceof Node\\Expr\\CallLike ? $node->getRawArgs() : $node->args;\n\n        foreach ($args as $arg) {\n            if ($arg instanceof Node\\Arg && null !== $arg->name) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    protected function nodeFirstNamedArgumentIndex(Node\\Expr\\CallLike|Node\\Attribute|Node\\Expr\\New_ $node): int\n    {\n        $args = $node instanceof Node\\Expr\\CallLike ? $node->getRawArgs() : $node->args;\n\n        foreach ($args as $i => $arg) {\n            if ($arg instanceof Node\\Arg && null !== $arg->name) {\n                return $i;\n            }\n        }\n\n        return \\PHP_INT_MAX;\n    }\n\n    private function getStringNamedArguments(Node\\Expr\\CallLike|Node\\Attribute $node, ?string $argumentName = null, bool $isArgumentNamePattern = false): array\n    {\n        $args = $node instanceof Node\\Expr\\CallLike ? $node->getArgs() : $node->args;\n        $argumentValues = [];\n\n        foreach ($args as $arg) {\n            if (!$isArgumentNamePattern && $arg->name?->toString() === $argumentName) {\n                $argumentValues[] = $this->getStringValue($arg->value);\n            } elseif ($isArgumentNamePattern && preg_match($argumentName, $arg->name?->toString() ?? '') > 0) {\n                $argumentValues[] = $this->getStringValue($arg->value);\n            }\n        }\n\n        return array_filter($argumentValues);\n    }\n\n    private function getStringValue(Node $node): ?string\n    {\n        if ($node instanceof Node\\Scalar\\String_) {\n            return $node->value;\n        }\n\n        if ($node instanceof Node\\Expr\\BinaryOp\\Concat) {\n            if (null === $left = $this->getStringValue($node->left)) {\n                return null;\n            }\n\n            if (null === $right = $this->getStringValue($node->right)) {\n                return null;\n            }\n\n            return $left.$right;\n        }\n\n        if ($node instanceof Node\\Expr\\Assign && $node->expr instanceof Node\\Scalar\\String_) {\n            return $node->expr->value;\n        }\n\n        if ($node instanceof Node\\Expr\\ClassConstFetch) {\n            try {\n                $reflection = new \\ReflectionClass($node->class->toString());\n                $constant = $reflection->getReflectionConstant($node->name->toString());\n                if (false !== $constant && \\is_string($constant->getValue())) {\n                    return $constant->getValue();\n                }\n            } catch (\\ReflectionException) {\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "Extractor/Visitor/ConstraintVisitor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Extractor\\Visitor;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitor;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n *\n * Code mostly comes from https://github.com/php-translation/extractor/blob/master/src/Visitor/Php/Symfony/Constraint.php\n */\nfinal class ConstraintVisitor extends AbstractVisitor implements NodeVisitor\n{\n    public function __construct(\n        private readonly array $constraintClassNames = [],\n    ) {\n    }\n\n    public function beforeTraverse(array $nodes): ?Node\n    {\n        return null;\n    }\n\n    public function enterNode(Node $node): ?Node\n    {\n        return null;\n    }\n\n    public function leaveNode(Node $node): ?Node\n    {\n        if (!$node instanceof Node\\Expr\\New_ && !$node instanceof Node\\Attribute) {\n            return null;\n        }\n\n        $className = $node instanceof Node\\Attribute ? $node->name : $node->class;\n        if (!$className instanceof Node\\Name) {\n            return null;\n        }\n\n        $parts = $className->getParts();\n        $isConstraintClass = false;\n\n        foreach ($parts as $part) {\n            if (\\in_array($part, $this->constraintClassNames, true)) {\n                $isConstraintClass = true;\n\n                break;\n            }\n        }\n\n        if (!$isConstraintClass) {\n            return null;\n        }\n\n        $arg = $node->args[0] ?? null;\n        if (!$arg instanceof Node\\Arg) {\n            return null;\n        }\n\n        if ($this->hasNodeNamedArguments($node)) {\n            $messages = $this->getStringArguments($node, '/message/i', true);\n        } else {\n            if (!$arg->value instanceof Node\\Expr\\Array_) {\n                // There is no way to guess which argument is a message to be translated.\n                return null;\n            }\n\n            $messages = [];\n            $options = $arg->value;\n\n            foreach ($options->items as $item) {\n                if (!$item->key instanceof Node\\Scalar\\String_) {\n                    continue;\n                }\n\n                if (false === stripos($item->key->value ?? '', 'message')) {\n                    continue;\n                }\n\n                if (!$item->value instanceof Node\\Scalar\\String_) {\n                    continue;\n                }\n\n                $messages[] = $item->value->value;\n\n                break;\n            }\n        }\n\n        foreach ($messages as $message) {\n            $this->addMessageToCatalogue($message, 'validators', $node->getStartLine());\n        }\n\n        return null;\n    }\n\n    public function afterTraverse(array $nodes): ?Node\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "Extractor/Visitor/TransMethodVisitor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Extractor\\Visitor;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitor;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nfinal class TransMethodVisitor extends AbstractVisitor implements NodeVisitor\n{\n    public function beforeTraverse(array $nodes): ?Node\n    {\n        return null;\n    }\n\n    public function enterNode(Node $node): ?Node\n    {\n        return null;\n    }\n\n    public function leaveNode(Node $node): ?Node\n    {\n        if (!$node instanceof Node\\Expr\\MethodCall && !$node instanceof Node\\Expr\\FuncCall) {\n            return null;\n        }\n\n        if (!\\is_string($node->name) && !$node->name instanceof Node\\Identifier && !$node->name instanceof Node\\Name) {\n            return null;\n        }\n\n        $name = $node->name instanceof Node\\Name ? $node->name->getLast() : (string) $node->name;\n\n        if ('trans' === $name || 't' === $name) {\n            $firstNamedArgumentIndex = $this->nodeFirstNamedArgumentIndex($node);\n\n            if (!$messages = $this->getStringArguments($node, 0 < $firstNamedArgumentIndex ? 0 : 'id')) {\n                return null;\n            }\n\n            $domain = $this->getStringArguments($node, 2 < $firstNamedArgumentIndex ? 2 : 'domain')[0] ?? null;\n\n            foreach ($messages as $message) {\n                $this->addMessageToCatalogue($message, $domain, $node->getStartLine());\n            }\n        }\n\n        return null;\n    }\n\n    public function afterTraverse(array $nodes): ?Node\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "Extractor/Visitor/TranslatableMessageVisitor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Extractor\\Visitor;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitor;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nfinal class TranslatableMessageVisitor extends AbstractVisitor implements NodeVisitor\n{\n    public function beforeTraverse(array $nodes): ?Node\n    {\n        return null;\n    }\n\n    public function enterNode(Node $node): ?Node\n    {\n        return null;\n    }\n\n    public function leaveNode(Node $node): ?Node\n    {\n        if (!$node instanceof Node\\Expr\\New_) {\n            return null;\n        }\n\n        if (!($className = $node->class) instanceof Node\\Name) {\n            return null;\n        }\n\n        if (!\\in_array('TranslatableMessage', $className->getParts(), true)) {\n            return null;\n        }\n\n        $firstNamedArgumentIndex = $this->nodeFirstNamedArgumentIndex($node);\n\n        if (!$messages = $this->getStringArguments($node, 0 < $firstNamedArgumentIndex ? 0 : 'message')) {\n            return null;\n        }\n\n        $domain = $this->getStringArguments($node, 2 < $firstNamedArgumentIndex ? 2 : 'domain')[0] ?? null;\n\n        foreach ($messages as $message) {\n            $this->addMessageToCatalogue($message, $domain, $node->getStartLine());\n        }\n\n        return null;\n    }\n\n    public function afterTraverse(array $nodes): ?Node\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "Formatter/IntlFormatter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Formatter;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\n\n/**\n * @author Guilherme Blanco <guilhermeblanco@hotmail.com>\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass IntlFormatter implements IntlFormatterInterface\n{\n    private bool $hasMessageFormatter;\n    private array $cache = [];\n\n    public function formatIntl(string $message, string $locale, array $parameters = []): string\n    {\n        // MessageFormatter constructor throws an exception if the message is empty\n        if ('' === $message) {\n            return '';\n        }\n\n        if (!$formatter = $this->cache[$locale][$message] ?? null) {\n            if (!$this->hasMessageFormatter ??= class_exists(\\MessageFormatter::class)) {\n                throw new LogicException('Cannot parse message translation: please install the \"intl\" PHP extension or the \"symfony/polyfill-intl-messageformatter\" package.');\n            }\n            try {\n                $this->cache[$locale][$message] = $formatter = new \\MessageFormatter($locale, $message);\n            } catch (\\IntlException $e) {\n                throw new InvalidArgumentException(\\sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e);\n            }\n        }\n\n        foreach ($parameters as $key => $value) {\n            if (\\in_array($key[0] ?? null, ['%', '{'], true)) {\n                unset($parameters[$key]);\n                $parameters[trim($key, '%{ }')] = $value;\n            }\n        }\n\n        if (false === $message = $formatter->format($parameters)) {\n            throw new InvalidArgumentException(\\sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage());\n        }\n\n        return $message;\n    }\n}\n"
  },
  {
    "path": "Formatter/IntlFormatterInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Formatter;\n\n/**\n * Formats ICU message patterns.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface IntlFormatterInterface\n{\n    /**\n     * Formats a localized message using rules defined by ICU MessageFormat.\n     *\n     * @see http://icu-project.org/apiref/icu4c/classMessageFormat.html#details\n     */\n    public function formatIntl(string $message, string $locale, array $parameters = []): string;\n}\n"
  },
  {
    "path": "Formatter/MessageFormatter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Formatter;\n\nuse Symfony\\Component\\Translation\\IdentityTranslator;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n// Help opcache.preload discover always-needed symbols\nclass_exists(IntlFormatter::class);\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass MessageFormatter implements MessageFormatterInterface, IntlFormatterInterface\n{\n    private TranslatorInterface $translator;\n    private IntlFormatterInterface $intlFormatter;\n\n    /**\n     * @param TranslatorInterface|null $translator An identity translator to use as selector for pluralization\n     */\n    public function __construct(?TranslatorInterface $translator = null, ?IntlFormatterInterface $intlFormatter = null)\n    {\n        $this->translator = $translator ?? new IdentityTranslator();\n        $this->intlFormatter = $intlFormatter ?? new IntlFormatter();\n    }\n\n    public function format(string $message, string $locale, array $parameters = []): string\n    {\n        return $this->translator->trans($message, $parameters, null, $locale);\n    }\n\n    public function formatIntl(string $message, string $locale, array $parameters = []): string\n    {\n        return $this->intlFormatter->formatIntl($message, $locale, $parameters);\n    }\n}\n"
  },
  {
    "path": "Formatter/MessageFormatterInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Formatter;\n\n/**\n * @author Guilherme Blanco <guilhermeblanco@hotmail.com>\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\ninterface MessageFormatterInterface\n{\n    /**\n     * Formats a localized message pattern with given arguments.\n     *\n     * @param string $message    The message (may also be an object that can be cast to string)\n     * @param string $locale     The message locale\n     * @param array  $parameters An array of parameters for the message\n     */\n    public function format(string $message, string $locale, array $parameters = []): string;\n}\n"
  },
  {
    "path": "IdentityTranslator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorTrait;\n\n/**\n * IdentityTranslator does not translate anything.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass IdentityTranslator implements TranslatorInterface, LocaleAwareInterface\n{\n    use TranslatorTrait;\n\n    public function setLocale(string $locale): void\n    {\n        $this->locale = $locale;\n    }\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2004-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Loader/ArrayLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * ArrayLoader loads translations from a PHP array.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ArrayLoader implements LoaderInterface\n{\n    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue\n    {\n        $resource = $this->flatten($resource);\n        $catalogue = new MessageCatalogue($locale);\n        $catalogue->add($resource, $domain);\n\n        return $catalogue;\n    }\n\n    /**\n     * Flattens an nested array of translations.\n     *\n     * The scheme used is:\n     *   'key' => ['key2' => ['key3' => 'value']]\n     * Becomes:\n     *   'key.key2.key3' => 'value'\n     */\n    private function flatten(array $messages): array\n    {\n        $result = [];\n        foreach ($messages as $key => $value) {\n            if (\\is_array($value)) {\n                foreach ($this->flatten($value) as $k => $v) {\n                    if (null !== $v) {\n                        $result[$key.'.'.$k] = $v;\n                    }\n                }\n            } elseif (null !== $value) {\n                $result[$key] = $value;\n            }\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "Loader/CsvFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\n\n/**\n * CsvFileLoader loads translations from CSV files.\n *\n * @author Saša Stamenković <umpirsky@gmail.com>\n */\nclass CsvFileLoader extends FileLoader\n{\n    private string $delimiter = ';';\n    private string $enclosure = '\"';\n\n    protected function loadResource(string $resource): array\n    {\n        $messages = [];\n\n        try {\n            $file = new \\SplFileObject($resource, 'rb');\n        } catch (\\RuntimeException $e) {\n            throw new NotFoundResourceException(\\sprintf('Error opening file \"%s\".', $resource), 0, $e);\n        }\n\n        $file->setFlags(\\SplFileObject::READ_CSV | \\SplFileObject::SKIP_EMPTY | \\SplFileObject::DROP_NEW_LINE);\n        $file->setCsvControl($this->delimiter, $this->enclosure, '');\n\n        foreach ($file as $data) {\n            if (false === $data) {\n                continue;\n            }\n\n            if (!str_starts_with($data[0], '#') && isset($data[1]) && 2 === \\count($data)) {\n                $messages[$data[0]] = $data[1];\n            }\n        }\n\n        return $messages;\n    }\n\n    /**\n     * Sets the delimiter and enclosure character for CSV.\n     */\n    public function setCsvControl(string $delimiter = ';', string $enclosure = '\"'): void\n    {\n        $this->delimiter = $delimiter;\n        $this->enclosure = $enclosure;\n    }\n}\n"
  },
  {
    "path": "Loader/FileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nabstract class FileLoader extends ArrayLoader\n{\n    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue\n    {\n        if (!stream_is_local($resource)) {\n            throw new InvalidResourceException(\\sprintf('This is not a local file \"%s\".', $resource));\n        }\n\n        if (!file_exists($resource)) {\n            throw new NotFoundResourceException(\\sprintf('File \"%s\" not found.', $resource));\n        }\n\n        $messages = $this->loadResource($resource);\n\n        // empty resource\n        $messages ??= [];\n\n        // not an array\n        if (!\\is_array($messages)) {\n            throw new InvalidResourceException(\\sprintf('Unable to load file \"%s\".', $resource));\n        }\n\n        $catalogue = parent::load($messages, $locale, $domain);\n\n        if (class_exists(FileResource::class)) {\n            $catalogue->addResource(new FileResource($resource));\n        }\n\n        return $catalogue;\n    }\n\n    /**\n     * @throws InvalidResourceException if stream content has an invalid format\n     */\n    abstract protected function loadResource(string $resource): array;\n}\n"
  },
  {
    "path": "Loader/IcuDatFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * IcuResFileLoader loads translations from a resource bundle.\n *\n * @author stealth35\n */\nclass IcuDatFileLoader extends IcuResFileLoader\n{\n    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue\n    {\n        if (!stream_is_local($resource.'.dat')) {\n            throw new InvalidResourceException(\\sprintf('This is not a local file \"%s\".', $resource));\n        }\n\n        if (!file_exists($resource.'.dat')) {\n            throw new NotFoundResourceException(\\sprintf('File \"%s\" not found.', $resource));\n        }\n\n        try {\n            $rb = new \\ResourceBundle($locale, $resource);\n        } catch (\\Exception) {\n            $rb = null;\n        }\n\n        if (!$rb) {\n            throw new InvalidResourceException(\\sprintf('Cannot load resource \"%s\".', $resource));\n        } elseif (intl_is_failure($rb->getErrorCode())) {\n            throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());\n        }\n\n        $messages = $this->flatten($rb);\n        $catalogue = new MessageCatalogue($locale);\n        $catalogue->add($messages, $domain);\n\n        if (class_exists(FileResource::class)) {\n            $catalogue->addResource(new FileResource($resource.'.dat'));\n        }\n\n        return $catalogue;\n    }\n}\n"
  },
  {
    "path": "Loader/IcuResFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Config\\Resource\\DirectoryResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * IcuResFileLoader loads translations from a resource bundle.\n *\n * @author stealth35\n */\nclass IcuResFileLoader implements LoaderInterface\n{\n    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue\n    {\n        if (!stream_is_local($resource)) {\n            throw new InvalidResourceException(\\sprintf('This is not a local file \"%s\".', $resource));\n        }\n\n        if (!is_dir($resource)) {\n            throw new NotFoundResourceException(\\sprintf('File \"%s\" not found.', $resource));\n        }\n\n        try {\n            $rb = new \\ResourceBundle($locale, $resource);\n        } catch (\\Exception) {\n            $rb = null;\n        }\n\n        if (!$rb) {\n            throw new InvalidResourceException(\\sprintf('Cannot load resource \"%s\".', $resource));\n        } elseif (intl_is_failure($rb->getErrorCode())) {\n            throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());\n        }\n\n        $messages = $this->flatten($rb);\n        $catalogue = new MessageCatalogue($locale);\n        $catalogue->add($messages, $domain);\n\n        if (class_exists(DirectoryResource::class)) {\n            $catalogue->addResource(new DirectoryResource($resource));\n        }\n\n        return $catalogue;\n    }\n\n    /**\n     * Flattens an ResourceBundle.\n     *\n     * The scheme used is:\n     *   key { key2 { key3 { \"value\" } } }\n     * Becomes:\n     *   'key.key2.key3' => 'value'\n     *\n     * This function takes an array by reference and will modify it\n     *\n     * @param \\ResourceBundle $rb       The ResourceBundle that will be flattened\n     * @param array           $messages Used internally for recursive calls\n     * @param string|null     $path     Current path being parsed, used internally for recursive calls\n     */\n    protected function flatten(\\ResourceBundle $rb, array &$messages = [], ?string $path = null): array\n    {\n        foreach ($rb as $key => $value) {\n            $nodePath = $path ? $path.'.'.$key : $key;\n            if ($value instanceof \\ResourceBundle) {\n                $this->flatten($value, $messages, $nodePath);\n            } else {\n                $messages[$nodePath] = $value;\n            }\n        }\n\n        return $messages;\n    }\n}\n"
  },
  {
    "path": "Loader/IniFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\n/**\n * IniFileLoader loads translations from an ini file.\n *\n * @author stealth35\n */\nclass IniFileLoader extends FileLoader\n{\n    protected function loadResource(string $resource): array\n    {\n        return parse_ini_file($resource, true);\n    }\n}\n"
  },
  {
    "path": "Loader/JsonFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\n\n/**\n * JsonFileLoader loads translations from an json file.\n *\n * @author singles\n */\nclass JsonFileLoader extends FileLoader\n{\n    protected function loadResource(string $resource): array\n    {\n        $messages = [];\n        if ($data = file_get_contents($resource)) {\n            $messages = json_decode($data, true);\n\n            if (0 < $errorCode = json_last_error()) {\n                throw new InvalidResourceException('Error parsing JSON: '.$this->getJSONErrorMessage($errorCode));\n            }\n        }\n\n        return $messages;\n    }\n\n    /**\n     * Translates JSON_ERROR_* constant into meaningful message.\n     */\n    private function getJSONErrorMessage(int $errorCode): string\n    {\n        return match ($errorCode) {\n            \\JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',\n            \\JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',\n            \\JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',\n            \\JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',\n            \\JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded',\n            default => 'Unknown error',\n        };\n    }\n}\n"
  },
  {
    "path": "Loader/LoaderInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * LoaderInterface is the interface implemented by all translation loaders.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface LoaderInterface\n{\n    /**\n     * Loads a locale.\n     *\n     * @throws NotFoundResourceException when the resource cannot be found\n     * @throws InvalidResourceException  when the resource cannot be loaded\n     */\n    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue;\n}\n"
  },
  {
    "path": "Loader/MoFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\n\n/**\n * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)\n */\nclass MoFileLoader extends FileLoader\n{\n    /**\n     * Magic used for validating the format of an MO file as well as\n     * detecting if the machine used to create that file was little endian.\n     */\n    public const MO_LITTLE_ENDIAN_MAGIC = 0x950412DE;\n\n    /**\n     * Magic used for validating the format of an MO file as well as\n     * detecting if the machine used to create that file was big endian.\n     */\n    public const MO_BIG_ENDIAN_MAGIC = 0xDE120495;\n\n    /**\n     * The size of the header of an MO file in bytes.\n     */\n    public const MO_HEADER_SIZE = 28;\n\n    /**\n     * Parses machine object (MO) format, independent of the machine's endian it\n     * was created on. Both 32bit and 64bit systems are supported.\n     */\n    protected function loadResource(string $resource): array\n    {\n        $stream = fopen($resource, 'r');\n\n        $stat = fstat($stream);\n\n        if ($stat['size'] < self::MO_HEADER_SIZE) {\n            throw new InvalidResourceException('MO stream content has an invalid format.');\n        }\n        $magic = unpack('V1', fread($stream, 4));\n        $magic = hexdec(substr(dechex(current($magic)), -8));\n\n        if (self::MO_LITTLE_ENDIAN_MAGIC == $magic) {\n            $isBigEndian = false;\n        } elseif (self::MO_BIG_ENDIAN_MAGIC == $magic) {\n            $isBigEndian = true;\n        } else {\n            throw new InvalidResourceException('MO stream content has an invalid format.');\n        }\n\n        // formatRevision\n        $this->readLong($stream, $isBigEndian);\n        $count = $this->readLong($stream, $isBigEndian);\n        $offsetId = $this->readLong($stream, $isBigEndian);\n        $offsetTranslated = $this->readLong($stream, $isBigEndian);\n        // sizeHashes\n        $this->readLong($stream, $isBigEndian);\n        // offsetHashes\n        $this->readLong($stream, $isBigEndian);\n\n        $messages = [];\n\n        for ($i = 0; $i < $count; ++$i) {\n            $pluralId = null;\n            $translated = null;\n\n            fseek($stream, $offsetId + $i * 8);\n\n            $length = $this->readLong($stream, $isBigEndian);\n            $offset = $this->readLong($stream, $isBigEndian);\n\n            if ($length < 1) {\n                continue;\n            }\n\n            fseek($stream, $offset);\n            $singularId = fread($stream, $length);\n\n            if (str_contains($singularId, \"\\000\")) {\n                [$singularId, $pluralId] = explode(\"\\000\", $singularId);\n            }\n\n            fseek($stream, $offsetTranslated + $i * 8);\n            $length = $this->readLong($stream, $isBigEndian);\n            $offset = $this->readLong($stream, $isBigEndian);\n\n            if ($length < 1) {\n                continue;\n            }\n\n            fseek($stream, $offset);\n            $translated = fread($stream, $length);\n\n            if (str_contains($translated, \"\\000\")) {\n                $translated = explode(\"\\000\", $translated);\n            }\n\n            $ids = ['singular' => $singularId, 'plural' => $pluralId];\n            $item = compact('ids', 'translated');\n\n            if (!empty($item['ids']['singular'])) {\n                $id = $item['ids']['singular'];\n                if (isset($item['ids']['plural'])) {\n                    $id .= '|'.$item['ids']['plural'];\n                }\n                $messages[$id] = stripcslashes(implode('|', (array) $item['translated']));\n            }\n        }\n\n        fclose($stream);\n\n        return array_filter($messages);\n    }\n\n    /**\n     * Reads an unsigned long from stream respecting endianness.\n     *\n     * @param resource $stream\n     */\n    private function readLong($stream, bool $isBigEndian): int\n    {\n        $result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));\n        $result = current($result);\n\n        return (int) substr($result, -8);\n    }\n}\n"
  },
  {
    "path": "Loader/PhpFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\n/**\n * PhpFileLoader loads translations from PHP files returning an array of translations.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass PhpFileLoader extends FileLoader\n{\n    private static ?array $cache = [];\n\n    protected function loadResource(string $resource): array\n    {\n        if ([] === self::$cache && \\function_exists('opcache_invalidate') && filter_var(\\ini_get('opcache.enable'), \\FILTER_VALIDATE_BOOL) && (!\\in_array(\\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) || filter_var(\\ini_get('opcache.enable_cli'), \\FILTER_VALIDATE_BOOL))) {\n            self::$cache = null;\n        }\n\n        if (null === self::$cache) {\n            return require $resource;\n        }\n\n        return self::$cache[$resource] ??= require $resource;\n    }\n}\n"
  },
  {
    "path": "Loader/PoFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\n/**\n * @copyright Copyright (c) 2010, Union of RAD https://github.com/UnionOfRAD/lithium\n * @copyright Copyright (c) 2012, Clemens Tolboom\n */\nclass PoFileLoader extends FileLoader\n{\n    /**\n     * Parses portable object (PO) format.\n     *\n     * From https://www.gnu.org/software/gettext/manual/gettext.html#PO-Files\n     * we should be able to parse files having:\n     *\n     * white-space\n     * #  translator-comments\n     * #. extracted-comments\n     * #: reference...\n     * #, flag...\n     * #| msgid previous-untranslated-string\n     * msgid untranslated-string\n     * msgstr translated-string\n     *\n     * extra or different lines are:\n     *\n     * #| msgctxt previous-context\n     * #| msgid previous-untranslated-string\n     * msgctxt context\n     *\n     * #| msgid previous-untranslated-string-singular\n     * #| msgid_plural previous-untranslated-string-plural\n     * msgid untranslated-string-singular\n     * msgid_plural untranslated-string-plural\n     * msgstr[0] translated-string-case-0\n     * ...\n     * msgstr[N] translated-string-case-n\n     *\n     * The definition states:\n     * - white-space and comments are optional.\n     * - msgid \"\" that an empty singleline defines a header.\n     *\n     * This parser sacrifices some features of the reference implementation the\n     * differences to that implementation are as follows.\n     * - No support for comments spanning multiple lines.\n     * - Translator and extracted comments are treated as being the same type.\n     * - Message IDs are allowed to have other encodings as just US-ASCII.\n     *\n     * Items with an empty id are ignored.\n     */\n    protected function loadResource(string $resource): array\n    {\n        $stream = fopen($resource, 'r');\n\n        $defaults = [\n            'ids' => [],\n            'translated' => null,\n        ];\n\n        $messages = [];\n        $item = $defaults;\n        $flags = [];\n\n        while ($line = fgets($stream)) {\n            $line = trim($line);\n\n            if ('' === $line) {\n                // Whitespace indicated current item is done\n                if (!\\in_array('fuzzy', $flags, true)) {\n                    $this->addMessage($messages, $item);\n                }\n                $item = $defaults;\n                $flags = [];\n            } elseif (str_starts_with($line, '#,')) {\n                $flags = array_map('trim', explode(',', substr($line, 2)));\n            } elseif (str_starts_with($line, 'msgid \"')) {\n                // We start a new msg so save previous\n                // TODO: this fails when comments or contexts are added\n                $this->addMessage($messages, $item);\n                $item = $defaults;\n                $item['ids']['singular'] = substr($line, 7, -1);\n            } elseif (str_starts_with($line, 'msgstr \"')) {\n                $item['translated'] = substr($line, 8, -1);\n            } elseif ('\"' === $line[0]) {\n                $continues = isset($item['translated']) ? 'translated' : 'ids';\n\n                if (\\is_array($item[$continues])) {\n                    end($item[$continues]);\n                    $item[$continues][key($item[$continues])] .= substr($line, 1, -1);\n                } else {\n                    $item[$continues] .= substr($line, 1, -1);\n                }\n            } elseif (str_starts_with($line, 'msgid_plural \"')) {\n                $item['ids']['plural'] = substr($line, 14, -1);\n            } elseif (str_starts_with($line, 'msgstr[')) {\n                $size = strpos($line, ']');\n                $item['translated'][(int) substr($line, 7, 1)] = substr($line, $size + 3, -1);\n            }\n        }\n        // save last item\n        if (!\\in_array('fuzzy', $flags, true)) {\n            $this->addMessage($messages, $item);\n        }\n        fclose($stream);\n\n        return $messages;\n    }\n\n    /**\n     * Save a translation item to the messages.\n     *\n     * A .po file could contain by error missing plural indexes. We need to\n     * fix these before saving them.\n     */\n    private function addMessage(array &$messages, array $item): void\n    {\n        if (!empty($item['ids']['singular'])) {\n            $id = stripcslashes($item['ids']['singular']);\n            if (isset($item['ids']['plural'])) {\n                $id .= '|'.stripcslashes($item['ids']['plural']);\n            }\n\n            $translated = (array) $item['translated'];\n            // PO are by definition indexed so sort by index.\n            ksort($translated);\n            // Make sure every index is filled.\n            end($translated);\n            $count = key($translated);\n            // Fill missing spots with '-'.\n            $empties = array_fill(0, $count + 1, '-');\n            $translated += $empties;\n            ksort($translated);\n\n            $messages[$id] = stripcslashes(implode('|', $translated));\n        }\n    }\n}\n"
  },
  {
    "path": "Loader/QtFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Config\\Util\\XmlUtils;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Exception\\RuntimeException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * QtFileLoader loads translations from QT Translations XML files.\n *\n * @author Benjamin Eberlei <kontakt@beberlei.de>\n */\nclass QtFileLoader implements LoaderInterface\n{\n    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue\n    {\n        if (!class_exists(XmlUtils::class)) {\n            throw new RuntimeException('Loading translations from the QT format requires the Symfony Config component.');\n        }\n\n        if (!stream_is_local($resource)) {\n            throw new InvalidResourceException(\\sprintf('This is not a local file \"%s\".', $resource));\n        }\n\n        if (!file_exists($resource)) {\n            throw new NotFoundResourceException(\\sprintf('File \"%s\" not found.', $resource));\n        }\n\n        try {\n            $dom = XmlUtils::loadFile($resource);\n        } catch (\\InvalidArgumentException $e) {\n            throw new InvalidResourceException(\\sprintf('Unable to load \"%s\".', $resource), $e->getCode(), $e);\n        }\n\n        $internalErrors = libxml_use_internal_errors(true);\n        libxml_clear_errors();\n\n        $xpath = new \\DOMXPath($dom);\n        $nodes = $xpath->evaluate('//TS/context/name[text()=\"'.$domain.'\"]');\n\n        $catalogue = new MessageCatalogue($locale);\n        if (1 == $nodes->length) {\n            $translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message');\n            foreach ($translations as $translation) {\n                $translationValue = (string) $translation->getElementsByTagName('translation')->item(0)->nodeValue;\n\n                if ($translationValue) {\n                    $catalogue->set(\n                        (string) $translation->getElementsByTagName('source')->item(0)->nodeValue,\n                        $translationValue,\n                        $domain\n                    );\n                }\n            }\n\n            if (class_exists(FileResource::class)) {\n                $catalogue->addResource(new FileResource($resource));\n            }\n        }\n\n        libxml_use_internal_errors($internalErrors);\n\n        return $catalogue;\n    }\n}\n"
  },
  {
    "path": "Loader/XliffFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Config\\Util\\Exception\\InvalidXmlException;\nuse Symfony\\Component\\Config\\Util\\Exception\\XmlParsingException;\nuse Symfony\\Component\\Config\\Util\\XmlUtils;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Exception\\RuntimeException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\nuse Symfony\\Component\\Translation\\Util\\XliffUtils;\n\n/**\n * XliffFileLoader loads translations from XLIFF files.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass XliffFileLoader implements LoaderInterface\n{\n    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue\n    {\n        if (!class_exists(XmlUtils::class)) {\n            throw new RuntimeException('Loading translations from the Xliff format requires the Symfony Config component.');\n        }\n\n        if (!$this->isXmlString($resource)) {\n            if (!stream_is_local($resource)) {\n                throw new InvalidResourceException(\\sprintf('This is not a local file \"%s\".', $resource));\n            }\n\n            if (!file_exists($resource)) {\n                throw new NotFoundResourceException(\\sprintf('File \"%s\" not found.', $resource));\n            }\n\n            if (!is_file($resource)) {\n                throw new InvalidResourceException(\\sprintf('This is neither a file nor an XLIFF string \"%s\".', $resource));\n            }\n        }\n\n        try {\n            if ($this->isXmlString($resource)) {\n                $dom = XmlUtils::parse($resource);\n            } else {\n                $dom = XmlUtils::loadFile($resource);\n            }\n        } catch (\\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) {\n            throw new InvalidResourceException(\\sprintf('Unable to load \"%s\": ', $resource).$e->getMessage(), $e->getCode(), $e);\n        }\n\n        if ($errors = XliffUtils::validateSchema($dom)) {\n            throw new InvalidResourceException(\\sprintf('Invalid resource provided: \"%s\"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors));\n        }\n\n        $catalogue = new MessageCatalogue($locale);\n        $this->extract($dom, $catalogue, $domain);\n\n        if (is_file($resource) && class_exists(FileResource::class)) {\n            $catalogue->addResource(new FileResource($resource));\n        }\n\n        return $catalogue;\n    }\n\n    private function extract(\\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void\n    {\n        $xliffVersion = XliffUtils::getVersionNumber($dom);\n\n        if ('1.2' === $xliffVersion) {\n            $this->extractXliff1($dom, $catalogue, $domain);\n        }\n\n        if (\\in_array($xliffVersion, ['2.0', '2.1', '2.2'], true)) {\n            $this->extractXliff2($dom, $catalogue, $domain);\n        }\n    }\n\n    /**\n     * Extract messages and metadata from DOMDocument into a MessageCatalogue.\n     */\n    private function extractXliff1(\\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void\n    {\n        $xml = simplexml_import_dom($dom);\n        $encoding = $dom->encoding ? strtoupper($dom->encoding) : null;\n\n        $namespace = 'urn:oasis:names:tc:xliff:document:1.2';\n        $xml->registerXPathNamespace('xliff', $namespace);\n\n        foreach ($xml->xpath('//xliff:file') as $file) {\n            $fileAttributes = $file->attributes();\n\n            $file->registerXPathNamespace('xliff', $namespace);\n\n            foreach ($file->xpath('.//xliff:prop') as $prop) {\n                $catalogue->setCatalogueMetadata($prop->attributes()['prop-type'], (string) $prop, $domain);\n            }\n\n            foreach ($file->xpath('.//xliff:trans-unit') as $translation) {\n                $attributes = $translation->attributes();\n\n                if (!(isset($attributes['resname']) || isset($translation->source))) {\n                    continue;\n                }\n\n                $source = (string) (isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source);\n\n                if (isset($translation->target)\n                    && 'needs-translation' === (string) $translation->target->attributes()['state']\n                    && \\in_array((string) $translation->target, [$source, (string) $translation->source], true)\n                ) {\n                    continue;\n                }\n\n                // If the xlf file has another encoding specified, try to convert it because\n                // simple_xml will always return utf-8 encoded values\n                $target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding);\n\n                $catalogue->set($source, $target, $domain);\n\n                $metadata = [\n                    'source' => (string) $translation->source,\n                    'file' => [\n                        'original' => (string) $fileAttributes['original'],\n                    ],\n                ];\n                if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) {\n                    $metadata['notes'] = $notes;\n                }\n\n                if (isset($translation->target) && $translation->target->attributes()) {\n                    $metadata['target-attributes'] = [];\n                    foreach ($translation->target->attributes() as $key => $value) {\n                        $metadata['target-attributes'][$key] = (string) $value;\n                    }\n                }\n\n                if (isset($attributes['id'])) {\n                    $metadata['id'] = (string) $attributes['id'];\n                }\n\n                $catalogue->setMetadata($source, $metadata, $domain);\n            }\n        }\n    }\n\n    private function extractXliff2(\\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void\n    {\n        $xml = simplexml_import_dom($dom);\n        $encoding = $dom->encoding ? strtoupper($dom->encoding) : null;\n\n        $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0');\n\n        foreach ($xml->xpath('//xliff:unit') as $unit) {\n            if (null !== $pgsSwitch = $unit->attributes('urn:oasis:names:tc:xliff:pgs:1.0')['switch'] ?? null) {\n                $this->extractXliff2PgsUnit($unit, $catalogue, $domain, (string) $pgsSwitch, $encoding);\n                continue;\n            }\n\n            foreach ($unit->segment as $segment) {\n                $attributes = $unit->attributes();\n                $source = $attributes['name'] ?? $segment->source;\n\n                // If the xlf file has another encoding specified, try to convert it because\n                // simple_xml will always return utf-8 encoded values\n                $target = $this->utf8ToCharset((string) ($segment->target ?? $segment->source), $encoding);\n\n                $catalogue->set((string) $source, $target, $domain);\n\n                $metadata = [];\n                if ($segment->attributes()) {\n                    $metadata['segment-attributes'] = [];\n                    foreach ($segment->attributes() as $key => $value) {\n                        $metadata['segment-attributes'][$key] = (string) $value;\n                    }\n                }\n\n                if (isset($segment->target) && $segment->target->attributes()) {\n                    $metadata['target-attributes'] = [];\n                    foreach ($segment->target->attributes() as $key => $value) {\n                        $metadata['target-attributes'][$key] = (string) $value;\n                    }\n                }\n\n                if (isset($unit->notes)) {\n                    $metadata['notes'] = [];\n                    foreach ($unit->notes->note as $noteNode) {\n                        $note = [];\n                        foreach ($noteNode->attributes() as $key => $value) {\n                            $note[$key] = (string) $value;\n                        }\n                        $note['content'] = (string) $noteNode;\n                        $metadata['notes'][] = $note;\n                    }\n                }\n\n                $catalogue->setMetadata((string) $source, $metadata, $domain);\n            }\n        }\n    }\n\n    private function extractXliff2PgsUnit(\\SimpleXMLElement $unit, MessageCatalogue $catalogue, string $domain, string $pgsSwitch, ?string $encoding): void\n    {\n        $switches = $this->parsePgsSwitch($pgsSwitch);\n        $attributes = $unit->attributes();\n        $source = (string) ($attributes['name'] ?? $attributes['id']);\n\n        $cases = [];\n        foreach ($unit->segment as $segment) {\n            if (null === $pgsCase = $segment->attributes('urn:oasis:names:tc:xliff:pgs:1.0')['case'] ?? null) {\n                continue;\n            }\n\n            $cases[(string) $pgsCase] = $this->extractPgsSegmentText($segment->target ?? $segment->source, $switches);\n        }\n\n        $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n        $catalogue->set($source, $this->utf8ToCharset($this->buildIcuMessage($switches, $cases), $encoding), $intlDomain);\n\n        $metadata = ['pgs-switch' => $pgsSwitch];\n        if (isset($unit->notes)) {\n            $metadata['notes'] = [];\n            foreach ($unit->notes->note as $noteNode) {\n                $note = array_map('strval', $noteNode->attributes() ?? []);\n\n                $note['content'] = (string) $noteNode;\n                $metadata['notes'][] = $note;\n            }\n        }\n\n        $catalogue->setMetadata($source, $metadata, $intlDomain);\n    }\n\n    private function parsePgsSwitch(string $pgsSwitch): array\n    {\n        $switches = [];\n        foreach (preg_split('/\\s+/', trim($pgsSwitch)) as $item) {\n            $switches[] = array_combine(['type', 'variable'], explode(':', $item, 2));\n        }\n\n        return $switches;\n    }\n\n    private function extractPgsSegmentText(\\SimpleXMLElement $element, array $switches): string\n    {\n        $pluralVariables = [];\n        foreach ($switches as $switch) {\n            if ('plural' === $switch['type'] || 'ordinal' === $switch['type']) {\n                $pluralVariables[$switch['variable']] = true;\n            }\n        }\n\n        $text = '';\n        foreach (dom_import_simplexml($element)->childNodes as $child) {\n            if (\\XML_TEXT_NODE === $child->nodeType) {\n                $text .= $child->textContent;\n            } elseif (\\XML_ELEMENT_NODE === $child->nodeType && 'ph' === $child->localName) {\n                if (($disp = $child->getAttribute('disp')) && isset($pluralVariables[$disp])) {\n                    $text .= '#';\n                } elseif ($disp) {\n                    $text .= '{'.$disp.'}';\n                }\n            }\n        }\n\n        return $text;\n    }\n\n    private function buildIcuMessage(array $switches, array $cases): string\n    {\n        if (1 === \\count($switches)) {\n            $switch = $switches[0];\n            $icuType = $this->getIcuType($switch['type']);\n\n            $icuCases = [];\n            foreach ($cases as $caseValue => $text) {\n                $icuCases[] = $this->formatIcuCase($caseValue, $switch['type']).' {'.$text.'}';\n            }\n\n            return '{'.$switch['variable'].', '.$icuType.', '.implode(' ', $icuCases).'}';\n        }\n\n        $outerSwitch = $switches[0];\n        $innerSwitches = \\array_slice($switches, 1);\n        $icuType = $this->getIcuType($outerSwitch['type']);\n\n        $grouped = [];\n        foreach ($cases as $caseKey => $text) {\n            $caseParts = explode(' ', $caseKey, 2);\n            $grouped[$caseParts[0]][$caseParts[1] ?? 'other'] = $text;\n        }\n\n        $icuCases = [];\n        foreach ($grouped as $caseValue => $innerCases) {\n            $icuCases[] = $this->formatIcuCase($caseValue, $outerSwitch['type']).' {'.$this->buildIcuMessage($innerSwitches, $innerCases).'}';\n        }\n\n        return '{'.$outerSwitch['variable'].', '.$icuType.', '.implode(' ', $icuCases).'}';\n    }\n\n    private function getIcuType(string $pgsType): string\n    {\n        return match ($pgsType) {\n            'plural' => 'plural',\n            'ordinal' => 'selectordinal',\n            default => 'select',\n        };\n    }\n\n    private function formatIcuCase(int|string $caseValue, string $switchType): string\n    {\n        return (\\in_array($switchType, ['plural', 'ordinal'], true) && is_numeric($caseValue) ? '=' : '').$caseValue;\n    }\n\n    /**\n     * Convert a UTF8 string to the specified encoding.\n     */\n    private function utf8ToCharset(string $content, ?string $encoding = null): string\n    {\n        if ('UTF-8' !== $encoding && $encoding) {\n            return mb_convert_encoding($content, $encoding, 'UTF-8');\n        }\n\n        return $content;\n    }\n\n    private function parseNotesMetadata(?\\SimpleXMLElement $noteElement = null, ?string $encoding = null): array\n    {\n        $notes = [];\n\n        if (null === $noteElement) {\n            return $notes;\n        }\n\n        /** @var \\SimpleXMLElement $xmlNote */\n        foreach ($noteElement as $xmlNote) {\n            $noteAttributes = $xmlNote->attributes();\n            $note = ['content' => $this->utf8ToCharset((string) $xmlNote, $encoding)];\n            if (isset($noteAttributes['priority'])) {\n                $note['priority'] = (int) $noteAttributes['priority'];\n            }\n\n            if (isset($noteAttributes['from'])) {\n                $note['from'] = (string) $noteAttributes['from'];\n            }\n\n            $notes[] = $note;\n        }\n\n        return $notes;\n    }\n\n    private function isXmlString(string $resource): bool\n    {\n        return str_starts_with($resource, '<?xml');\n    }\n}\n"
  },
  {
    "path": "Loader/YamlFileLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Loader;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\nuse Symfony\\Component\\Yaml\\Exception\\ParseException;\nuse Symfony\\Component\\Yaml\\Parser as YamlParser;\nuse Symfony\\Component\\Yaml\\Yaml;\n\n/**\n * YamlFileLoader loads translations from Yaml files.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass YamlFileLoader extends FileLoader\n{\n    private YamlParser $yamlParser;\n\n    protected function loadResource(string $resource): array\n    {\n        if (!isset($this->yamlParser)) {\n            if (!class_exists(YamlParser::class)) {\n                throw new LogicException('Loading translations from the YAML format requires the Symfony Yaml component.');\n            }\n\n            $this->yamlParser = new YamlParser();\n        }\n\n        try {\n            $messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT);\n        } catch (ParseException $e) {\n            throw new InvalidResourceException(\\sprintf('The file \"%s\" does not contain valid YAML: ', $resource).$e->getMessage(), 0, $e);\n        }\n\n        if (null !== $messages && !\\is_array($messages)) {\n            throw new InvalidResourceException(\\sprintf('Unable to load file \"%s\".', $resource));\n        }\n\n        return $messages ?: [];\n    }\n}\n"
  },
  {
    "path": "LocaleFallbackProvider.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\n\n/**\n * Derives fallback locales based on ICU parent locale information, by shortening locale\n * sub tags and ultimately by going through a list of configured fallback locales.\n *\n * Also provides locale string validation.\n *\n * @author Matthias Pigulla <mp@webfactory.de>\n */\nfinal class LocaleFallbackProvider\n{\n    /**\n     * @param string[] $localeFallbacks List of fallback locales to add _after_ the ones derived from ICU information\n     *\n     * @throws InvalidArgumentException If a locale contains invalid characters\n     */\n    public function __construct(\n        private array $localeFallbacks = [],\n    ) {\n        foreach ($localeFallbacks as $locale) {\n            self::validateLocale($locale);\n        }\n    }\n\n    /**\n     * @return string[]\n     */\n    public function computeFallbackLocales(string $locale): array\n    {\n        self::validateLocale($locale);\n\n        static $parentLocales;\n        $parentLocales ??= require __DIR__.'/Resources/data/parents.php';\n\n        $originLocale = $locale;\n        $locales = [];\n\n        while ($locale) {\n            if ($parent = $parentLocales[$locale] ?? null) {\n                $locale = 'root' !== $parent ? $parent : null;\n            } elseif (\\function_exists('locale_parse')) {\n                $localeSubTags = locale_parse($locale);\n                $locale = null;\n                if (1 < \\count($localeSubTags)) {\n                    array_pop($localeSubTags);\n                    $locale = locale_compose($localeSubTags) ?: null;\n                }\n            } elseif ($i = strrpos($locale, '_') ?: strrpos($locale, '-')) {\n                $locale = substr($locale, 0, $i);\n            } else {\n                $locale = null;\n            }\n\n            if (null !== $locale) {\n                $locales[$locale] = $locale;\n            }\n        }\n\n        foreach ($this->localeFallbacks as $fallback) {\n            if ($fallback === $originLocale) {\n                continue;\n            }\n\n            $locales[$fallback] = $fallback;\n        }\n\n        return array_keys($locales);\n    }\n\n    /**\n     * Asserts that the locale is valid, throws an Exception if not.\n     *\n     * @throws InvalidArgumentException If the locale contains invalid characters\n     */\n    public static function validateLocale(string $locale): void\n    {\n        if (!preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) {\n            throw new InvalidArgumentException(\\sprintf('Invalid \"%s\" locale.', $locale));\n        }\n    }\n}\n"
  },
  {
    "path": "LocaleSwitcher.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\Routing\\RequestContext;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\n\n/**\n * @author Kevin Bond <kevinbond@gmail.com>\n */\nclass LocaleSwitcher implements LocaleAwareInterface\n{\n    private string $defaultLocale;\n\n    /**\n     * @param LocaleAwareInterface[] $localeAwareServices\n     */\n    public function __construct(\n        private string $locale,\n        private iterable $localeAwareServices,\n        private ?RequestContext $requestContext = null,\n    ) {\n        $this->defaultLocale = $locale;\n    }\n\n    public function setLocale(string $locale): void\n    {\n        // Silently ignore if the intl extension is not loaded\n        try {\n            if (class_exists(\\Locale::class, false)) {\n                \\Locale::setDefault($locale);\n            }\n        } catch (\\Exception) {\n        }\n\n        $this->locale = $locale;\n        $this->requestContext?->setParameter('_locale', $locale);\n\n        foreach ($this->localeAwareServices as $service) {\n            $service->setLocale($locale);\n        }\n    }\n\n    public function getLocale(): string\n    {\n        return $this->locale;\n    }\n\n    /**\n     * Switch to a new locale, execute a callback, then switch back to the original.\n     *\n     * @template T\n     *\n     * @param callable(string $locale):T $callback\n     *\n     * @return T\n     */\n    public function runWithLocale(string $locale, callable $callback): mixed\n    {\n        $original = $this->getLocale();\n        $this->setLocale($locale);\n\n        try {\n            return $callback($locale);\n        } finally {\n            $this->setLocale($original);\n        }\n    }\n\n    public function reset(): void\n    {\n        $this->setLocale($this->defaultLocale);\n    }\n}\n"
  },
  {
    "path": "LoggingTranslator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass LoggingTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface\n{\n    public function __construct(\n        private TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator,\n        private LoggerInterface $logger,\n    ) {\n    }\n\n    public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string\n    {\n        $trans = $this->translator->trans($id = (string) $id, $parameters, $domain, $locale);\n        $this->log($id, $domain, $locale);\n\n        return $trans;\n    }\n\n    public function setLocale(string $locale): void\n    {\n        $prev = $this->translator->getLocale();\n        $this->translator->setLocale($locale);\n        if ($prev === $locale) {\n            return;\n        }\n\n        $this->logger->debug(\\sprintf('The locale of the translator has changed from \"%s\" to \"%s\".', $prev, $locale));\n    }\n\n    public function getLocale(): string\n    {\n        return $this->translator->getLocale();\n    }\n\n    public function getCatalogue(?string $locale = null): MessageCatalogueInterface\n    {\n        return $this->translator->getCatalogue($locale);\n    }\n\n    public function getCatalogues(): array\n    {\n        return $this->translator->getCatalogues();\n    }\n\n    public function getFallbackLocales(): array\n    {\n        if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) {\n            return $this->translator->getFallbackLocales();\n        }\n\n        return [];\n    }\n\n    public function __call(string $method, array $args): mixed\n    {\n        return $this->translator->{$method}(...$args);\n    }\n\n    /**\n     * Logs for missing translations.\n     */\n    private function log(string $id, ?string $domain, ?string $locale): void\n    {\n        $domain ??= 'messages';\n\n        $catalogue = $this->translator->getCatalogue($locale);\n        if ($catalogue->defines($id, $domain)) {\n            return;\n        }\n\n        if ($catalogue->has($id, $domain)) {\n            $this->logger->debug('Translation use fallback catalogue.', ['id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()]);\n        } else {\n            $this->logger->warning('Translation not found.', ['id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()]);\n        }\n    }\n}\n"
  },
  {
    "path": "MessageCatalogue.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\Config\\Resource\\ResourceInterface;\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface, CatalogueMetadataAwareInterface\n{\n    private array $metadata = [];\n    private array $catalogueMetadata = [];\n    private array $resources = [];\n    private ?MessageCatalogueInterface $fallbackCatalogue = null;\n    private ?self $parent = null;\n\n    /**\n     * @param array $messages An array of messages classified by domain\n     */\n    public function __construct(\n        private string $locale,\n        private array $messages = [],\n    ) {\n    }\n\n    public function getLocale(): string\n    {\n        return $this->locale;\n    }\n\n    public function getDomains(): array\n    {\n        $domains = [];\n\n        foreach ($this->messages as $domain => $messages) {\n            if (str_ends_with($domain, self::INTL_DOMAIN_SUFFIX)) {\n                $domain = substr($domain, 0, -\\strlen(self::INTL_DOMAIN_SUFFIX));\n            }\n            $domains[$domain] = $domain;\n        }\n\n        return array_values($domains);\n    }\n\n    public function all(?string $domain = null): array\n    {\n        if (null !== $domain) {\n            // skip messages merge if intl-icu requested explicitly\n            if (str_ends_with($domain, self::INTL_DOMAIN_SUFFIX)) {\n                return $this->messages[$domain] ?? [];\n            }\n\n            return ($this->messages[$domain.self::INTL_DOMAIN_SUFFIX] ?? []) + ($this->messages[$domain] ?? []);\n        }\n\n        $allMessages = [];\n\n        foreach ($this->messages as $domain => $messages) {\n            if (str_ends_with($domain, self::INTL_DOMAIN_SUFFIX)) {\n                $domain = substr($domain, 0, -\\strlen(self::INTL_DOMAIN_SUFFIX));\n                $allMessages[$domain] = $messages + ($allMessages[$domain] ?? []);\n            } else {\n                $allMessages[$domain] = ($allMessages[$domain] ?? []) + $messages;\n            }\n        }\n\n        return $allMessages;\n    }\n\n    public function set(string $id, string $translation, string $domain = 'messages'): void\n    {\n        $this->add([$id => $translation], $domain);\n    }\n\n    public function has(string $id, string $domain = 'messages'): bool\n    {\n        if (isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {\n            return true;\n        }\n\n        if (null !== $this->fallbackCatalogue) {\n            return $this->fallbackCatalogue->has($id, $domain);\n        }\n\n        return false;\n    }\n\n    public function defines(string $id, string $domain = 'messages'): bool\n    {\n        return isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id]);\n    }\n\n    public function get(string $id, string $domain = 'messages'): string\n    {\n        if (isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {\n            return $this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id];\n        }\n\n        if (isset($this->messages[$domain][$id])) {\n            return $this->messages[$domain][$id];\n        }\n\n        if (null !== $this->fallbackCatalogue) {\n            return $this->fallbackCatalogue->get($id, $domain);\n        }\n\n        return $id;\n    }\n\n    public function replace(array $messages, string $domain = 'messages'): void\n    {\n        unset($this->messages[$domain], $this->messages[$domain.self::INTL_DOMAIN_SUFFIX]);\n\n        $this->add($messages, $domain);\n    }\n\n    public function add(array $messages, string $domain = 'messages'): void\n    {\n        $altDomain = str_ends_with($domain, self::INTL_DOMAIN_SUFFIX) ? substr($domain, 0, -\\strlen(self::INTL_DOMAIN_SUFFIX)) : $domain.self::INTL_DOMAIN_SUFFIX;\n        foreach ($messages as $id => $message) {\n            unset($this->messages[$altDomain][$id]);\n            $this->messages[$domain][$id] = $message;\n        }\n\n        if ([] === ($this->messages[$altDomain] ?? null)) {\n            unset($this->messages[$altDomain]);\n        }\n    }\n\n    public function addCatalogue(MessageCatalogueInterface $catalogue): void\n    {\n        if ($catalogue->getLocale() !== $this->locale) {\n            throw new LogicException(\\sprintf('Cannot add a catalogue for locale \"%s\" as the current locale for this catalogue is \"%s\".', $catalogue->getLocale(), $this->locale));\n        }\n\n        foreach ($catalogue->all() as $domain => $messages) {\n            if ($intlMessages = $catalogue->all($domain.self::INTL_DOMAIN_SUFFIX)) {\n                $this->add($intlMessages, $domain.self::INTL_DOMAIN_SUFFIX);\n                $messages = array_diff_key($messages, $intlMessages);\n            }\n            $this->add($messages, $domain);\n        }\n\n        foreach ($catalogue->getResources() as $resource) {\n            $this->addResource($resource);\n        }\n\n        if ($catalogue instanceof MetadataAwareInterface) {\n            $metadata = $catalogue->getMetadata('', '');\n            $this->addMetadata($metadata);\n        }\n\n        if ($catalogue instanceof CatalogueMetadataAwareInterface) {\n            $catalogueMetadata = $catalogue->getCatalogueMetadata('', '');\n            $this->addCatalogueMetadata($catalogueMetadata);\n        }\n    }\n\n    public function addFallbackCatalogue(MessageCatalogueInterface $catalogue): void\n    {\n        // detect circular references\n        $c = $catalogue;\n        while ($c = $c->getFallbackCatalogue()) {\n            if ($c->getLocale() === $this->getLocale()) {\n                throw new LogicException(\\sprintf('Circular reference detected when adding a fallback catalogue for locale \"%s\".', $catalogue->getLocale()));\n            }\n        }\n\n        $c = $this;\n        do {\n            if ($c->getLocale() === $catalogue->getLocale()) {\n                throw new LogicException(\\sprintf('Circular reference detected when adding a fallback catalogue for locale \"%s\".', $catalogue->getLocale()));\n            }\n\n            foreach ($catalogue->getResources() as $resource) {\n                $c->addResource($resource);\n            }\n        } while ($c = $c->parent);\n\n        $catalogue->parent = $this;\n        $this->fallbackCatalogue = $catalogue;\n\n        foreach ($catalogue->getResources() as $resource) {\n            $this->addResource($resource);\n        }\n    }\n\n    public function getFallbackCatalogue(): ?MessageCatalogueInterface\n    {\n        return $this->fallbackCatalogue;\n    }\n\n    public function getResources(): array\n    {\n        return array_values($this->resources);\n    }\n\n    public function addResource(ResourceInterface $resource): void\n    {\n        $this->resources[$resource->__toString()] = $resource;\n    }\n\n    public function getMetadata(string $key = '', string $domain = 'messages'): mixed\n    {\n        if ('' == $domain) {\n            return $this->metadata;\n        }\n\n        if (isset($this->metadata[$domain.self::INTL_DOMAIN_SUFFIX])) {\n            if ('' === $key) {\n                return $this->metadata[$domain.self::INTL_DOMAIN_SUFFIX];\n            }\n\n            if (isset($this->metadata[$domain.self::INTL_DOMAIN_SUFFIX][$key])) {\n                return $this->metadata[$domain.self::INTL_DOMAIN_SUFFIX][$key];\n            }\n        }\n\n        if (isset($this->metadata[$domain])) {\n            if ('' == $key) {\n                return $this->metadata[$domain];\n            }\n\n            if (isset($this->metadata[$domain][$key])) {\n                return $this->metadata[$domain][$key];\n            }\n        }\n\n        return null;\n    }\n\n    public function setMetadata(string $key, mixed $value, string $domain = 'messages'): void\n    {\n        $this->metadata[$domain][$key] = $value;\n    }\n\n    public function deleteMetadata(string $key = '', string $domain = 'messages'): void\n    {\n        if ('' == $domain) {\n            $this->metadata = [];\n        } elseif ('' == $key) {\n            unset($this->metadata[$domain]);\n        } else {\n            unset($this->metadata[$domain][$key]);\n        }\n    }\n\n    public function getCatalogueMetadata(string $key = '', string $domain = 'messages'): mixed\n    {\n        if (!$domain) {\n            return $this->catalogueMetadata;\n        }\n\n        if (isset($this->catalogueMetadata[$domain])) {\n            if (!$key) {\n                return $this->catalogueMetadata[$domain];\n            }\n\n            if (isset($this->catalogueMetadata[$domain][$key])) {\n                return $this->catalogueMetadata[$domain][$key];\n            }\n        }\n\n        return null;\n    }\n\n    public function setCatalogueMetadata(string $key, mixed $value, string $domain = 'messages'): void\n    {\n        $this->catalogueMetadata[$domain][$key] = $value;\n    }\n\n    public function deleteCatalogueMetadata(string $key = '', string $domain = 'messages'): void\n    {\n        if (!$domain) {\n            $this->catalogueMetadata = [];\n        } elseif (!$key) {\n            unset($this->catalogueMetadata[$domain]);\n        } else {\n            unset($this->catalogueMetadata[$domain][$key]);\n        }\n    }\n\n    /**\n     * Adds current values with the new values.\n     *\n     * @param array $values Values to add\n     */\n    private function addMetadata(array $values): void\n    {\n        foreach ($values as $domain => $keys) {\n            foreach ($keys as $key => $value) {\n                $this->setMetadata($key, $value, $domain);\n            }\n        }\n    }\n\n    private function addCatalogueMetadata(array $values): void\n    {\n        foreach ($values as $domain => $keys) {\n            foreach ($keys as $key => $value) {\n                $this->setCatalogueMetadata($key, $value, $domain);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "MessageCatalogueInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\Config\\Resource\\ResourceInterface;\n\n/**\n * MessageCatalogueInterface.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface MessageCatalogueInterface\n{\n    public const INTL_DOMAIN_SUFFIX = '+intl-icu';\n\n    /**\n     * Gets the catalogue locale.\n     */\n    public function getLocale(): string;\n\n    /**\n     * Gets the domains.\n     */\n    public function getDomains(): array;\n\n    /**\n     * Gets the messages within a given domain.\n     *\n     * If $domain is null, it returns all messages.\n     */\n    public function all(?string $domain = null): array;\n\n    /**\n     * Sets a message translation.\n     *\n     * @param string $id          The message id\n     * @param string $translation The messages translation\n     * @param string $domain      The domain name\n     */\n    public function set(string $id, string $translation, string $domain = 'messages'): void;\n\n    /**\n     * Checks if a message has a translation.\n     *\n     * @param string $id     The message id\n     * @param string $domain The domain name\n     */\n    public function has(string $id, string $domain = 'messages'): bool;\n\n    /**\n     * Checks if a message has a translation (it does not take into account the fallback mechanism).\n     *\n     * @param string $id     The message id\n     * @param string $domain The domain name\n     */\n    public function defines(string $id, string $domain = 'messages'): bool;\n\n    /**\n     * Gets a message translation.\n     *\n     * @param string $id     The message id\n     * @param string $domain The domain name\n     */\n    public function get(string $id, string $domain = 'messages'): string;\n\n    /**\n     * Sets translations for a given domain.\n     *\n     * @param array  $messages An array of translations\n     * @param string $domain   The domain name\n     */\n    public function replace(array $messages, string $domain = 'messages'): void;\n\n    /**\n     * Adds translations for a given domain.\n     *\n     * @param array  $messages An array of translations\n     * @param string $domain   The domain name\n     */\n    public function add(array $messages, string $domain = 'messages'): void;\n\n    /**\n     * Merges translations from the given Catalogue into the current one.\n     *\n     * The two catalogues must have the same locale.\n     */\n    public function addCatalogue(self $catalogue): void;\n\n    /**\n     * Merges translations from the given Catalogue into the current one\n     * only when the translation does not exist.\n     *\n     * This is used to provide default translations when they do not exist for the current locale.\n     */\n    public function addFallbackCatalogue(self $catalogue): void;\n\n    /**\n     * Gets the fallback catalogue.\n     */\n    public function getFallbackCatalogue(): ?self;\n\n    /**\n     * Returns an array of resources loaded to build this collection.\n     *\n     * @return ResourceInterface[]\n     */\n    public function getResources(): array;\n\n    /**\n     * Adds a resource for this collection.\n     */\n    public function addResource(ResourceInterface $resource): void;\n}\n"
  },
  {
    "path": "MetadataAwareInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\n/**\n * This interface is used to get, set, and delete metadata about the translation messages.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface MetadataAwareInterface\n{\n    /**\n     * Gets metadata for the given domain and key.\n     *\n     * Passing an empty domain will return an array with all metadata indexed by\n     * domain and then by key. Passing an empty key will return an array with all\n     * metadata for the given domain.\n     *\n     * @return mixed The value that was set or an array with the domains/keys or null\n     */\n    public function getMetadata(string $key = '', string $domain = 'messages'): mixed;\n\n    /**\n     * Adds metadata to a message domain.\n     */\n    public function setMetadata(string $key, mixed $value, string $domain = 'messages'): void;\n\n    /**\n     * Deletes metadata for the given key and domain.\n     *\n     * Passing an empty domain will delete all metadata. Passing an empty key will\n     * delete all metadata for the given domain.\n     */\n    public function deleteMetadata(string $key = '', string $domain = 'messages'): void;\n}\n"
  },
  {
    "path": "Provider/AbstractProviderFactory.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\Exception\\IncompleteDsnException;\n\nabstract class AbstractProviderFactory implements ProviderFactoryInterface\n{\n    public function supports(Dsn $dsn): bool\n    {\n        return \\in_array($dsn->getScheme(), $this->getSupportedSchemes(), true);\n    }\n\n    /**\n     * @return string[]\n     */\n    abstract protected function getSupportedSchemes(): array;\n\n    protected function getUser(Dsn $dsn): string\n    {\n        return $dsn->getUser() ?? throw new IncompleteDsnException('User is not set.', $dsn->getScheme().'://'.$dsn->getHost());\n    }\n\n    protected function getPassword(Dsn $dsn): string\n    {\n        return $dsn->getPassword() ?? throw new IncompleteDsnException('Password is not set.', $dsn->getOriginalDsn());\n    }\n}\n"
  },
  {
    "path": "Provider/Dsn.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\MissingRequiredOptionException;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Oskar Stark <oskarstark@googlemail.com>\n */\nfinal class Dsn\n{\n    private ?string $scheme;\n    private ?string $host;\n    private ?string $user;\n    private ?string $password;\n    private ?int $port;\n    private ?string $path;\n    private array $options = [];\n    private string $originalDsn;\n\n    public function __construct(#[\\SensitiveParameter] string $dsn)\n    {\n        $this->originalDsn = $dsn;\n\n        if (false === $params = parse_url($dsn)) {\n            throw new InvalidArgumentException('The translation provider DSN is invalid.');\n        }\n\n        if (!isset($params['scheme'])) {\n            throw new InvalidArgumentException('The translation provider DSN must contain a scheme.');\n        }\n        $this->scheme = $params['scheme'];\n\n        if (!isset($params['host'])) {\n            throw new InvalidArgumentException('The translation provider DSN must contain a host (use \"default\" by default).');\n        }\n        $this->host = $params['host'];\n\n        $this->user = '' !== ($params['user'] ?? '') ? rawurldecode($params['user']) : null;\n        $this->password = '' !== ($params['pass'] ?? '') ? rawurldecode($params['pass']) : null;\n        $this->port = $params['port'] ?? null;\n        $this->path = $params['path'] ?? null;\n        parse_str($params['query'] ?? '', $this->options);\n    }\n\n    public function getScheme(): string\n    {\n        return $this->scheme;\n    }\n\n    public function getHost(): string\n    {\n        return $this->host;\n    }\n\n    public function getUser(): ?string\n    {\n        return $this->user;\n    }\n\n    public function getPassword(): ?string\n    {\n        return $this->password;\n    }\n\n    public function getPort(?int $default = null): ?int\n    {\n        return $this->port ?? $default;\n    }\n\n    public function getOption(string $key, mixed $default = null): mixed\n    {\n        return $this->options[$key] ?? $default;\n    }\n\n    public function getRequiredOption(string $key): mixed\n    {\n        if (!\\array_key_exists($key, $this->options) || '' === trim($this->options[$key])) {\n            throw new MissingRequiredOptionException($key);\n        }\n\n        return $this->options[$key];\n    }\n\n    public function getOptions(): array\n    {\n        return $this->options;\n    }\n\n    public function getPath(): ?string\n    {\n        return $this->path;\n    }\n\n    public function getOriginalDsn(): string\n    {\n        return $this->originalDsn;\n    }\n}\n"
  },
  {
    "path": "Provider/FilteringProvider.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\TranslatorBag;\nuse Symfony\\Component\\Translation\\TranslatorBagInterface;\n\n/**\n * Filters domains and locales between the Translator config values and those specific to each provider.\n *\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nclass FilteringProvider implements ProviderInterface\n{\n    public function __construct(\n        private ProviderInterface $provider,\n        private array $locales,\n        private array $domains = [],\n    ) {\n        $this->locales = array_filter($locales);\n    }\n\n    public function __toString(): string\n    {\n        return (string) $this->provider;\n    }\n\n    public function write(TranslatorBagInterface $translatorBag): void\n    {\n        $this->provider->write($translatorBag);\n    }\n\n    public function read(array $domains, array $locales): TranslatorBag\n    {\n        $domains = !$this->domains ? $domains : array_intersect($this->domains, $domains);\n        $locales = array_intersect($this->locales, $locales);\n\n        return $this->provider->read($domains, $locales);\n    }\n\n    public function delete(TranslatorBagInterface $translatorBag): void\n    {\n        $this->provider->delete($translatorBag);\n    }\n\n    public function getDomains(): array\n    {\n        return $this->domains;\n    }\n}\n"
  },
  {
    "path": "Provider/NullProvider.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\TranslatorBag;\nuse Symfony\\Component\\Translation\\TranslatorBagInterface;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nclass NullProvider implements ProviderInterface\n{\n    public function __toString(): string\n    {\n        return 'null';\n    }\n\n    public function write(TranslatorBagInterface $translatorBag, bool $override = false): void\n    {\n    }\n\n    public function read(array $domains, array $locales): TranslatorBag\n    {\n        return new TranslatorBag();\n    }\n\n    public function delete(TranslatorBagInterface $translatorBag): void\n    {\n    }\n}\n"
  },
  {
    "path": "Provider/NullProviderFactory.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\Exception\\UnsupportedSchemeException;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nfinal class NullProviderFactory extends AbstractProviderFactory\n{\n    public function create(Dsn $dsn): ProviderInterface\n    {\n        if ('null' === $dsn->getScheme()) {\n            return new NullProvider();\n        }\n\n        throw new UnsupportedSchemeException($dsn, 'null', $this->getSupportedSchemes());\n    }\n\n    protected function getSupportedSchemes(): array\n    {\n        return ['null'];\n    }\n}\n"
  },
  {
    "path": "Provider/ProviderFactoryInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\Exception\\IncompleteDsnException;\nuse Symfony\\Component\\Translation\\Exception\\UnsupportedSchemeException;\n\ninterface ProviderFactoryInterface\n{\n    /**\n     * @throws UnsupportedSchemeException\n     * @throws IncompleteDsnException\n     */\n    public function create(Dsn $dsn): ProviderInterface;\n\n    public function supports(Dsn $dsn): bool;\n}\n"
  },
  {
    "path": "Provider/ProviderInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\TranslatorBag;\nuse Symfony\\Component\\Translation\\TranslatorBagInterface;\n\ninterface ProviderInterface extends \\Stringable\n{\n    /**\n     * Translations available in the TranslatorBag only must be created.\n     * Translations available in both the TranslatorBag and on the provider\n     * must be overwritten.\n     * Translations available on the provider only must be kept.\n     */\n    public function write(TranslatorBagInterface $translatorBag): void;\n\n    public function read(array $domains, array $locales): TranslatorBag;\n\n    public function delete(TranslatorBagInterface $translatorBag): void;\n}\n"
  },
  {
    "path": "Provider/TranslationProviderCollection.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nfinal class TranslationProviderCollection\n{\n    /**\n     * @var array<string, ProviderInterface>\n     */\n    private array $providers;\n\n    /**\n     * @param array<string, ProviderInterface> $providers\n     */\n    public function __construct(iterable $providers)\n    {\n        $this->providers = \\is_array($providers) ? $providers : iterator_to_array($providers);\n    }\n\n    public function __toString(): string\n    {\n        return '['.implode(',', array_keys($this->providers)).']';\n    }\n\n    public function has(string $name): bool\n    {\n        return isset($this->providers[$name]);\n    }\n\n    public function get(string $name): ProviderInterface\n    {\n        if (!$this->has($name)) {\n            throw new InvalidArgumentException(\\sprintf('Provider \"%s\" not found. Available: \"%s\".', $name, (string) $this));\n        }\n\n        return $this->providers[$name];\n    }\n\n    public function keys(): array\n    {\n        return array_keys($this->providers);\n    }\n}\n"
  },
  {
    "path": "Provider/TranslationProviderCollectionFactory.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Provider;\n\nuse Symfony\\Component\\Translation\\Exception\\UnsupportedSchemeException;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nclass TranslationProviderCollectionFactory\n{\n    /**\n     * @param iterable<mixed, ProviderFactoryInterface> $factories\n     */\n    public function __construct(\n        private iterable $factories,\n        private array $enabledLocales,\n    ) {\n    }\n\n    public function fromConfig(array $config): TranslationProviderCollection\n    {\n        $providers = [];\n        foreach ($config as $name => $currentConfig) {\n            $providers[$name] = $this->fromDsnObject(\n                new Dsn($currentConfig['dsn']),\n                !$currentConfig['locales'] ? $this->enabledLocales : $currentConfig['locales'],\n                !$currentConfig['domains'] ? [] : $currentConfig['domains']\n            );\n        }\n\n        return new TranslationProviderCollection($providers);\n    }\n\n    public function fromDsnObject(Dsn $dsn, array $locales, array $domains = []): ProviderInterface\n    {\n        foreach ($this->factories as $factory) {\n            if ($factory->supports($dsn)) {\n                return new FilteringProvider($factory->create($dsn), $locales, $domains);\n            }\n        }\n\n        throw new UnsupportedSchemeException($dsn);\n    }\n}\n"
  },
  {
    "path": "PseudoLocalizationTranslator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n/**\n * This translator should only be used in a development environment.\n */\nfinal class PseudoLocalizationTranslator implements TranslatorInterface, TranslatorBagInterface\n{\n    private const EXPANSION_CHARACTER = '~';\n\n    private bool $accents;\n    private float $expansionFactor;\n    private bool $brackets;\n    private bool $parseHTML;\n\n    /**\n     * @var string[]\n     */\n    private array $localizableHTMLAttributes;\n\n    /**\n     * Available options:\n     *  * accents:\n     *      type: boolean\n     *      default: true\n     *      description: replace ASCII characters of the translated string with accented versions or similar characters\n     *      example: if true, \"foo\" => \"ƒöö\".\n     *\n     *  * expansion_factor:\n     *      type: float\n     *      default: 1\n     *      validation: it must be greater than or equal to 1\n     *      description: expand the translated string by the given factor with spaces and tildes\n     *      example: if 2, \"foo\" => \"~foo ~\"\n     *\n     *  * brackets:\n     *      type: boolean\n     *      default: true\n     *      description: wrap the translated string with brackets\n     *      example: if true, \"foo\" => \"[foo]\"\n     *\n     *  * parse_html:\n     *      type: boolean\n     *      default: false\n     *      description: parse the translated string as HTML - looking for HTML tags has a performance impact but allows to preserve them from alterations - it also allows to compute the visible translated string length which is useful to correctly expand or when it contains HTML\n     *      warning: unclosed tags are unsupported, they will be fixed (closed) by the parser - eg, \"foo <div>bar\" => \"foo <div>bar</div>\"\n     *\n     *  * localizable_html_attributes:\n     *      type: string[]\n     *      default: []\n     *      description: the list of HTML attributes whose values can be altered - it is only useful when the \"parse_html\" option is set to true\n     *      example: if [\"title\"], and with the \"accents\" option set to true, \"<a href=\"#\" title=\"Go to your profile\">Profile</a>\" => \"<a href=\"#\" title=\"Ĝö ţö ýöûŕ þŕöƒîļé\">Þŕöƒîļé</a>\" - if \"title\" was not in the \"localizable_html_attributes\" list, the title attribute data would be left unchanged.\n     */\n    public function __construct(\n        private TranslatorInterface $translator,\n        array $options = [],\n    ) {\n        $this->translator = $translator;\n        $this->accents = $options['accents'] ?? true;\n\n        if (1.0 > ($this->expansionFactor = $options['expansion_factor'] ?? 1.0)) {\n            throw new \\InvalidArgumentException('The expansion factor must be greater than or equal to 1.');\n        }\n\n        $this->brackets = $options['brackets'] ?? true;\n\n        $this->parseHTML = $options['parse_html'] ?? false;\n        if ($this->parseHTML && !$this->accents && 1.0 === $this->expansionFactor) {\n            $this->parseHTML = false;\n        }\n\n        $this->localizableHTMLAttributes = $options['localizable_html_attributes'] ?? [];\n    }\n\n    public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string\n    {\n        $trans = '';\n        $visibleText = '';\n\n        foreach ($this->getParts($this->translator->trans($id, $parameters, $domain, $locale)) as [$visible, $localizable, $text]) {\n            if ($visible) {\n                $visibleText .= $text;\n            }\n\n            if (!$localizable) {\n                $trans .= $text;\n\n                continue;\n            }\n\n            $this->addAccents($trans, $text);\n        }\n\n        $this->expand($trans, $visibleText);\n\n        $this->addBrackets($trans);\n\n        return $trans;\n    }\n\n    public function getLocale(): string\n    {\n        return $this->translator->getLocale();\n    }\n\n    public function getCatalogue(?string $locale = null): MessageCatalogueInterface\n    {\n        if (!$this->translator instanceof TranslatorBagInterface) {\n            throw new LogicException(\\sprintf('The \"%s()\" method cannot be called as the wrapped translator class \"%s\" does not implement the \"%s\".', __METHOD__, $this->translator::class, TranslatorBagInterface::class));\n        }\n\n        return $this->translator->getCatalogue($locale);\n    }\n\n    public function getCatalogues(): array\n    {\n        if (!$this->translator instanceof TranslatorBagInterface) {\n            throw new LogicException(\\sprintf('The \"%s()\" method cannot be called as the wrapped translator class \"%s\" does not implement the \"%s\".', __METHOD__, $this->translator::class, TranslatorBagInterface::class));\n        }\n\n        return $this->translator->getCatalogues();\n    }\n\n    private function getParts(string $originalTrans): array\n    {\n        if (!$this->parseHTML) {\n            return [[true, true, $originalTrans]];\n        }\n\n        $html = mb_encode_numericentity($originalTrans, [0x80, 0x10FFFF, 0, 0x1FFFFF], mb_detect_encoding($originalTrans, null, true) ?: 'UTF-8');\n\n        $useInternalErrors = libxml_use_internal_errors(true);\n\n        $dom = new \\DOMDocument();\n        $dom->loadHTML('<trans>'.$html.'</trans>');\n\n        libxml_clear_errors();\n        libxml_use_internal_errors($useInternalErrors);\n\n        return $this->parseNode($dom->childNodes->item(1)->childNodes->item(0)->childNodes->item(0));\n    }\n\n    private function parseNode(\\DOMNode $node): array\n    {\n        $parts = [];\n\n        foreach ($node->childNodes as $childNode) {\n            if (!$childNode instanceof \\DOMElement) {\n                $parts[] = [true, true, $childNode->nodeValue];\n\n                continue;\n            }\n\n            $parts[] = [false, false, '<'.$childNode->tagName];\n\n            foreach ($childNode->attributes as $attribute) {\n                $parts[] = [false, false, ' '.$attribute->nodeName.'=\"'];\n\n                $localizableAttribute = \\in_array($attribute->nodeName, $this->localizableHTMLAttributes, true);\n                foreach (preg_split('/(&(?:amp|quot|#039|lt|gt);+)/', htmlspecialchars($attribute->nodeValue, \\ENT_QUOTES, 'UTF-8'), -1, \\PREG_SPLIT_DELIM_CAPTURE) as $i => $match) {\n                    if ('' === $match) {\n                        continue;\n                    }\n\n                    $parts[] = [false, $localizableAttribute && 0 === $i % 2, $match];\n                }\n\n                $parts[] = [false, false, '\"'];\n            }\n\n            $parts[] = [false, false, '>'];\n\n            $parts = array_merge($parts, $this->parseNode($childNode));\n\n            $parts[] = [false, false, '</'.$childNode->tagName.'>'];\n        }\n\n        return $parts;\n    }\n\n    private function addAccents(string &$trans, string $text): void\n    {\n        $trans .= $this->accents ? strtr($text, [\n            ' ' => ' ',\n            '!' => '¡',\n            '\"' => '″',\n            '#' => '♯',\n            '$' => '€',\n            '%' => '‰',\n            '&' => '⅋',\n            '\\'' => '´',\n            '(' => '{',\n            ')' => '}',\n            '*' => '⁎',\n            '+' => '⁺',\n            ',' => '،',\n            '-' => '‐',\n            '.' => '·',\n            '/' => '⁄',\n            '0' => '⓪',\n            '1' => '①',\n            '2' => '②',\n            '3' => '③',\n            '4' => '④',\n            '5' => '⑤',\n            '6' => '⑥',\n            '7' => '⑦',\n            '8' => '⑧',\n            '9' => '⑨',\n            ':' => '∶',\n            ';' => '⁏',\n            '<' => '≤',\n            '=' => '≂',\n            '>' => '≥',\n            '?' => '¿',\n            '@' => '՞',\n            'A' => 'Å',\n            'B' => 'Ɓ',\n            'C' => 'Ç',\n            'D' => 'Ð',\n            'E' => 'É',\n            'F' => 'Ƒ',\n            'G' => 'Ĝ',\n            'H' => 'Ĥ',\n            'I' => 'Î',\n            'J' => 'Ĵ',\n            'K' => 'Ķ',\n            'L' => 'Ļ',\n            'M' => 'Ṁ',\n            'N' => 'Ñ',\n            'O' => 'Ö',\n            'P' => 'Þ',\n            'Q' => 'Ǫ',\n            'R' => 'Ŕ',\n            'S' => 'Š',\n            'T' => 'Ţ',\n            'U' => 'Û',\n            'V' => 'Ṽ',\n            'W' => 'Ŵ',\n            'X' => 'Ẋ',\n            'Y' => 'Ý',\n            'Z' => 'Ž',\n            '[' => '⁅',\n            '\\\\' => '∖',\n            ']' => '⁆',\n            '^' => '˄',\n            '_' => '‿',\n            '`' => '‵',\n            'a' => 'å',\n            'b' => 'ƀ',\n            'c' => 'ç',\n            'd' => 'ð',\n            'e' => 'é',\n            'f' => 'ƒ',\n            'g' => 'ĝ',\n            'h' => 'ĥ',\n            'i' => 'î',\n            'j' => 'ĵ',\n            'k' => 'ķ',\n            'l' => 'ļ',\n            'm' => 'ɱ',\n            'n' => 'ñ',\n            'o' => 'ö',\n            'p' => 'þ',\n            'q' => 'ǫ',\n            'r' => 'ŕ',\n            's' => 'š',\n            't' => 'ţ',\n            'u' => 'û',\n            'v' => 'ṽ',\n            'w' => 'ŵ',\n            'x' => 'ẋ',\n            'y' => 'ý',\n            'z' => 'ž',\n            '{' => '(',\n            '|' => '¦',\n            '}' => ')',\n            '~' => '˞',\n        ]) : $text;\n    }\n\n    private function expand(string &$trans, string $visibleText): void\n    {\n        if (1.0 >= $this->expansionFactor) {\n            return;\n        }\n\n        $visibleLength = $this->strlen($visibleText);\n        $missingLength = (int) ceil($visibleLength * $this->expansionFactor) - $visibleLength;\n        if ($this->brackets) {\n            $missingLength -= 2;\n        }\n\n        if (0 >= $missingLength) {\n            return;\n        }\n\n        $words = [];\n        $wordsCount = 0;\n        foreach (preg_split('/ +/', $visibleText, -1, \\PREG_SPLIT_NO_EMPTY) as $word) {\n            $wordLength = $this->strlen($word);\n\n            if ($wordLength >= $missingLength) {\n                continue;\n            }\n\n            if (!isset($words[$wordLength])) {\n                $words[$wordLength] = 0;\n            }\n\n            ++$words[$wordLength];\n            ++$wordsCount;\n        }\n\n        if (!$words) {\n            $trans .= 1 === $missingLength ? self::EXPANSION_CHARACTER : ' '.str_repeat(self::EXPANSION_CHARACTER, $missingLength - 1);\n\n            return;\n        }\n\n        arsort($words, \\SORT_NUMERIC);\n\n        $longestWordLength = max(array_keys($words));\n\n        while (true) {\n            $r = mt_rand(1, $wordsCount);\n\n            foreach ($words as $length => $count) {\n                $r -= $count;\n                if ($r <= 0) {\n                    break;\n                }\n            }\n\n            $trans .= ' '.str_repeat(self::EXPANSION_CHARACTER, $length);\n\n            $missingLength -= $length + 1;\n\n            if (0 === $missingLength) {\n                return;\n            }\n\n            while ($longestWordLength >= $missingLength) {\n                $wordsCount -= $words[$longestWordLength];\n                unset($words[$longestWordLength]);\n\n                if (!$words) {\n                    $trans .= 1 === $missingLength ? self::EXPANSION_CHARACTER : ' '.str_repeat(self::EXPANSION_CHARACTER, $missingLength - 1);\n\n                    return;\n                }\n\n                $longestWordLength = max(array_keys($words));\n            }\n        }\n    }\n\n    private function addBrackets(string &$trans): void\n    {\n        if (!$this->brackets) {\n            return;\n        }\n\n        $trans = '['.$trans.']';\n    }\n\n    private function strlen(string $s): int\n    {\n        return false === ($encoding = mb_detect_encoding($s, null, true)) ? \\strlen($s) : mb_strlen($s, $encoding);\n    }\n}\n\n// @php-cs-fixer-ignore random_api_migration As logic is coupled with mt_srand() in tests\n"
  },
  {
    "path": "README.md",
    "content": "Translation Component\n=====================\n\nThe Translation component provides tools to internationalize your application.\n\nGetting Started\n---------------\n\n```bash\ncomposer require symfony/translation\n```\n\n```php\nuse Symfony\\Component\\Translation\\Translator;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\n\n$translator = new Translator('fr_FR');\n$translator->addLoader('array', new ArrayLoader());\n$translator->addResource('array', [\n    'Hello World!' => 'Bonjour !',\n], 'fr_FR');\n\necho $translator->trans('Hello World!'); // outputs « Bonjour ! »\n```\n\nSponsor\n-------\n\nHelp Symfony by [sponsoring][3] its development!\n\nResources\n---------\n\n * [Documentation](https://symfony.com/doc/current/translation.html)\n * [Contributing](https://symfony.com/doc/current/contributing/index.html)\n * [Report issues](https://github.com/symfony/symfony/issues) and\n   [send Pull Requests](https://github.com/symfony/symfony/pulls)\n   in the [main Symfony repository](https://github.com/symfony/symfony)\n\n[3]: https://symfony.com/sponsor\n"
  },
  {
    "path": "Reader/TranslationReader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Reader;\n\nuse Symfony\\Component\\Finder\\Finder;\nuse Symfony\\Component\\Translation\\Loader\\LoaderInterface;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * TranslationReader reads translation messages from translation files.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\nclass TranslationReader implements TranslationReaderInterface\n{\n    /**\n     * Loaders used for import.\n     *\n     * @var array<string, LoaderInterface>\n     */\n    private array $loaders = [];\n\n    /**\n     * Adds a loader to the translation extractor.\n     *\n     * @param string $format The format of the loader\n     */\n    public function addLoader(string $format, LoaderInterface $loader): void\n    {\n        $this->loaders[$format] = $loader;\n    }\n\n    public function read(string $directory, MessageCatalogue $catalogue): void\n    {\n        if (!is_dir($directory)) {\n            return;\n        }\n\n        foreach ($this->loaders as $format => $loader) {\n            // load any existing translation files\n            $finder = new Finder();\n            $extension = $catalogue->getLocale().'.'.$format;\n            $files = $finder->files()->name('*.'.$extension)->in($directory);\n            foreach ($files as $file) {\n                $domain = substr($file->getFilename(), 0, -1 * \\strlen($extension) - 1);\n                $catalogue->addCatalogue($loader->load($file->getPathname(), $catalogue->getLocale(), $domain));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Reader/TranslationReaderInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Reader;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * TranslationReader reads translation messages from translation files.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n */\ninterface TranslationReaderInterface\n{\n    /**\n     * Reads translation messages from a directory to the catalogue.\n     */\n    public function read(string $directory, MessageCatalogue $catalogue): void;\n}\n"
  },
  {
    "path": "Resources/bin/translation-status.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif ('cli' !== \\PHP_SAPI) {\n    throw new Exception('This script must be run from the command line.');\n}\n\n$usageInstructions = <<<END\n\n      Usage instructions\n      -------------------------------------------------------------------------------\n\n      $ cd symfony-code-root-directory/\n\n      # show the translation status of all locales\n      $ php translation-status.php\n\n      # only show the translation status of incomplete or erroneous locales\n      $ php translation-status.php --incomplete\n\n      # show the translation status of all locales, all their missing translations and mismatches between trans-unit id and source\n      $ php translation-status.php -v\n\n      # show the status of a single locale\n      $ php translation-status.php fr\n\n      # show the status of a single locale, missing translations and mismatches between trans-unit id and source\n      $ php translation-status.php fr -v\n\n    END;\n\n$config = [\n    // if TRUE, the full list of missing translations is displayed\n    'verbose_output' => false,\n    // NULL = analyze all locales\n    'locale_to_analyze' => null,\n    // append --incomplete to only show incomplete languages\n    'include_completed_languages' => true,\n    // the reference files all the other translations are compared to\n    'original_files' => [\n        'src/Symfony/Component/Form/Resources/translations/validators.en.xlf',\n        'src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf',\n        'src/Symfony/Component/Validator/Resources/translations/validators.en.xlf',\n    ],\n];\n\n$argc = $_SERVER['argc'];\n$argv = $_SERVER['argv'];\n\nif ($argc > 4) {\n    echo str_replace('translation-status.php', $argv[0], $usageInstructions);\n    exit(1);\n}\n\nforeach (array_slice($argv, 1) as $argumentOrOption) {\n    if ('--incomplete' === $argumentOrOption) {\n        $config['include_completed_languages'] = false;\n        continue;\n    }\n\n    if (str_starts_with($argumentOrOption, '-')) {\n        $config['verbose_output'] = true;\n    } else {\n        $config['locale_to_analyze'] = $argumentOrOption;\n    }\n}\n\nforeach ($config['original_files'] as $originalFilePath) {\n    if (!file_exists($originalFilePath)) {\n        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);\n        exit(1);\n    }\n}\n\n$totalMissingTranslations = 0;\n$totalTranslationMismatches = 0;\n\nforeach ($config['original_files'] as $originalFilePath) {\n    $translationFilePaths = findTranslationFiles($originalFilePath, $config['locale_to_analyze']);\n    $translationStatus = calculateTranslationStatus($originalFilePath, $translationFilePaths);\n\n    $totalMissingTranslations += array_sum(array_map(static fn ($translation) => count($translation['missingKeys']), array_values($translationStatus)));\n    $totalTranslationMismatches += array_sum(array_map(static fn ($translation) => count($translation['mismatches']), array_values($translationStatus)));\n\n    printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output'], $config['include_completed_languages']);\n}\n\nexit($totalTranslationMismatches > 0 ? 1 : 0);\n\nfunction findTranslationFiles($originalFilePath, $localeToAnalyze): array\n{\n    $translations = [];\n\n    $translationsDir = dirname($originalFilePath);\n    $originalFileName = basename($originalFilePath);\n    $translationFileNamePattern = str_replace('.en.', '.*.', $originalFileName);\n\n    $translationFiles = glob($translationsDir.'/'.$translationFileNamePattern, \\GLOB_NOSORT);\n    sort($translationFiles);\n    foreach ($translationFiles as $filePath) {\n        $locale = extractLocaleFromFilePath($filePath);\n\n        if (null !== $localeToAnalyze && $locale !== $localeToAnalyze) {\n            continue;\n        }\n\n        $translations[$locale] = $filePath;\n    }\n\n    return $translations;\n}\n\nfunction calculateTranslationStatus($originalFilePath, $translationFilePaths): array\n{\n    $translationStatus = [];\n    $allTranslationKeys = extractTranslationKeys($originalFilePath);\n\n    foreach ($translationFilePaths as $locale => $translationPath) {\n        $translatedKeys = extractTranslationKeys($translationPath);\n        $missingKeys = array_diff_key($allTranslationKeys, $translatedKeys);\n        $mismatches = findTransUnitMismatches($allTranslationKeys, $translatedKeys);\n\n        $translationStatus[$locale] = [\n            'total' => count($allTranslationKeys),\n            'translated' => count($translatedKeys),\n            'missingKeys' => $missingKeys,\n            'mismatches' => $mismatches,\n        ];\n        $translationStatus[$locale]['is_completed'] = isTranslationCompleted($translationStatus[$locale]);\n    }\n\n    return $translationStatus;\n}\n\nfunction isTranslationCompleted(array $translationStatus): bool\n{\n    return $translationStatus['total'] === $translationStatus['translated'] && 0 === count($translationStatus['mismatches']);\n}\n\nfunction printTranslationStatus($originalFilePath, $translationStatus, $verboseOutput, $includeCompletedLanguages): void\n{\n    printTitle($originalFilePath);\n    printTable($translationStatus, $verboseOutput, $includeCompletedLanguages);\n    echo \\PHP_EOL.\\PHP_EOL;\n}\n\nfunction extractLocaleFromFilePath($filePath)\n{\n    $parts = explode('.', $filePath);\n\n    return $parts[count($parts) - 2];\n}\n\nfunction extractTranslationKeys($filePath): array\n{\n    $translationKeys = [];\n    $contents = new SimpleXMLElement(file_get_contents($filePath));\n\n    foreach ($contents->file->body->{'trans-unit'} as $translationKey) {\n        $translationId = (string) $translationKey['id'];\n        $translationKey = (string) ($translationKey['resname'] ?? $translationKey->source);\n\n        $translationKeys[$translationId] = $translationKey;\n    }\n\n    return $translationKeys;\n}\n\n/**\n * Check whether the trans-unit id and source match with the base translation.\n */\nfunction findTransUnitMismatches(array $baseTranslationKeys, array $translatedKeys): array\n{\n    $mismatches = [];\n\n    foreach ($baseTranslationKeys as $translationId => $translationKey) {\n        if (!isset($translatedKeys[$translationId])) {\n            continue;\n        }\n        if ($translatedKeys[$translationId] !== $translationKey) {\n            $mismatches[$translationId] = [\n                'found' => $translatedKeys[$translationId],\n                'expected' => $translationKey,\n            ];\n        }\n    }\n\n    return $mismatches;\n}\n\nfunction printTitle($title): void\n{\n    echo $title.\\PHP_EOL;\n    echo str_repeat('=', strlen($title)).\\PHP_EOL.\\PHP_EOL;\n}\n\nfunction printTable($translations, $verboseOutput, bool $includeCompletedLanguages): void\n{\n    if (0 === count($translations)) {\n        echo 'No translations found';\n\n        return;\n    }\n    $longestLocaleNameLength = max(array_map('strlen', array_keys($translations)));\n\n    foreach ($translations as $locale => $translation) {\n        if (!$includeCompletedLanguages && $translation['is_completed']) {\n            continue;\n        }\n\n        if ($translation['translated'] > $translation['total']) {\n            textColorRed();\n        } elseif (count($translation['mismatches']) > 0) {\n            textColorRed();\n        } elseif ($translation['is_completed']) {\n            textColorGreen();\n        }\n\n        echo sprintf(\n            '|  Locale: %-'.$longestLocaleNameLength.'s  |  Translated: %2d/%2d  |  Mismatches: %d  |',\n            $locale,\n            $translation['translated'],\n            $translation['total'],\n            count($translation['mismatches'])\n        ).\\PHP_EOL;\n\n        textColorNormal();\n\n        $shouldBeClosed = false;\n        if (true === $verboseOutput && count($translation['missingKeys']) > 0) {\n            echo '|    Missing Translations:'.\\PHP_EOL;\n\n            foreach ($translation['missingKeys'] as $id => $content) {\n                echo sprintf('|      (id=%s) %s', $id, $content).\\PHP_EOL;\n            }\n            $shouldBeClosed = true;\n        }\n        if (true === $verboseOutput && count($translation['mismatches']) > 0) {\n            echo '|    Mismatches between trans-unit id and source:'.\\PHP_EOL;\n\n            foreach ($translation['mismatches'] as $id => $content) {\n                echo sprintf('|      (id=%s) Expected: %s', $id, $content['expected']).\\PHP_EOL;\n                echo sprintf('|              Found:    %s', $content['found']).\\PHP_EOL;\n            }\n            $shouldBeClosed = true;\n        }\n        if ($shouldBeClosed) {\n            echo str_repeat('-', 80).\\PHP_EOL;\n        }\n    }\n}\n\nfunction textColorGreen(): void\n{\n    echo \"\\033[32m\";\n}\n\nfunction textColorRed(): void\n{\n    echo \"\\033[31m\";\n}\n\nfunction textColorNormal(): void\n{\n    echo \"\\033[0m\";\n}\n"
  },
  {
    "path": "Resources/data/parents.json",
    "content": "{\n    \"az_Cyrl\": \"root\",\n    \"bs_Cyrl\": \"root\",\n    \"en_150\": \"en_001\",\n    \"en_AG\": \"en_001\",\n    \"en_AI\": \"en_001\",\n    \"en_AT\": \"en_150\",\n    \"en_AU\": \"en_001\",\n    \"en_BB\": \"en_001\",\n    \"en_BE\": \"en_150\",\n    \"en_BM\": \"en_001\",\n    \"en_BS\": \"en_001\",\n    \"en_BW\": \"en_001\",\n    \"en_BZ\": \"en_001\",\n    \"en_CC\": \"en_001\",\n    \"en_CH\": \"en_150\",\n    \"en_CK\": \"en_001\",\n    \"en_CM\": \"en_001\",\n    \"en_CX\": \"en_001\",\n    \"en_CY\": \"en_001\",\n    \"en_CZ\": \"en_150\",\n    \"en_DE\": \"en_150\",\n    \"en_DG\": \"en_001\",\n    \"en_DK\": \"en_150\",\n    \"en_DM\": \"en_001\",\n    \"en_EE\": \"en_150\",\n    \"en_ER\": \"en_001\",\n    \"en_ES\": \"en_150\",\n    \"en_FI\": \"en_150\",\n    \"en_FJ\": \"en_001\",\n    \"en_FK\": \"en_001\",\n    \"en_FM\": \"en_001\",\n    \"en_FR\": \"en_150\",\n    \"en_GB\": \"en_001\",\n    \"en_GD\": \"en_001\",\n    \"en_GE\": \"en_150\",\n    \"en_GG\": \"en_001\",\n    \"en_GH\": \"en_001\",\n    \"en_GI\": \"en_001\",\n    \"en_GM\": \"en_001\",\n    \"en_GS\": \"en_001\",\n    \"en_GY\": \"en_001\",\n    \"en_HK\": \"en_001\",\n    \"en_HU\": \"en_150\",\n    \"en_ID\": \"en_001\",\n    \"en_IE\": \"en_001\",\n    \"en_IL\": \"en_001\",\n    \"en_IM\": \"en_001\",\n    \"en_IN\": \"en_001\",\n    \"en_IO\": \"en_001\",\n    \"en_IT\": \"en_150\",\n    \"en_JE\": \"en_001\",\n    \"en_JM\": \"en_001\",\n    \"en_KE\": \"en_001\",\n    \"en_KI\": \"en_001\",\n    \"en_KN\": \"en_001\",\n    \"en_KY\": \"en_001\",\n    \"en_LC\": \"en_001\",\n    \"en_LR\": \"en_001\",\n    \"en_LS\": \"en_001\",\n    \"en_LT\": \"en_150\",\n    \"en_LV\": \"en_150\",\n    \"en_MG\": \"en_001\",\n    \"en_MO\": \"en_001\",\n    \"en_MS\": \"en_001\",\n    \"en_MT\": \"en_001\",\n    \"en_MU\": \"en_001\",\n    \"en_MV\": \"en_001\",\n    \"en_MW\": \"en_001\",\n    \"en_MY\": \"en_001\",\n    \"en_NA\": \"en_001\",\n    \"en_NF\": \"en_001\",\n    \"en_NG\": \"en_001\",\n    \"en_NL\": \"en_150\",\n    \"en_NO\": \"en_150\",\n    \"en_NR\": \"en_001\",\n    \"en_NU\": \"en_001\",\n    \"en_NZ\": \"en_001\",\n    \"en_PG\": \"en_001\",\n    \"en_PK\": \"en_001\",\n    \"en_PL\": \"en_150\",\n    \"en_PN\": \"en_001\",\n    \"en_PT\": \"en_150\",\n    \"en_PW\": \"en_001\",\n    \"en_RO\": \"en_150\",\n    \"en_RW\": \"en_001\",\n    \"en_SB\": \"en_001\",\n    \"en_SC\": \"en_001\",\n    \"en_SD\": \"en_001\",\n    \"en_SE\": \"en_150\",\n    \"en_SG\": \"en_001\",\n    \"en_SH\": \"en_001\",\n    \"en_SI\": \"en_150\",\n    \"en_SK\": \"en_150\",\n    \"en_SL\": \"en_001\",\n    \"en_SS\": \"en_001\",\n    \"en_SX\": \"en_001\",\n    \"en_SZ\": \"en_001\",\n    \"en_TC\": \"en_001\",\n    \"en_TK\": \"en_001\",\n    \"en_TO\": \"en_001\",\n    \"en_TT\": \"en_001\",\n    \"en_TV\": \"en_001\",\n    \"en_TZ\": \"en_001\",\n    \"en_UA\": \"en_150\",\n    \"en_UG\": \"en_001\",\n    \"en_VC\": \"en_001\",\n    \"en_VG\": \"en_001\",\n    \"en_VU\": \"en_001\",\n    \"en_WS\": \"en_001\",\n    \"en_ZA\": \"en_001\",\n    \"en_ZM\": \"en_001\",\n    \"en_ZW\": \"en_001\",\n    \"es_AR\": \"es_419\",\n    \"es_BO\": \"es_419\",\n    \"es_BR\": \"es_419\",\n    \"es_BZ\": \"es_419\",\n    \"es_CL\": \"es_419\",\n    \"es_CO\": \"es_419\",\n    \"es_CR\": \"es_419\",\n    \"es_CU\": \"es_419\",\n    \"es_DO\": \"es_419\",\n    \"es_EC\": \"es_419\",\n    \"es_GT\": \"es_419\",\n    \"es_HN\": \"es_419\",\n    \"es_MX\": \"es_419\",\n    \"es_NI\": \"es_419\",\n    \"es_PA\": \"es_419\",\n    \"es_PE\": \"es_419\",\n    \"es_PR\": \"es_419\",\n    \"es_PY\": \"es_419\",\n    \"es_SV\": \"es_419\",\n    \"es_US\": \"es_419\",\n    \"es_UY\": \"es_419\",\n    \"es_VE\": \"es_419\",\n    \"ff_Adlm\": \"root\",\n    \"hi_Latn\": \"en_IN\",\n    \"kk_Arab\": \"root\",\n    \"ks_Deva\": \"root\",\n    \"nb\": \"no\",\n    \"nn\": \"no\",\n    \"pa_Arab\": \"root\",\n    \"pt_AO\": \"pt_PT\",\n    \"pt_CH\": \"pt_PT\",\n    \"pt_CV\": \"pt_PT\",\n    \"pt_GQ\": \"pt_PT\",\n    \"pt_GW\": \"pt_PT\",\n    \"pt_LU\": \"pt_PT\",\n    \"pt_MO\": \"pt_PT\",\n    \"pt_MZ\": \"pt_PT\",\n    \"pt_ST\": \"pt_PT\",\n    \"pt_TL\": \"pt_PT\",\n    \"sd_Deva\": \"root\",\n    \"sr_Latn\": \"root\",\n    \"uz_Arab\": \"root\",\n    \"uz_Cyrl\": \"root\",\n    \"zh_Hant\": \"root\",\n    \"zh_Hant_MO\": \"zh_Hant_HK\"\n}\n"
  },
  {
    "path": "Resources/data/parents.php",
    "content": "<?php\n\nreturn [\n    'az_Cyrl' => 'root',\n    'bs_Cyrl' => 'root',\n    'en_150' => 'en_001',\n    'en_AG' => 'en_001',\n    'en_AI' => 'en_001',\n    'en_AT' => 'en_150',\n    'en_AU' => 'en_001',\n    'en_BB' => 'en_001',\n    'en_BE' => 'en_150',\n    'en_BM' => 'en_001',\n    'en_BS' => 'en_001',\n    'en_BW' => 'en_001',\n    'en_BZ' => 'en_001',\n    'en_CC' => 'en_001',\n    'en_CH' => 'en_150',\n    'en_CK' => 'en_001',\n    'en_CM' => 'en_001',\n    'en_CX' => 'en_001',\n    'en_CY' => 'en_001',\n    'en_CZ' => 'en_150',\n    'en_DE' => 'en_150',\n    'en_DG' => 'en_001',\n    'en_DK' => 'en_150',\n    'en_DM' => 'en_001',\n    'en_EE' => 'en_150',\n    'en_ER' => 'en_001',\n    'en_ES' => 'en_150',\n    'en_FI' => 'en_150',\n    'en_FJ' => 'en_001',\n    'en_FK' => 'en_001',\n    'en_FM' => 'en_001',\n    'en_FR' => 'en_150',\n    'en_GB' => 'en_001',\n    'en_GD' => 'en_001',\n    'en_GE' => 'en_150',\n    'en_GG' => 'en_001',\n    'en_GH' => 'en_001',\n    'en_GI' => 'en_001',\n    'en_GM' => 'en_001',\n    'en_GS' => 'en_001',\n    'en_GY' => 'en_001',\n    'en_HK' => 'en_001',\n    'en_HU' => 'en_150',\n    'en_ID' => 'en_001',\n    'en_IE' => 'en_001',\n    'en_IL' => 'en_001',\n    'en_IM' => 'en_001',\n    'en_IN' => 'en_001',\n    'en_IO' => 'en_001',\n    'en_IT' => 'en_150',\n    'en_JE' => 'en_001',\n    'en_JM' => 'en_001',\n    'en_KE' => 'en_001',\n    'en_KI' => 'en_001',\n    'en_KN' => 'en_001',\n    'en_KY' => 'en_001',\n    'en_LC' => 'en_001',\n    'en_LR' => 'en_001',\n    'en_LS' => 'en_001',\n    'en_LT' => 'en_150',\n    'en_LV' => 'en_150',\n    'en_MG' => 'en_001',\n    'en_MO' => 'en_001',\n    'en_MS' => 'en_001',\n    'en_MT' => 'en_001',\n    'en_MU' => 'en_001',\n    'en_MV' => 'en_001',\n    'en_MW' => 'en_001',\n    'en_MY' => 'en_001',\n    'en_NA' => 'en_001',\n    'en_NF' => 'en_001',\n    'en_NG' => 'en_001',\n    'en_NL' => 'en_150',\n    'en_NO' => 'en_150',\n    'en_NR' => 'en_001',\n    'en_NU' => 'en_001',\n    'en_NZ' => 'en_001',\n    'en_PG' => 'en_001',\n    'en_PK' => 'en_001',\n    'en_PL' => 'en_150',\n    'en_PN' => 'en_001',\n    'en_PT' => 'en_150',\n    'en_PW' => 'en_001',\n    'en_RO' => 'en_150',\n    'en_RW' => 'en_001',\n    'en_SB' => 'en_001',\n    'en_SC' => 'en_001',\n    'en_SD' => 'en_001',\n    'en_SE' => 'en_150',\n    'en_SG' => 'en_001',\n    'en_SH' => 'en_001',\n    'en_SI' => 'en_150',\n    'en_SK' => 'en_150',\n    'en_SL' => 'en_001',\n    'en_SS' => 'en_001',\n    'en_SX' => 'en_001',\n    'en_SZ' => 'en_001',\n    'en_TC' => 'en_001',\n    'en_TK' => 'en_001',\n    'en_TO' => 'en_001',\n    'en_TT' => 'en_001',\n    'en_TV' => 'en_001',\n    'en_TZ' => 'en_001',\n    'en_UA' => 'en_150',\n    'en_UG' => 'en_001',\n    'en_VC' => 'en_001',\n    'en_VG' => 'en_001',\n    'en_VU' => 'en_001',\n    'en_WS' => 'en_001',\n    'en_ZA' => 'en_001',\n    'en_ZM' => 'en_001',\n    'en_ZW' => 'en_001',\n    'es_AR' => 'es_419',\n    'es_BO' => 'es_419',\n    'es_BR' => 'es_419',\n    'es_BZ' => 'es_419',\n    'es_CL' => 'es_419',\n    'es_CO' => 'es_419',\n    'es_CR' => 'es_419',\n    'es_CU' => 'es_419',\n    'es_DO' => 'es_419',\n    'es_EC' => 'es_419',\n    'es_GT' => 'es_419',\n    'es_HN' => 'es_419',\n    'es_MX' => 'es_419',\n    'es_NI' => 'es_419',\n    'es_PA' => 'es_419',\n    'es_PE' => 'es_419',\n    'es_PR' => 'es_419',\n    'es_PY' => 'es_419',\n    'es_SV' => 'es_419',\n    'es_US' => 'es_419',\n    'es_UY' => 'es_419',\n    'es_VE' => 'es_419',\n    'ff_Adlm' => 'root',\n    'hi_Latn' => 'en_IN',\n    'kk_Arab' => 'root',\n    'ks_Deva' => 'root',\n    'nb' => 'no',\n    'nn' => 'no',\n    'pa_Arab' => 'root',\n    'pt_AO' => 'pt_PT',\n    'pt_CH' => 'pt_PT',\n    'pt_CV' => 'pt_PT',\n    'pt_GQ' => 'pt_PT',\n    'pt_GW' => 'pt_PT',\n    'pt_LU' => 'pt_PT',\n    'pt_MO' => 'pt_PT',\n    'pt_MZ' => 'pt_PT',\n    'pt_ST' => 'pt_PT',\n    'pt_TL' => 'pt_PT',\n    'sd_Deva' => 'root',\n    'sr_Latn' => 'root',\n    'uz_Arab' => 'root',\n    'uz_Cyrl' => 'root',\n    'zh_Hant' => 'root',\n    'zh_Hant_MO' => 'zh_Hant_HK',\n];\n"
  },
  {
    "path": "Resources/functions.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nif (!\\function_exists(t::class)) {\n    /**\n     * @author Nate Wiebe <nate@northern.co>\n     */\n    function t(string $message, array $parameters = [], ?string $domain = null): TranslatableMessage\n    {\n        return new TranslatableMessage($message, $parameters, $domain);\n    }\n}\n"
  },
  {
    "path": "Resources/schemas/xliff-core-1.2-transitional.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\nMay-19-2004:\n- Changed the <choice> for ElemType_header, moving minOccurs=\"0\" maxOccurs=\"unbounded\" from its elements\nto <choice> itself.\n- Added <choice> for ElemType_trans-unit to allow \"any order\" for <context-group>, <count-group>, <prop-group>, <note>, and\n<alt-trans>.\n\nOct-2005\n- updated version info to 1.2\n- equiv-trans attribute to <trans-unit> element\n- merged-trans attribute for <group> element\n- Add the <seg-source> element as optional in the <trans-unit> and <alt-trans> content models, at the same level as <source>\n- Create a new value \"seg\" for the mtype attribute of the <mrk> element\n- Add mid as an optional attribute for the <alt-trans> element\n\nNov-14-2005\n- Changed name attribute for <context-group> from required to optional\n- Added extension point at <xliff>\n\nJan-9-2006\n- Added alttranstype type attribute to <alt-trans>, and values\n\nJan-10-2006\n- Corrected error with overwritten purposeValueList\n- Corrected name=\"AttrType_Version\",  attribute should have been \"name\"\n\n-->\n<xsd:schema xmlns:xlf=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" targetNamespace=\"urn:oasis:names:tc:xliff:document:1.2\" xml:lang=\"en\">\n  <!-- Import for xml:lang and xml:space -->\n  <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" schemaLocation=\"http://www.w3.org/2001/xml.xsd\"/>\n  <!-- Attributes Lists -->\n  <xsd:simpleType name=\"XTend\">\n    <xsd:restriction base=\"xsd:string\">\n      <xsd:pattern value=\"x-[^\\s]+\"/>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"context-typeValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'context-type'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:string\">\n      <xsd:enumeration value=\"database\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a database content.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"element\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the content of an element within an XML document.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"elementtitle\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the name of an element within an XML document.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"linenumber\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the line number from the sourcefile (see context-type=\"sourcefile\") where the &lt;source&gt; is found.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"numparams\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a the number of parameters contained within the &lt;source&gt;.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"paramnotes\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates notes pertaining to the parameters in the &lt;source&gt;.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"record\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the content of a record within a database.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"recordtitle\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the name of a record within a database.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"sourcefile\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the original source file in the case that multiple files are merged to form the original file from which the XLIFF file is created. This differs from the original &lt;file&gt; attribute in that this sourcefile is one of many that make up that file.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"count-typeValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'count-type'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"num-usages\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the count units are items that are used X times in a certain context; example: this is a reusable text unit which is used 42 times in other texts.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"repetition\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the count units are translation units existing already in the same document.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"total\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a total count.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"InlineDelimitersValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'ctype' when used other elements than &lt;ph&gt; or &lt;x&gt;.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"bold\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a run of bolded text.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"italic\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a run of text in italics.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"underlined\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a run of underlined text.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"link\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a run of hyper-text.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"InlinePlaceholdersValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'ctype' when used with &lt;ph&gt; or &lt;x&gt;.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"image\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a inline image.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"pb\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a page break.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"lb\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a line break.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"mime-typeValueList\">\n    <xsd:restriction base=\"xsd:string\">\n      <xsd:pattern value=\"(text|multipart|message|application|image|audio|video|model)(/.+)*\"/>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"datatypeValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'datatype'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"asp\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Active Server Page data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"c\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates C source file data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"cdf\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Channel Definition Format (CDF) data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"cfm\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates ColdFusion data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"cpp\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates C++ source file data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"csharp\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates C-Sharp data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"cstring\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates strings from C, ASM, and driver files data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"csv\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates comma-separated values data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"database\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates database data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"documentfooter\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates portions of document that follows data and contains metadata.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"documentheader\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates portions of document that precedes data and contains metadata.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"filedialog\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates data from standard UI file operations dialogs (e.g., Open, Save, Save As, Export, Import).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"form\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates standard user input screen data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"html\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates HyperText Markup Language (HTML) data - document instance.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"htmlbody\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates content within an HTML document’s &lt;body&gt; element.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"ini\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Windows INI file data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"interleaf\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Interleaf data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"javaclass\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Java source file data (extension '.java').</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"javapropertyresourcebundle\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Java property resource bundle data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"javalistresourcebundle\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Java list resource bundle data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"javascript\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates JavaScript source file data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"jscript\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates JScript source file data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"layout\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates information relating to formatting.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"lisp\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates LISP source file data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"margin\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates information relating to margin formats.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"menufile\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a file containing menu.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"messagefile\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates numerically identified string table.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"mif\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Maker Interchange Format (MIF) data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"mimetype\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the datatype attribute value is a MIME Type value and is defined in the mime-type attribute.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"mo\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates GNU Machine Object data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"msglib\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Message Librarian strings created by Novell's Message Librarian Tool.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"pagefooter\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates information to be displayed at the bottom of each page of a document.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"pageheader\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates information to be displayed at the top of each page of a document.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"parameters\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a list of property values (e.g., settings within INI files or preferences dialog).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"pascal\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Pascal source file data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"php\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Hypertext Preprocessor data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"plaintext\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates plain text file (no formatting other than, possibly, wrapping).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"po\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates GNU Portable Object file.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"report\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates dynamically generated user defined document. e.g. Oracle Report, Crystal Report, etc.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"resources\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Windows .NET binary resources.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"resx\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Windows .NET Resources.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"rtf\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Rich Text Format (RTF) data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"sgml\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - document instance.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"sgmldtd\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - Document Type Definition (DTD).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"svg\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Scalable Vector Graphic (SVG) data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"vbscript\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates VisualBasic Script source file.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"warning\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates warning message.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"winres\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Windows (Win32) resources (i.e. resources extracted from an RC script, a message file, or a compiled file).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"xhtml\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Extensible HyperText Markup Language (XHTML) data - document instance.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"xml\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Extensible Markup Language (XML) data - document instance.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"xmldtd\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Extensible Markup Language (XML) data - Document Type Definition (DTD).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"xsl\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates Extensible Stylesheet Language (XSL) data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"xul\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates XUL elements.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"mtypeValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'mtype'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"abbrev\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the marked text is an abbreviation.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"abbreviated-form\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.8: A term resulting from the omission of any part of the full term while designating the same concept.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"abbreviation\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.8.1: An abbreviated form of a simple term resulting from the omission of some of its letters (e.g. 'adj.' for 'adjective').</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"acronym\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.8.4: An abbreviated form of a term made up of letters from the full form of a multiword term strung together into a sequence pronounced only syllabically (e.g. 'radar' for 'radio detecting and ranging').</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"appellation\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620: A proper-name term, such as the name of an agency or other proper entity.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"collocation\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.18.1: A recurrent word combination characterized by cohesion in that the components of the collocation must co-occur within an utterance or series of utterances, even though they do not necessarily have to maintain immediate proximity to one another.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"common-name\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.5: A synonym for an international scientific term that is used in general discourse in a given language.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"datetime\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the marked text is a date and/or time.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"equation\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.15: An expression used to represent a concept based on a statement that two mathematical expressions are, for instance, equal as identified by the equal sign (=), or assigned to one another by a similar sign.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"expanded-form\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.7: The complete representation of a term for which there is an abbreviated form.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"formula\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.14: Figures, symbols or the like used to express a concept briefly, such as a mathematical or chemical formula.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"head-term\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.1: The concept designation that has been chosen to head a terminological record.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"initialism\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.8.3: An abbreviated form of a term consisting of some of the initial letters of the words making up a multiword term or the term elements making up a compound term when these letters are pronounced individually (e.g. 'BSE' for 'bovine spongiform encephalopathy').</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"international-scientific-term\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.4: A term that is part of an international scientific nomenclature as adopted by an appropriate scientific body.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"internationalism\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.6: A term that has the same or nearly identical orthographic or phonemic form in many languages.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"logical-expression\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.16: An expression used to represent a concept based on mathematical or logical relations, such as statements of inequality, set relationships, Boolean operations, and the like.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"materials-management-unit\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.17: A unit to track object.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"name\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the marked text is a name.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"near-synonym\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.3: A term that represents the same or a very similar concept as another term in the same language, but for which interchangeability is limited to some contexts and inapplicable in others.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"part-number\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.17.2: A unique alphanumeric designation assigned to an object in a manufacturing system.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"phrase\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the marked text is a phrase.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"phraseological-unit\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.18: Any group of two or more words that form a unit, the meaning of which frequently cannot be deduced based on the combined sense of the words making up the phrase.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"protected\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the marked text should not be translated.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"romanized-form\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.12: A form of a term resulting from an operation whereby non-Latin writing systems are converted to the Latin alphabet.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"seg\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the marked text represents a segment.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"set-phrase\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.18.2: A fixed, lexicalized phrase.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"short-form\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.8.2: A variant of a multiword term that includes fewer words than the full form of the term (e.g. 'Group of Twenty-four' for 'Intergovernmental Group of Twenty-four on International Monetary Affairs').</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"sku\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.17.1: Stock keeping unit, an inventory item identified by a unique alphanumeric designation assigned to an object in an inventory control system.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"standard-text\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.19: A fixed chunk of recurring text.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"symbol\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.13: A designation of a concept by letters, numerals, pictograms or any combination thereof.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"synonym\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.2: Any term that represents the same or a very similar concept as the main entry term in a term entry.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"synonymous-phrase\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.18.3: Phraseological unit in a language that expresses the same semantic content as another phrase in that same language.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"term\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the marked text is a term.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"transcribed-form\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.11: A form of a term resulting from an operation whereby the characters of one writing system are represented by characters from another writing system, taking into account the pronunciation of the characters converted.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"transliterated-form\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.10: A form of a term resulting from an operation whereby the characters of an alphabetic writing system are represented by characters from another alphabetic writing system.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"truncated-term\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.8.5: An abbreviated form of a term resulting from the omission of one or more term elements or syllables (e.g. 'flu' for 'influenza').</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"variant\">\n        <xsd:annotation>\n          <xsd:documentation>ISO-12620 2.1.9: One of the alternate forms of a term.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"restypeValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'restype'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"auto3state\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC AUTO3STATE control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"autocheckbox\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC AUTOCHECKBOX control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"autoradiobutton\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC AUTORADIOBUTTON control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"bedit\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC BEDIT control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"bitmap\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a bitmap, for example a BITMAP resource in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"button\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a button object, for example a BUTTON control Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"caption\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a caption, such as the caption of a dialog box.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"cell\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the cell in a table, for example the content of the &lt;td&gt; element in HTML.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"checkbox\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates check box object, for example a CHECKBOX control in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"checkboxmenuitem\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a menu item with an associated checkbox.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"checkedlistbox\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a list box, but with a check-box for each item.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"colorchooser\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a color selection dialog.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"combobox\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a combination of edit box and listbox object, for example a COMBOBOX control in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"comboboxexitem\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates an initialization entry of an extended combobox DLGINIT resource block. (code 0x1234).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"comboboxitem\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates an initialization entry of a combobox DLGINIT resource block (code 0x0403).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"component\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a UI base class element that cannot be represented by any other element.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"contextmenu\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a context menu.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"ctext\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC CTEXT control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"cursor\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a cursor, for example a CURSOR resource in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"datetimepicker\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a date/time picker.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"defpushbutton\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC DEFPUSHBUTTON control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"dialog\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a dialog box.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"dlginit\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC DLGINIT resource block.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"edit\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates an edit box object, for example an EDIT control in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"file\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a filename.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"filechooser\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a file dialog.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"fn\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a footnote.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"font\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a font name.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"footer\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a footer.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"frame\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a frame object.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"grid\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a XUL grid element.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"groupbox\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a groupbox object, for example a GROUPBOX control in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"header\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a header item.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"heading\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a heading, such has the content of &lt;h1&gt;, &lt;h2&gt;, etc. in HTML.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"hedit\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC HEDIT control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"hscrollbar\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a horizontal scrollbar.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"icon\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates an icon, for example an ICON resource in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"iedit\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC IEDIT control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"keywords\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates keyword list, such as the content of the Keywords meta-data in HTML, or a K footnote in WinHelp RTF.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"label\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a label object.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"linklabel\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a label that is also a HTML link (not necessarily a URL).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"list\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a list (a group of list-items, for example an &lt;ol&gt; or &lt;ul&gt; element in HTML).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"listbox\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a listbox object, for example an LISTBOX control in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"listitem\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates an list item (an entry in a list).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"ltext\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC LTEXT control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"menu\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a menu (a group of menu-items).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"menubar\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a toolbar containing one or more tope level menus.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"menuitem\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a menu item (an entry in a menu).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"menuseparator\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a XUL menuseparator element.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"message\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a message, for example an entry in a MESSAGETABLE resource in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"monthcalendar\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a calendar control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"numericupdown\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates an edit box beside a spin control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"panel\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a catch all for rectangular areas.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"popupmenu\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a standalone menu not necessarily associated with a menubar.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"pushbox\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a pushbox object, for example a PUSHBOX control in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"pushbutton\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC PUSHBUTTON control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"radio\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a radio button object.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"radiobuttonmenuitem\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a menuitem with associated radio button.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"rcdata\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates raw data resources for an application.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"row\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a row in a table.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"rtext\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC RTEXT control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"scrollpane\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a user navigable container used to show a portion of a document.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"separator\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a generic divider object (e.g. menu group separator).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"shortcut\">\n        <xsd:annotation>\n          <xsd:documentation>Windows accelerators, shortcuts in resource or property files.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"spinner\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a UI control to indicate process activity but not progress.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"splitter\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a splitter bar.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"state3\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC STATE3 control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"statusbar\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a window for providing feedback to the users, like 'read-only', etc.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"string\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a string, for example an entry in a STRINGTABLE resource in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"tabcontrol\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a layers of controls with a tab to select layers.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"table\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a display and edits regular two-dimensional tables of cells.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"textbox\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a XUL textbox element.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"togglebutton\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a UI button that can be toggled to on or off state.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"toolbar\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates an array of controls, usually buttons.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"tooltip\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a pop up tool tip text.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"trackbar\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a bar with a pointer indicating a position within a certain range.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"tree\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a control that displays a set of hierarchical data.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"uri\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a URI (URN or URL).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"userbutton\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a Windows RC USERBUTTON control.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"usercontrol\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a user-defined control like CONTROL control in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"var\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the text of a variable.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"versioninfo\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates version information about a resource like VERSIONINFO in Windows.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"vscrollbar\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a vertical scrollbar.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"window\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a graphical window.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"size-unitValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'size-unit'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"byte\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in 8-bit bytes.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"char\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in Unicode characters.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"col\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in columns. Used for HTML text area.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"cm\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in centimeters.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"dlgunit\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in dialog units, as defined in Windows resources.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"em\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in 'font-size' units (as defined in CSS).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"ex\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in 'x-height' units (as defined in CSS).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"glyph\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in glyphs. A glyph is considered to be one or more combined Unicode characters that represent a single displayable text character. Sometimes referred to as a 'grapheme cluster'</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"in\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in inches.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"mm\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in millimeters.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"percent\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in percentage.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"pixel\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in pixels.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"point\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in point.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"row\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a size in rows. Used for HTML text area.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"stateValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'state'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"final\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the terminating state.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"needs-adaptation\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates only non-textual information needs adaptation.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"needs-l10n\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates both text and non-textual information needs adaptation.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"needs-review-adaptation\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates only non-textual information needs review.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"needs-review-l10n\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates both text and non-textual information needs review.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"needs-review-translation\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that only the text of the item needs to be reviewed.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"needs-translation\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the item needs to be translated.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"new\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the item is new. For example, translation units that were not in a previous version of the document.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"signed-off\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that changes are reviewed and approved.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"translated\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the item has been translated.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"state-qualifierValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'state-qualifier'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"exact-match\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates an exact match. An exact match occurs when a source text of a segment is exactly the same as the source text of a segment that was translated previously.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"fuzzy-match\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a fuzzy match. A fuzzy match occurs when a source text of a segment is very similar to the source text of a segment that was translated previously (e.g. when the difference is casing, a few changed words, white-space discripancy, etc.).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"id-match\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a match based on matching IDs (in addition to matching text).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"leveraged-glossary\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a translation derived from a glossary.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"leveraged-inherited\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a translation derived from existing translation.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"leveraged-mt\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a translation derived from machine translation.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"leveraged-repository\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a translation derived from a translation repository.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"leveraged-tm\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates a translation derived from a translation memory.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"mt-suggestion\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the translation is suggested by machine translation.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"rejected-grammar\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the item has been rejected because of incorrect grammar.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"rejected-inaccurate\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the item has been rejected because it is incorrect.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"rejected-length\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the item has been rejected because it is too long or too short.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"rejected-spelling\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the item has been rejected because of incorrect spelling.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"tm-suggestion\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates the translation is suggested by translation memory.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"unitValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'unit'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"word\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to words.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"page\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to pages.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"trans-unit\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to &lt;trans-unit&gt; elements.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"bin-unit\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to &lt;bin-unit&gt; elements.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"glyph\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to glyphs.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"item\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to &lt;trans-unit&gt; and/or &lt;bin-unit&gt; elements.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"instance\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to the occurrences of instances defined by the count-type value.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"character\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to characters.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"line\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to lines.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"sentence\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to sentences.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"paragraph\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to paragraphs.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"segment\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to segments.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"placeable\">\n        <xsd:annotation>\n          <xsd:documentation>Refers to placeables (inline elements).</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"priorityValueList\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'priority'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:positiveInteger\">\n      <xsd:enumeration value=\"1\">\n        <xsd:annotation>\n          <xsd:documentation>Highest priority.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"2\">\n        <xsd:annotation>\n          <xsd:documentation>High priority.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"3\">\n        <xsd:annotation>\n          <xsd:documentation>High priority, but not as important as 2.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"4\">\n        <xsd:annotation>\n          <xsd:documentation>High priority, but not as important as 3.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"5\">\n        <xsd:annotation>\n          <xsd:documentation>Medium priority, but more important than 6.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"6\">\n        <xsd:annotation>\n          <xsd:documentation>Medium priority, but less important than 5.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"7\">\n        <xsd:annotation>\n          <xsd:documentation>Low priority, but more important than 8.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"8\">\n        <xsd:annotation>\n          <xsd:documentation>Low priority, but more important than 9.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"9\">\n        <xsd:annotation>\n          <xsd:documentation>Low priority.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"10\">\n        <xsd:annotation>\n          <xsd:documentation>Lowest priority.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"reformatValueYesNo\">\n    <xsd:restriction base=\"xsd:string\">\n      <xsd:enumeration value=\"yes\">\n        <xsd:annotation>\n          <xsd:documentation>This value indicates that all properties can be reformatted. This value must be used alone.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"no\">\n        <xsd:annotation>\n          <xsd:documentation>This value indicates that no properties should be reformatted. This value must be used alone.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"reformatValueList\">\n    <xsd:list>\n      <xsd:simpleType>\n        <xsd:union memberTypes=\"xlf:XTend\">\n          <xsd:simpleType>\n            <xsd:restriction base=\"xsd:string\">\n              <xsd:enumeration value=\"coord\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that all information in the coord attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"coord-x\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the x information in the coord attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"coord-y\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the y information in the coord attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"coord-cx\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the cx information in the coord attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"coord-cy\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the cy information in the coord attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"font\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that all the information in the font attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"font-name\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the name information in the font attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"font-size\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the size information in the font attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"font-weight\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the weight information in the font attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"css-style\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the information in the css-style attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"style\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the information in the style attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n              <xsd:enumeration value=\"ex-style\">\n                <xsd:annotation>\n                  <xsd:documentation>This value indicates that the information in the exstyle attribute can be modified.</xsd:documentation>\n                </xsd:annotation>\n              </xsd:enumeration>\n            </xsd:restriction>\n          </xsd:simpleType>\n        </xsd:union>\n      </xsd:simpleType>\n    </xsd:list>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"purposeValueList\">\n    <xsd:restriction base=\"xsd:string\">\n      <xsd:enumeration value=\"information\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the context is informational in nature, specifying for example, how a term should be translated. Thus, should be displayed to anyone editing the XLIFF document.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"location\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the context-group is used to specify where the term was found in the translatable source. Thus, it is not displayed.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"match\">\n        <xsd:annotation>\n          <xsd:documentation>Indicates that the context information should be used during translation memory lookups. Thus, it is not displayed.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"alttranstypeValueList\">\n    <xsd:restriction base=\"xsd:string\">\n      <xsd:enumeration value=\"proposal\">\n        <xsd:annotation>\n          <xsd:documentation>Represents a translation proposal from a translation memory or other resource.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"previous-version\">\n        <xsd:annotation>\n          <xsd:documentation>Represents a previous version of the target element.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"rejected\">\n        <xsd:annotation>\n          <xsd:documentation>Represents a rejected version of the target element.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"reference\">\n        <xsd:annotation>\n          <xsd:documentation>Represents a translation to be used for reference purposes only, for example from a related product or a different language.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n      <xsd:enumeration value=\"accepted\">\n        <xsd:annotation>\n          <xsd:documentation>Represents a proposed translation that was used for the translation of the trans-unit, possibly modified.</xsd:documentation>\n        </xsd:annotation>\n      </xsd:enumeration>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <!-- Other Types -->\n  <xsd:complexType name=\"ElemType_ExternalReference\">\n    <xsd:choice>\n      <xsd:element ref=\"xlf:internal-file\"/>\n      <xsd:element ref=\"xlf:external-file\"/>\n    </xsd:choice>\n  </xsd:complexType>\n  <xsd:simpleType name=\"AttrType_purpose\">\n    <xsd:list>\n      <xsd:simpleType>\n        <xsd:union memberTypes=\"xlf:purposeValueList xlf:XTend\"/>\n      </xsd:simpleType>\n    </xsd:list>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_datatype\">\n    <xsd:union memberTypes=\"xlf:datatypeValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_restype\">\n    <xsd:union memberTypes=\"xlf:restypeValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_alttranstype\">\n    <xsd:union memberTypes=\"xlf:alttranstypeValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_context-type\">\n    <xsd:union memberTypes=\"xlf:context-typeValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_state\">\n    <xsd:union memberTypes=\"xlf:stateValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_state-qualifier\">\n    <xsd:union memberTypes=\"xlf:state-qualifierValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_count-type\">\n    <xsd:union memberTypes=\"xlf:restypeValueList xlf:count-typeValueList xlf:datatypeValueList xlf:stateValueList xlf:state-qualifierValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_InlineDelimiters\">\n    <xsd:union memberTypes=\"xlf:InlineDelimitersValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_InlinePlaceholders\">\n    <xsd:union memberTypes=\"xlf:InlinePlaceholdersValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_size-unit\">\n    <xsd:union memberTypes=\"xlf:size-unitValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_mtype\">\n    <xsd:union memberTypes=\"xlf:mtypeValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_unit\">\n    <xsd:union memberTypes=\"xlf:unitValueList xlf:XTend\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_priority\">\n    <xsd:union memberTypes=\"xlf:priorityValueList\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_reformat\">\n    <xsd:union memberTypes=\"xlf:reformatValueYesNo xlf:reformatValueList\"/>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_YesNo\">\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"yes\"/>\n      <xsd:enumeration value=\"no\"/>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_Position\">\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"open\"/>\n      <xsd:enumeration value=\"close\"/>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_assoc\">\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"preceding\"/>\n      <xsd:enumeration value=\"following\"/>\n      <xsd:enumeration value=\"both\"/>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_annotates\">\n    <xsd:restriction base=\"xsd:NMTOKEN\">\n      <xsd:enumeration value=\"source\"/>\n      <xsd:enumeration value=\"target\"/>\n      <xsd:enumeration value=\"general\"/>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_Coordinates\">\n    <xsd:annotation>\n      <xsd:documentation>Values for the attribute 'coord'.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:string\">\n      <xsd:pattern value=\"(-?\\d+|#);(-?\\d+|#);(-?\\d+|#);(-?\\d+|#)\"/>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <xsd:simpleType name=\"AttrType_Version\">\n    <xsd:annotation>\n      <xsd:documentation>Version values: 1.0 and 1.1 are allowed for backward compatibility.</xsd:documentation>\n    </xsd:annotation>\n    <xsd:restriction base=\"xsd:string\">\n      <xsd:enumeration value=\"1.2\"/>\n      <xsd:enumeration value=\"1.1\"/>\n      <xsd:enumeration value=\"1.0\"/>\n    </xsd:restriction>\n  </xsd:simpleType>\n  <!-- Groups -->\n  <xsd:group name=\"ElemGroup_TextContent\">\n    <xsd:choice>\n      <xsd:element ref=\"xlf:g\"/>\n      <xsd:element ref=\"xlf:bpt\"/>\n      <xsd:element ref=\"xlf:ept\"/>\n      <xsd:element ref=\"xlf:ph\"/>\n      <xsd:element ref=\"xlf:it\"/>\n      <xsd:element ref=\"xlf:mrk\"/>\n      <xsd:element ref=\"xlf:x\"/>\n      <xsd:element ref=\"xlf:bx\"/>\n      <xsd:element ref=\"xlf:ex\"/>\n    </xsd:choice>\n  </xsd:group>\n  <xsd:attributeGroup name=\"AttrGroup_TextContent\">\n    <xsd:attribute name=\"id\" type=\"xsd:string\" use=\"required\"/>\n    <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n    <xsd:attribute name=\"xid\" type=\"xsd:string\" use=\"optional\"/>\n    <xsd:attribute name=\"equiv-text\" type=\"xsd:string\" use=\"optional\"/>\n    <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n  </xsd:attributeGroup>\n  <!-- XLIFF Structure -->\n  <xsd:element name=\"xliff\">\n    <xsd:complexType>\n      <xsd:sequence maxOccurs=\"unbounded\">\n        <xsd:any maxOccurs=\"unbounded\" minOccurs=\"0\" namespace=\"##other\" processContents=\"skip\"/>\n        <xsd:element ref=\"xlf:file\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"version\" type=\"xlf:AttrType_Version\" use=\"required\"/>\n      <xsd:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"file\">\n    <xsd:complexType>\n      <xsd:sequence>\n        <xsd:element minOccurs=\"0\" ref=\"xlf:header\"/>\n        <xsd:element ref=\"xlf:body\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"original\" type=\"xsd:string\" use=\"required\"/>\n      <xsd:attribute name=\"source-language\" type=\"xsd:language\" use=\"required\"/>\n      <xsd:attribute name=\"datatype\" type=\"xlf:AttrType_datatype\" use=\"required\"/>\n      <xsd:attribute name=\"tool-id\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute default=\"manual\" name=\"tool\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"date\" type=\"xsd:dateTime\" use=\"optional\"/>\n      <xsd:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"category\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"target-language\" type=\"xsd:language\" use=\"optional\"/>\n      <xsd:attribute name=\"product-name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"product-version\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"build-num\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n    <xsd:unique name=\"U_group_id\">\n      <xsd:selector xpath=\".//xlf:group\"/>\n      <xsd:field xpath=\"@id\"/>\n    </xsd:unique>\n    <xsd:key name=\"K_unit_id\">\n      <xsd:selector xpath=\".//xlf:trans-unit|.//xlf:bin-unit\"/>\n      <xsd:field xpath=\"@id\"/>\n    </xsd:key>\n    <xsd:keyref name=\"KR_unit_id\" refer=\"xlf:K_unit_id\">\n      <xsd:selector xpath=\".//bpt|.//ept|.//it|.//ph|.//g|.//x|.//bx|.//ex|.//sub\"/>\n      <xsd:field xpath=\"@xid\"/>\n    </xsd:keyref>\n    <xsd:key name=\"K_tool-id\">\n      <xsd:selector xpath=\"xlf:header/xlf:tool\"/>\n      <xsd:field xpath=\"@tool-id\"/>\n    </xsd:key>\n    <xsd:keyref name=\"KR_file_tool-id\" refer=\"xlf:K_tool-id\">\n      <xsd:selector xpath=\".\"/>\n      <xsd:field xpath=\"@tool-id\"/>\n    </xsd:keyref>\n    <xsd:keyref name=\"KR_phase_tool-id\" refer=\"xlf:K_tool-id\">\n      <xsd:selector xpath=\"xlf:header/xlf:phase-group/xlf:phase\"/>\n      <xsd:field xpath=\"@tool-id\"/>\n    </xsd:keyref>\n    <xsd:keyref name=\"KR_alt-trans_tool-id\" refer=\"xlf:K_tool-id\">\n      <xsd:selector xpath=\".//xlf:trans-unit/xlf:alt-trans\"/>\n      <xsd:field xpath=\"@tool-id\"/>\n    </xsd:keyref>\n    <xsd:key name=\"K_count-group_name\">\n      <xsd:selector xpath=\".//xlf:count-group\"/>\n      <xsd:field xpath=\"@name\"/>\n    </xsd:key>\n    <xsd:unique name=\"U_context-group_name\">\n      <xsd:selector xpath=\".//xlf:context-group\"/>\n      <xsd:field xpath=\"@name\"/>\n    </xsd:unique>\n    <xsd:key name=\"K_phase-name\">\n      <xsd:selector xpath=\"xlf:header/xlf:phase-group/xlf:phase\"/>\n      <xsd:field xpath=\"@phase-name\"/>\n    </xsd:key>\n    <xsd:keyref name=\"KR_phase-name\" refer=\"xlf:K_phase-name\">\n      <xsd:selector xpath=\".//xlf:count|.//xlf:trans-unit|.//xlf:target|.//bin-unit|.//bin-target\"/>\n      <xsd:field xpath=\"@phase-name\"/>\n    </xsd:keyref>\n    <xsd:unique name=\"U_uid\">\n      <xsd:selector xpath=\".//xlf:external-file\"/>\n      <xsd:field xpath=\"@uid\"/>\n    </xsd:unique>\n  </xsd:element>\n  <xsd:element name=\"header\">\n    <xsd:complexType>\n      <xsd:sequence>\n        <xsd:element minOccurs=\"0\" name=\"skl\" type=\"xlf:ElemType_ExternalReference\"/>\n        <xsd:element minOccurs=\"0\" ref=\"xlf:phase-group\"/>\n        <xsd:choice maxOccurs=\"unbounded\" minOccurs=\"0\">\n          <xsd:element name=\"glossary\" type=\"xlf:ElemType_ExternalReference\"/>\n          <xsd:element name=\"reference\" type=\"xlf:ElemType_ExternalReference\"/>\n          <xsd:element ref=\"xlf:count-group\"/>\n          <xsd:element ref=\"xlf:prop-group\"/>\n          <xsd:element ref=\"xlf:note\"/>\n          <xsd:element ref=\"xlf:tool\"/>\n        </xsd:choice>\n        <xsd:any maxOccurs=\"unbounded\" minOccurs=\"0\" namespace=\"##other\" processContents=\"skip\"/>\n      </xsd:sequence>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"internal-file\">\n    <xsd:complexType>\n      <xsd:simpleContent>\n        <xsd:extension base=\"xsd:string\">\n          <xsd:attribute name=\"form\" type=\"xsd:string\"/>\n          <xsd:attribute name=\"crc\" type=\"xsd:NMTOKEN\"/>\n        </xsd:extension>\n      </xsd:simpleContent>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"external-file\">\n    <xsd:complexType>\n      <xsd:attribute name=\"href\" type=\"xsd:string\" use=\"required\"/>\n      <xsd:attribute name=\"crc\" type=\"xsd:NMTOKEN\"/>\n      <xsd:attribute name=\"uid\" type=\"xsd:NMTOKEN\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"note\">\n    <xsd:complexType>\n      <xsd:simpleContent>\n        <xsd:extension base=\"xsd:string\">\n          <xsd:attribute ref=\"xml:lang\" use=\"optional\"/>\n          <xsd:attribute default=\"1\" name=\"priority\" type=\"xlf:AttrType_priority\" use=\"optional\"/>\n          <xsd:attribute name=\"from\" type=\"xsd:string\" use=\"optional\"/>\n          <xsd:attribute default=\"general\" name=\"annotates\" type=\"xlf:AttrType_annotates\" use=\"optional\"/>\n        </xsd:extension>\n      </xsd:simpleContent>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"phase-group\">\n    <xsd:complexType>\n      <xsd:sequence maxOccurs=\"unbounded\">\n        <xsd:element ref=\"xlf:phase\"/>\n      </xsd:sequence>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"phase\">\n    <xsd:complexType>\n      <xsd:sequence maxOccurs=\"unbounded\" minOccurs=\"0\">\n        <xsd:element ref=\"xlf:note\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"phase-name\" type=\"xsd:string\" use=\"required\"/>\n      <xsd:attribute name=\"process-name\" type=\"xsd:string\" use=\"required\"/>\n      <xsd:attribute name=\"company-name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"tool-id\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"tool\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"date\" type=\"xsd:dateTime\" use=\"optional\"/>\n      <xsd:attribute name=\"job-id\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"contact-name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"contact-email\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"contact-phone\" type=\"xsd:string\" use=\"optional\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"count-group\">\n    <xsd:complexType>\n      <xsd:sequence maxOccurs=\"unbounded\" minOccurs=\"0\">\n        <xsd:element ref=\"xlf:count\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"count\">\n    <xsd:complexType>\n      <xsd:simpleContent>\n        <xsd:extension base=\"xsd:string\">\n          <xsd:attribute name=\"count-type\" type=\"xlf:AttrType_count-type\" use=\"optional\"/>\n          <xsd:attribute name=\"phase-name\" type=\"xsd:string\" use=\"optional\"/>\n          <xsd:attribute default=\"word\" name=\"unit\" type=\"xlf:AttrType_unit\" use=\"optional\"/>\n        </xsd:extension>\n      </xsd:simpleContent>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"context-group\">\n    <xsd:complexType>\n      <xsd:sequence maxOccurs=\"unbounded\">\n        <xsd:element ref=\"xlf:context\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"crc\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"purpose\" type=\"xlf:AttrType_purpose\" use=\"optional\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"context\">\n    <xsd:complexType>\n      <xsd:simpleContent>\n        <xsd:extension base=\"xsd:string\">\n          <xsd:attribute name=\"context-type\" type=\"xlf:AttrType_context-type\" use=\"required\"/>\n          <xsd:attribute default=\"no\" name=\"match-mandatory\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n          <xsd:attribute name=\"crc\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n        </xsd:extension>\n      </xsd:simpleContent>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"prop-group\">\n    <xsd:complexType>\n      <xsd:sequence maxOccurs=\"unbounded\">\n        <xsd:element ref=\"xlf:prop\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"optional\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"prop\">\n    <xsd:complexType>\n      <xsd:simpleContent>\n        <xsd:extension base=\"xsd:string\">\n          <xsd:attribute name=\"prop-type\" type=\"xsd:string\" use=\"required\"/>\n          <xsd:attribute ref=\"xml:lang\" use=\"optional\"/>\n        </xsd:extension>\n      </xsd:simpleContent>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"tool\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:sequence>\n        <xsd:any namespace=\"##any\" processContents=\"skip\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"tool-id\" type=\"xsd:string\" use=\"required\"/>\n      <xsd:attribute name=\"tool-name\" type=\"xsd:string\" use=\"required\"/>\n      <xsd:attribute name=\"tool-version\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"tool-company\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"body\">\n    <xsd:complexType>\n      <xsd:choice maxOccurs=\"unbounded\" minOccurs=\"0\">\n        <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:group\"/>\n        <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:trans-unit\"/>\n        <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:bin-unit\"/>\n      </xsd:choice>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"group\">\n    <xsd:complexType>\n      <xsd:sequence>\n        <xsd:sequence>\n          <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:context-group\"/>\n          <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:count-group\"/>\n          <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:prop-group\"/>\n          <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:note\"/>\n          <xsd:any maxOccurs=\"unbounded\" minOccurs=\"0\" namespace=\"##other\" processContents=\"skip\"/>\n        </xsd:sequence>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:group\"/>\n          <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:trans-unit\"/>\n          <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:bin-unit\"/>\n        </xsd:choice>\n      </xsd:sequence>\n      <xsd:attribute name=\"id\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"datatype\" type=\"xlf:AttrType_datatype\" use=\"optional\"/>\n      <xsd:attribute default=\"default\" ref=\"xml:space\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"restype\" type=\"xlf:AttrType_restype\" use=\"optional\"/>\n      <xsd:attribute name=\"resname\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"extradata\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"extype\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"help-id\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"menu\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"menu-option\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"menu-name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"coord\" type=\"xlf:AttrType_Coordinates\" use=\"optional\"/>\n      <xsd:attribute name=\"font\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"css-style\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"style\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"exstyle\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"translate\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"reformat\" type=\"xlf:AttrType_reformat\" use=\"optional\"/>\n      <xsd:attribute default=\"pixel\" name=\"size-unit\" type=\"xlf:AttrType_size-unit\" use=\"optional\"/>\n      <xsd:attribute name=\"maxwidth\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"minwidth\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"maxheight\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"minheight\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"maxbytes\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"minbytes\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"charclass\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute default=\"no\" name=\"merged-trans\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"trans-unit\">\n    <xsd:complexType>\n      <xsd:sequence>\n        <xsd:element ref=\"xlf:source\"/>\n        <xsd:element minOccurs=\"0\" ref=\"xlf:seg-source\"/>\n        <xsd:element minOccurs=\"0\" ref=\"xlf:target\"/>\n        <xsd:choice maxOccurs=\"unbounded\" minOccurs=\"0\">\n          <xsd:element ref=\"xlf:context-group\"/>\n          <xsd:element ref=\"xlf:count-group\"/>\n          <xsd:element ref=\"xlf:prop-group\"/>\n          <xsd:element ref=\"xlf:note\"/>\n          <xsd:element ref=\"xlf:alt-trans\"/>\n        </xsd:choice>\n        <xsd:any maxOccurs=\"unbounded\" minOccurs=\"0\" namespace=\"##other\" processContents=\"skip\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"id\" type=\"xsd:string\" use=\"required\"/>\n      <xsd:attribute name=\"approved\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"translate\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"reformat\" type=\"xlf:AttrType_reformat\" use=\"optional\"/>\n      <xsd:attribute default=\"default\" ref=\"xml:space\" use=\"optional\"/>\n      <xsd:attribute name=\"datatype\" type=\"xlf:AttrType_datatype\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"phase-name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"restype\" type=\"xlf:AttrType_restype\" use=\"optional\"/>\n      <xsd:attribute name=\"resname\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"extradata\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"extype\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"help-id\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"menu\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"menu-option\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"menu-name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"coord\" type=\"xlf:AttrType_Coordinates\" use=\"optional\"/>\n      <xsd:attribute name=\"font\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"css-style\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"style\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"exstyle\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute default=\"pixel\" name=\"size-unit\" type=\"xlf:AttrType_size-unit\" use=\"optional\"/>\n      <xsd:attribute name=\"maxwidth\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"minwidth\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"maxheight\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"minheight\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"maxbytes\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"minbytes\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"charclass\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"merged-trans\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n    <xsd:unique name=\"U_tu_segsrc_mid\">\n      <xsd:selector xpath=\"./xlf:seg-source/xlf:mrk\"/>\n      <xsd:field xpath=\"@mid\"/>\n    </xsd:unique>\n    <xsd:keyref name=\"KR_tu_segsrc_mid\" refer=\"xlf:U_tu_segsrc_mid\">\n      <xsd:selector xpath=\"./xlf:target/xlf:mrk|./xlf:alt-trans\"/>\n      <xsd:field xpath=\"@mid\"/>\n    </xsd:keyref>\n  </xsd:element>\n  <xsd:element name=\"source\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:group maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:ElemGroup_TextContent\"/>\n      <xsd:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n    <xsd:unique name=\"U_source_bpt_rid\">\n      <xsd:selector xpath=\".//xlf:bpt\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:unique>\n    <xsd:keyref name=\"KR_source_ept_rid\" refer=\"xlf:U_source_bpt_rid\">\n      <xsd:selector xpath=\".//xlf:ept\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:keyref>\n    <xsd:unique name=\"U_source_bx_rid\">\n      <xsd:selector xpath=\".//xlf:bx\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:unique>\n    <xsd:keyref name=\"KR_source_ex_rid\" refer=\"xlf:U_source_bx_rid\">\n      <xsd:selector xpath=\".//xlf:ex\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:keyref>\n  </xsd:element>\n  <xsd:element name=\"seg-source\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:group maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:ElemGroup_TextContent\"/>\n      <xsd:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n    <xsd:unique name=\"U_segsrc_bpt_rid\">\n      <xsd:selector xpath=\".//xlf:bpt\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:unique>\n    <xsd:keyref name=\"KR_segsrc_ept_rid\" refer=\"xlf:U_segsrc_bpt_rid\">\n      <xsd:selector xpath=\".//xlf:ept\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:keyref>\n    <xsd:unique name=\"U_segsrc_bx_rid\">\n      <xsd:selector xpath=\".//xlf:bx\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:unique>\n    <xsd:keyref name=\"KR_segsrc_ex_rid\" refer=\"xlf:U_segsrc_bx_rid\">\n      <xsd:selector xpath=\".//xlf:ex\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:keyref>\n  </xsd:element>\n  <xsd:element name=\"target\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:group maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:ElemGroup_TextContent\"/>\n      <xsd:attribute name=\"state\" type=\"xlf:AttrType_state\" use=\"optional\"/>\n      <xsd:attribute name=\"state-qualifier\" type=\"xlf:AttrType_state-qualifier\" use=\"optional\"/>\n      <xsd:attribute name=\"phase-name\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"restype\" type=\"xlf:AttrType_restype\" use=\"optional\"/>\n      <xsd:attribute name=\"resname\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"coord\" type=\"xlf:AttrType_Coordinates\" use=\"optional\"/>\n      <xsd:attribute name=\"font\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"css-style\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"style\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"exstyle\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"equiv-trans\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n    <xsd:unique name=\"U_target_bpt_rid\">\n      <xsd:selector xpath=\".//xlf:bpt\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:unique>\n    <xsd:keyref name=\"KR_target_ept_rid\" refer=\"xlf:U_target_bpt_rid\">\n      <xsd:selector xpath=\".//xlf:ept\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:keyref>\n    <xsd:unique name=\"U_target_bx_rid\">\n      <xsd:selector xpath=\".//xlf:bx\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:unique>\n    <xsd:keyref name=\"KR_target_ex_rid\" refer=\"xlf:U_target_bx_rid\">\n      <xsd:selector xpath=\".//xlf:ex\"/>\n      <xsd:field xpath=\"@rid\"/>\n    </xsd:keyref>\n  </xsd:element>\n  <xsd:element name=\"alt-trans\">\n    <xsd:complexType>\n      <xsd:sequence>\n        <xsd:element minOccurs=\"0\" ref=\"xlf:source\"/>\n        <xsd:element minOccurs=\"0\" ref=\"xlf:seg-source\"/>\n        <xsd:element maxOccurs=\"unbounded\" ref=\"xlf:target\"/>\n        <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:context-group\"/>\n        <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:prop-group\"/>\n        <xsd:element maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:note\"/>\n        <xsd:any maxOccurs=\"unbounded\" minOccurs=\"0\" namespace=\"##other\" processContents=\"skip\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"match-quality\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"tool-id\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"tool\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"crc\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xsd:attribute name=\"origin\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"datatype\" type=\"xlf:AttrType_datatype\" use=\"optional\"/>\n      <xsd:attribute default=\"default\" ref=\"xml:space\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"restype\" type=\"xlf:AttrType_restype\" use=\"optional\"/>\n      <xsd:attribute name=\"resname\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"extradata\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"extype\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"help-id\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"menu\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"menu-option\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"menu-name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"mid\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"coord\" type=\"xlf:AttrType_Coordinates\" use=\"optional\"/>\n      <xsd:attribute name=\"font\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"css-style\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"style\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"exstyle\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"phase-name\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute default=\"proposal\" name=\"alttranstype\" type=\"xlf:AttrType_alttranstype\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n    <xsd:unique name=\"U_at_segsrc_mid\">\n      <xsd:selector xpath=\"./xlf:seg-source/xlf:mrk\"/>\n      <xsd:field xpath=\"@mid\"/>\n    </xsd:unique>\n    <xsd:keyref name=\"KR_at_segsrc_mid\" refer=\"xlf:U_at_segsrc_mid\">\n      <xsd:selector xpath=\"./xlf:target/xlf:mrk\"/>\n      <xsd:field xpath=\"@mid\"/>\n    </xsd:keyref>\n  </xsd:element>\n  <xsd:element name=\"bin-unit\">\n    <xsd:complexType>\n      <xsd:sequence>\n        <xsd:element ref=\"xlf:bin-source\"/>\n        <xsd:element minOccurs=\"0\" ref=\"xlf:bin-target\"/>\n        <xsd:choice maxOccurs=\"unbounded\" minOccurs=\"0\">\n          <xsd:element ref=\"xlf:context-group\"/>\n          <xsd:element ref=\"xlf:count-group\"/>\n          <xsd:element ref=\"xlf:prop-group\"/>\n          <xsd:element ref=\"xlf:note\"/>\n          <xsd:element ref=\"xlf:trans-unit\"/>\n        </xsd:choice>\n        <xsd:any maxOccurs=\"unbounded\" minOccurs=\"0\" namespace=\"##other\" processContents=\"skip\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"id\" type=\"xsd:string\" use=\"required\"/>\n      <xsd:attribute name=\"mime-type\" type=\"xlf:mime-typeValueList\" use=\"required\"/>\n      <xsd:attribute name=\"approved\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"translate\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"reformat\" type=\"xlf:AttrType_reformat\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"restype\" type=\"xlf:AttrType_restype\" use=\"optional\"/>\n      <xsd:attribute name=\"resname\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"phase-name\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"bin-source\">\n    <xsd:complexType>\n      <xsd:choice>\n        <xsd:element ref=\"xlf:internal-file\"/>\n        <xsd:element ref=\"xlf:external-file\"/>\n      </xsd:choice>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"bin-target\">\n    <xsd:complexType>\n      <xsd:choice>\n        <xsd:element ref=\"xlf:internal-file\"/>\n        <xsd:element ref=\"xlf:external-file\"/>\n      </xsd:choice>\n      <xsd:attribute name=\"mime-type\" type=\"xlf:mime-typeValueList\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"state\" type=\"xlf:AttrType_state\" use=\"optional\"/>\n      <xsd:attribute name=\"state-qualifier\" type=\"xlf:AttrType_state-qualifier\" use=\"optional\"/>\n      <xsd:attribute name=\"phase-name\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"restype\" type=\"xlf:AttrType_restype\" use=\"optional\"/>\n      <xsd:attribute name=\"resname\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <!-- Element for inline codes -->\n  <xsd:element name=\"g\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:group maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:ElemGroup_TextContent\"/>\n      <xsd:attribute name=\"ctype\" type=\"xlf:AttrType_InlineDelimiters\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"clone\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:attributeGroup ref=\"xlf:AttrGroup_TextContent\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"x\">\n    <xsd:complexType>\n      <xsd:attribute name=\"ctype\" type=\"xlf:AttrType_InlinePlaceholders\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"clone\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:attributeGroup ref=\"xlf:AttrGroup_TextContent\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"bx\">\n    <xsd:complexType>\n      <xsd:attribute name=\"rid\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"ctype\" type=\"xlf:AttrType_InlineDelimiters\" use=\"optional\"/>\n      <xsd:attribute default=\"yes\" name=\"clone\" type=\"xlf:AttrType_YesNo\" use=\"optional\"/>\n      <xsd:attributeGroup ref=\"xlf:AttrGroup_TextContent\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"ex\">\n    <xsd:complexType>\n      <xsd:attribute name=\"rid\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attributeGroup ref=\"xlf:AttrGroup_TextContent\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"ph\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:sequence maxOccurs=\"unbounded\" minOccurs=\"0\">\n        <xsd:element ref=\"xlf:sub\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"ctype\" type=\"xlf:AttrType_InlinePlaceholders\" use=\"optional\"/>\n      <xsd:attribute name=\"crc\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"assoc\" type=\"xlf:AttrType_assoc\" use=\"optional\"/>\n      <xsd:attributeGroup ref=\"xlf:AttrGroup_TextContent\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"bpt\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:sequence maxOccurs=\"unbounded\" minOccurs=\"0\">\n        <xsd:element ref=\"xlf:sub\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"rid\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"ctype\" type=\"xlf:AttrType_InlineDelimiters\" use=\"optional\"/>\n      <xsd:attribute name=\"crc\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attributeGroup ref=\"xlf:AttrGroup_TextContent\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"ept\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:sequence maxOccurs=\"unbounded\" minOccurs=\"0\">\n        <xsd:element ref=\"xlf:sub\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"rid\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"crc\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attributeGroup ref=\"xlf:AttrGroup_TextContent\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"it\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:sequence maxOccurs=\"unbounded\" minOccurs=\"0\">\n        <xsd:element ref=\"xlf:sub\"/>\n      </xsd:sequence>\n      <xsd:attribute name=\"pos\" type=\"xlf:AttrType_Position\" use=\"required\"/>\n      <xsd:attribute name=\"rid\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"ctype\" type=\"xlf:AttrType_InlineDelimiters\" use=\"optional\"/>\n      <xsd:attribute name=\"crc\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attributeGroup ref=\"xlf:AttrGroup_TextContent\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"sub\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:group maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:ElemGroup_TextContent\"/>\n      <xsd:attribute name=\"datatype\" type=\"xlf:AttrType_datatype\" use=\"optional\"/>\n      <xsd:attribute name=\"ctype\" type=\"xlf:AttrType_InlineDelimiters\" use=\"optional\"/>\n      <xsd:attribute name=\"xid\" type=\"xsd:string\" use=\"optional\"/>\n    </xsd:complexType>\n  </xsd:element>\n  <xsd:element name=\"mrk\">\n    <xsd:complexType mixed=\"true\">\n      <xsd:group maxOccurs=\"unbounded\" minOccurs=\"0\" ref=\"xlf:ElemGroup_TextContent\"/>\n      <xsd:attribute name=\"mtype\" type=\"xlf:AttrType_mtype\" use=\"required\"/>\n      <xsd:attribute name=\"mid\" type=\"xsd:NMTOKEN\" use=\"optional\"/>\n      <xsd:attribute name=\"comment\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:attribute name=\"ts\" type=\"xsd:string\" use=\"optional\"/>\n      <xsd:anyAttribute namespace=\"##any\" processContents=\"skip\"/>\n    </xsd:complexType>\n  </xsd:element>\n</xsd:schema>\n"
  },
  {
    "path": "Resources/schemas/xliff-core-2.0.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    XLIFF Version 2.0\n    OASIS Standard\n    05 August 2014\n    Copyright (c) OASIS Open 2014. All rights reserved.\n    Source: http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/schemas/\n     -->\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n    elementFormDefault=\"qualified\"\n    xmlns:xlf=\"urn:oasis:names:tc:xliff:document:2.0\"\n    targetNamespace=\"urn:oasis:names:tc:xliff:document:2.0\">\n\n  <!-- Import -->\n\n  <xs:import namespace=\"http://www.w3.org/XML/1998/namespace\"\n      schemaLocation=\"informativeCopiesOf3rdPartySchemas/w3c/xml.xsd\"/>\n\n  <!-- Element Group -->\n\n  <xs:group name=\"inline\">\n    <xs:choice>\n      <xs:element ref=\"xlf:cp\"/>\n      <xs:element ref=\"xlf:ph\"/>\n      <xs:element ref=\"xlf:pc\"/>\n      <xs:element ref=\"xlf:sc\"/>\n      <xs:element ref=\"xlf:ec\"/>\n      <xs:element ref=\"xlf:mrk\"/>\n      <xs:element ref=\"xlf:sm\"/>\n      <xs:element ref=\"xlf:em\"/>\n    </xs:choice>\n  </xs:group>\n\n  <!-- Attribute Types -->\n\n  <xs:simpleType name=\"yesNo\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"yes\"/>\n      <xs:enumeration value=\"no\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"yesNoFirstNo\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"yes\"/>\n      <xs:enumeration value=\"firstNo\"/>\n      <xs:enumeration value=\"no\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"dirValue\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"ltr\"/>\n      <xs:enumeration value=\"rtl\"/>\n      <xs:enumeration value=\"auto\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"appliesTo\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"source\"/>\n      <xs:enumeration value=\"target\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"userDefinedValue\">\n    <xs:restriction base=\"xs:string\">\n      <xs:pattern value=\"[^\\s:]+:[^\\s:]+\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"attrType_type\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"fmt\"/>\n      <xs:enumeration value=\"ui\"/>\n      <xs:enumeration value=\"quote\"/>\n      <xs:enumeration value=\"link\"/>\n      <xs:enumeration value=\"image\"/>\n      <xs:enumeration value=\"other\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"typeForMrkValues\">\n    <xs:restriction base=\"xs:NMTOKEN\">\n      <xs:enumeration value=\"generic\"/>\n      <xs:enumeration value=\"comment\"/>\n      <xs:enumeration value=\"term\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"attrType_typeForMrk\">\n    <xs:union memberTypes=\"xlf:typeForMrkValues xlf:userDefinedValue\"/>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"priorityValue\">\n    <xs:restriction base=\"xs:positiveInteger\">\n      <xs:minInclusive value=\"1\"/>\n      <xs:maxInclusive value=\"10\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"stateType\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"initial\"/>\n      <xs:enumeration value=\"translated\"/>\n      <xs:enumeration value=\"reviewed\"/>\n      <xs:enumeration value=\"final\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <!-- Structural Elements -->\n\n  <xs:element name=\"xliff\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"unbounded\" ref=\"xlf:file\"/>\n      </xs:sequence>\n      <xs:attribute name=\"version\" use=\"required\"/>\n      <xs:attribute name=\"srcLang\" use=\"required\"/>\n      <xs:attribute name=\"trgLang\" use=\"optional\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\" default=\"default\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"file\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:skeleton\"/>\n        <xs:any minOccurs=\"0\" maxOccurs=\"unbounded\" namespace=\"##other\"\n            processContents=\"lax\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:notes\"/>\n        <xs:choice minOccurs=\"1\" maxOccurs=\"unbounded\">\n          <xs:element ref=\"xlf:unit\"/>\n          <xs:element ref=\"xlf:group\"/>\n        </xs:choice>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"canResegment\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"original\" use=\"optional\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"srcDir\" use=\"optional\" type=\"xlf:dirValue\" default=\"auto\"/>\n      <xs:attribute name=\"trgDir\" use=\"optional\" type=\"xlf:dirValue\" default=\"auto\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"skeleton\">\n    <xs:complexType mixed=\"true\">\n      <xs:sequence>\n        <xs:any minOccurs=\"0\" maxOccurs=\"unbounded\" namespace=\"##other\"\n            processContents=\"lax\"/>\n      </xs:sequence>\n      <xs:attribute name=\"href\" use=\"optional\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"group\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:any minOccurs=\"0\" maxOccurs=\"unbounded\" namespace=\"##other\"\n            processContents=\"lax\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:notes\"/>\n        <xs:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n          <xs:element ref=\"xlf:unit\"/>\n          <xs:element ref=\"xlf:group\"/>\n        </xs:choice>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"name\" use=\"optional\"/>\n      <xs:attribute name=\"canResegment\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"srcDir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"trgDir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"unit\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:any minOccurs=\"0\" maxOccurs=\"unbounded\" namespace=\"##other\"\n            processContents=\"lax\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:notes\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:originalData\"/>\n        <xs:choice minOccurs=\"1\" maxOccurs=\"unbounded\">\n          <xs:element ref=\"xlf:segment\"/>\n          <xs:element ref=\"xlf:ignorable\"/>\n        </xs:choice>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"name\" use=\"optional\"/>\n      <xs:attribute name=\"canResegment\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"srcDir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"trgDir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"segment\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"1\" ref=\"xlf:source\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:target\"/>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"canResegment\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"state\" use=\"optional\" type=\"xlf:stateType\" default=\"initial\"/>\n      <xs:attribute name=\"subState\" use=\"optional\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"ignorable\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"1\" ref=\"xlf:source\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:target\"/>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"notes\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"unbounded\" ref=\"xlf:note\"/>\n      </xs:sequence>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"note\">\n    <xs:complexType mixed=\"true\">\n      <xs:attribute name=\"id\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"appliesTo\" use=\"optional\" type=\"xlf:appliesTo\"/>\n      <xs:attribute name=\"category\" use=\"optional\"/>\n      <xs:attribute name=\"priority\" use=\"optional\" type=\"xlf:priorityValue\" default=\"1\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"originalData\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"unbounded\" ref=\"xlf:data\"/>\n      </xs:sequence>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"data\">\n    <xs:complexType mixed=\"true\">\n      <xs:sequence>\n        <xs:element minOccurs=\"0\" maxOccurs=\"unbounded\" ref=\"xlf:cp\"/>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dir\" use=\"optional\" type=\"xlf:dirValue\" default=\"auto\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\" fixed=\"preserve\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"source\">\n    <xs:complexType mixed=\"true\">\n      <xs:group ref=\"xlf:inline\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      <xs:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"target\">\n    <xs:complexType mixed=\"true\">\n      <xs:group ref=\"xlf:inline\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      <xs:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xs:attribute name=\"order\" use=\"optional\" type=\"xs:positiveInteger\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <!-- Inline Elements -->\n\n  <xs:element name=\"cp\">\n    <!-- Code Point -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"hex\" use=\"required\" type=\"xs:hexBinary\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"ph\">\n    <!-- Placeholder -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"canCopy\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canDelete\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canReorder\" use=\"optional\" type=\"xlf:yesNoFirstNo\" default=\"yes\"/>\n      <xs:attribute name=\"copyOf\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"disp\" use=\"optional\"/>\n      <xs:attribute name=\"equiv\" use=\"optional\"/>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRef\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"subFlows\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subType\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_type\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"pc\">\n    <!-- Paired Code -->\n    <xs:complexType mixed=\"true\">\n      <xs:group ref=\"xlf:inline\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      <xs:attribute name=\"canCopy\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canDelete\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canOverlap\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"canReorder\" use=\"optional\" type=\"xlf:yesNoFirstNo\" default=\"yes\"/>\n      <xs:attribute name=\"copyOf\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dispEnd\" use=\"optional\"/>\n      <xs:attribute name=\"dispStart\" use=\"optional\"/>\n      <xs:attribute name=\"equivEnd\" use=\"optional\"/>\n      <xs:attribute name=\"equivStart\" use=\"optional\"/>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRefEnd\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRefStart\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"subFlowsEnd\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subFlowsStart\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subType\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_type\"/>\n      <xs:attribute name=\"dir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"sc\">\n    <!-- Start Code -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"canCopy\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canDelete\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canOverlap\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canReorder\" use=\"optional\" type=\"xlf:yesNoFirstNo\" default=\"yes\"/>\n      <xs:attribute name=\"copyOf\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRef\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"disp\" use=\"optional\"/>\n      <xs:attribute name=\"equiv\" use=\"optional\"/>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"isolated\" use=\"optional\" type=\"xlf:yesNo\" default=\"no\"/>\n      <xs:attribute name=\"subFlows\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subType\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_type\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"ec\">\n    <!-- End Code -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"canCopy\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canDelete\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canOverlap\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canReorder\" use=\"optional\" type=\"xlf:yesNoFirstNo\" default=\"yes\"/>\n      <xs:attribute name=\"copyOf\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRef\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"disp\" use=\"optional\"/>\n      <xs:attribute name=\"equiv\" use=\"optional\"/>\n      <xs:attribute name=\"id\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"isolated\" use=\"optional\" type=\"xlf:yesNo\" default=\"no\"/>\n      <xs:attribute name=\"startRef\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"subFlows\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subType\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_type\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"mrk\">\n    <!-- Annotation Marker -->\n    <xs:complexType mixed=\"true\">\n      <xs:group ref=\"xlf:inline\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_typeForMrk\"/>\n      <xs:attribute name=\"ref\" use=\"optional\" type=\"xs:anyURI\"/>\n      <xs:attribute name=\"value\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"sm\">\n    <!-- Start Annotation Marker -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_typeForMrk\"/>\n      <xs:attribute name=\"ref\" use=\"optional\" type=\"xs:anyURI\"/>\n      <xs:attribute name=\"value\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"em\">\n    <!-- End Annotation Marker -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"startRef\" use=\"required\" type=\"xs:NMTOKEN\"/>\n    </xs:complexType>\n  </xs:element>\n\n</xs:schema>\n"
  },
  {
    "path": "Resources/schemas/xliff-core-2.2.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    XLIFF Version 2.2\n    Based on XLIFF Version 2.0 OASIS Standard with additions for 2.2 modules.\n    Adds anyAttribute on segment to support PGS module attributes.\n     -->\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n    elementFormDefault=\"qualified\"\n    xmlns:xlf=\"urn:oasis:names:tc:xliff:document:2.0\"\n    targetNamespace=\"urn:oasis:names:tc:xliff:document:2.0\">\n\n  <!-- Import -->\n\n  <xs:import namespace=\"http://www.w3.org/XML/1998/namespace\"\n      schemaLocation=\"informativeCopiesOf3rdPartySchemas/w3c/xml.xsd\"/>\n\n  <!-- Element Group -->\n\n  <xs:group name=\"inline\">\n    <xs:choice>\n      <xs:element ref=\"xlf:cp\"/>\n      <xs:element ref=\"xlf:ph\"/>\n      <xs:element ref=\"xlf:pc\"/>\n      <xs:element ref=\"xlf:sc\"/>\n      <xs:element ref=\"xlf:ec\"/>\n      <xs:element ref=\"xlf:mrk\"/>\n      <xs:element ref=\"xlf:sm\"/>\n      <xs:element ref=\"xlf:em\"/>\n    </xs:choice>\n  </xs:group>\n\n  <!-- Attribute Types -->\n\n  <xs:simpleType name=\"yesNo\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"yes\"/>\n      <xs:enumeration value=\"no\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"yesNoFirstNo\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"yes\"/>\n      <xs:enumeration value=\"firstNo\"/>\n      <xs:enumeration value=\"no\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"dirValue\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"ltr\"/>\n      <xs:enumeration value=\"rtl\"/>\n      <xs:enumeration value=\"auto\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"appliesTo\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"source\"/>\n      <xs:enumeration value=\"target\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"userDefinedValue\">\n    <xs:restriction base=\"xs:string\">\n      <xs:pattern value=\"[^\\s:]+:[^\\s:]+\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"attrType_type\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"fmt\"/>\n      <xs:enumeration value=\"ui\"/>\n      <xs:enumeration value=\"quote\"/>\n      <xs:enumeration value=\"link\"/>\n      <xs:enumeration value=\"image\"/>\n      <xs:enumeration value=\"other\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"typeForMrkValues\">\n    <xs:restriction base=\"xs:NMTOKEN\">\n      <xs:enumeration value=\"generic\"/>\n      <xs:enumeration value=\"comment\"/>\n      <xs:enumeration value=\"term\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"attrType_typeForMrk\">\n    <xs:union memberTypes=\"xlf:typeForMrkValues xlf:userDefinedValue\"/>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"priorityValue\">\n    <xs:restriction base=\"xs:positiveInteger\">\n      <xs:minInclusive value=\"1\"/>\n      <xs:maxInclusive value=\"10\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <xs:simpleType name=\"stateType\">\n    <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"initial\"/>\n      <xs:enumeration value=\"translated\"/>\n      <xs:enumeration value=\"reviewed\"/>\n      <xs:enumeration value=\"final\"/>\n    </xs:restriction>\n  </xs:simpleType>\n\n  <!-- Structural Elements -->\n\n  <xs:element name=\"xliff\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"unbounded\" ref=\"xlf:file\"/>\n      </xs:sequence>\n      <xs:attribute name=\"version\" use=\"required\"/>\n      <xs:attribute name=\"srcLang\" use=\"required\"/>\n      <xs:attribute name=\"trgLang\" use=\"optional\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\" default=\"default\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"file\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:skeleton\"/>\n        <xs:any minOccurs=\"0\" maxOccurs=\"unbounded\" namespace=\"##other\"\n            processContents=\"lax\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:notes\"/>\n        <xs:choice minOccurs=\"1\" maxOccurs=\"unbounded\">\n          <xs:element ref=\"xlf:unit\"/>\n          <xs:element ref=\"xlf:group\"/>\n        </xs:choice>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"canResegment\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"original\" use=\"optional\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"srcDir\" use=\"optional\" type=\"xlf:dirValue\" default=\"auto\"/>\n      <xs:attribute name=\"trgDir\" use=\"optional\" type=\"xlf:dirValue\" default=\"auto\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"skeleton\">\n    <xs:complexType mixed=\"true\">\n      <xs:sequence>\n        <xs:any minOccurs=\"0\" maxOccurs=\"unbounded\" namespace=\"##other\"\n            processContents=\"lax\"/>\n      </xs:sequence>\n      <xs:attribute name=\"href\" use=\"optional\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"group\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:any minOccurs=\"0\" maxOccurs=\"unbounded\" namespace=\"##other\"\n            processContents=\"lax\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:notes\"/>\n        <xs:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n          <xs:element ref=\"xlf:unit\"/>\n          <xs:element ref=\"xlf:group\"/>\n        </xs:choice>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"name\" use=\"optional\"/>\n      <xs:attribute name=\"canResegment\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"srcDir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"trgDir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"unit\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:any minOccurs=\"0\" maxOccurs=\"unbounded\" namespace=\"##other\"\n            processContents=\"lax\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:notes\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:originalData\"/>\n        <xs:choice minOccurs=\"1\" maxOccurs=\"unbounded\">\n          <xs:element ref=\"xlf:segment\"/>\n          <xs:element ref=\"xlf:ignorable\"/>\n        </xs:choice>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"name\" use=\"optional\"/>\n      <xs:attribute name=\"canResegment\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"srcDir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"trgDir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"segment\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"1\" ref=\"xlf:source\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:target\"/>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"canResegment\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"state\" use=\"optional\" type=\"xlf:stateType\" default=\"initial\"/>\n      <xs:attribute name=\"subState\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"ignorable\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"1\" ref=\"xlf:source\"/>\n        <xs:element minOccurs=\"0\" maxOccurs=\"1\" ref=\"xlf:target\"/>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"notes\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"unbounded\" ref=\"xlf:note\"/>\n      </xs:sequence>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"note\">\n    <xs:complexType mixed=\"true\">\n      <xs:attribute name=\"id\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"appliesTo\" use=\"optional\" type=\"xlf:appliesTo\"/>\n      <xs:attribute name=\"category\" use=\"optional\"/>\n      <xs:attribute name=\"priority\" use=\"optional\" type=\"xlf:priorityValue\" default=\"1\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"originalData\">\n    <xs:complexType mixed=\"false\">\n      <xs:sequence>\n        <xs:element minOccurs=\"1\" maxOccurs=\"unbounded\" ref=\"xlf:data\"/>\n      </xs:sequence>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"data\">\n    <xs:complexType mixed=\"true\">\n      <xs:sequence>\n        <xs:element minOccurs=\"0\" maxOccurs=\"unbounded\" ref=\"xlf:cp\"/>\n      </xs:sequence>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dir\" use=\"optional\" type=\"xlf:dirValue\" default=\"auto\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\" fixed=\"preserve\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"source\">\n    <xs:complexType mixed=\"true\">\n      <xs:group ref=\"xlf:inline\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      <xs:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"target\">\n    <xs:complexType mixed=\"true\">\n      <xs:group ref=\"xlf:inline\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      <xs:attribute ref=\"xml:lang\" use=\"optional\"/>\n      <xs:attribute ref=\"xml:space\" use=\"optional\"/>\n      <xs:attribute name=\"order\" use=\"optional\" type=\"xs:positiveInteger\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <!-- Inline Elements -->\n\n  <xs:element name=\"cp\">\n    <!-- Code Point -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"hex\" use=\"required\" type=\"xs:hexBinary\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"ph\">\n    <!-- Placeholder -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"canCopy\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canDelete\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canReorder\" use=\"optional\" type=\"xlf:yesNoFirstNo\" default=\"yes\"/>\n      <xs:attribute name=\"copyOf\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"disp\" use=\"optional\"/>\n      <xs:attribute name=\"equiv\" use=\"optional\"/>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRef\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"subFlows\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subType\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_type\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"pc\">\n    <!-- Paired Code -->\n    <xs:complexType mixed=\"true\">\n      <xs:group ref=\"xlf:inline\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      <xs:attribute name=\"canCopy\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canDelete\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canOverlap\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"canReorder\" use=\"optional\" type=\"xlf:yesNoFirstNo\" default=\"yes\"/>\n      <xs:attribute name=\"copyOf\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dispEnd\" use=\"optional\"/>\n      <xs:attribute name=\"dispStart\" use=\"optional\"/>\n      <xs:attribute name=\"equivEnd\" use=\"optional\"/>\n      <xs:attribute name=\"equivStart\" use=\"optional\"/>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRefEnd\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRefStart\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"subFlowsEnd\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subFlowsStart\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subType\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_type\"/>\n      <xs:attribute name=\"dir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"sc\">\n    <!-- Start Code -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"canCopy\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canDelete\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canOverlap\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canReorder\" use=\"optional\" type=\"xlf:yesNoFirstNo\" default=\"yes\"/>\n      <xs:attribute name=\"copyOf\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRef\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"disp\" use=\"optional\"/>\n      <xs:attribute name=\"equiv\" use=\"optional\"/>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"isolated\" use=\"optional\" type=\"xlf:yesNo\" default=\"no\"/>\n      <xs:attribute name=\"subFlows\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subType\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_type\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"ec\">\n    <!-- End Code -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"canCopy\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canDelete\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canOverlap\" use=\"optional\" type=\"xlf:yesNo\" default=\"yes\"/>\n      <xs:attribute name=\"canReorder\" use=\"optional\" type=\"xlf:yesNoFirstNo\" default=\"yes\"/>\n      <xs:attribute name=\"copyOf\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dataRef\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"dir\" use=\"optional\" type=\"xlf:dirValue\"/>\n      <xs:attribute name=\"disp\" use=\"optional\"/>\n      <xs:attribute name=\"equiv\" use=\"optional\"/>\n      <xs:attribute name=\"id\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"isolated\" use=\"optional\" type=\"xlf:yesNo\" default=\"no\"/>\n      <xs:attribute name=\"startRef\" use=\"optional\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"subFlows\" use=\"optional\" type=\"xs:NMTOKENS\"/>\n      <xs:attribute name=\"subType\" use=\"optional\" type=\"xlf:userDefinedValue\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_type\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"mrk\">\n    <!-- Annotation Marker -->\n    <xs:complexType mixed=\"true\">\n      <xs:group ref=\"xlf:inline\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_typeForMrk\"/>\n      <xs:attribute name=\"ref\" use=\"optional\" type=\"xs:anyURI\"/>\n      <xs:attribute name=\"value\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"sm\">\n    <!-- Start Annotation Marker -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"id\" use=\"required\" type=\"xs:NMTOKEN\"/>\n      <xs:attribute name=\"translate\" use=\"optional\" type=\"xlf:yesNo\"/>\n      <xs:attribute name=\"type\" use=\"optional\" type=\"xlf:attrType_typeForMrk\"/>\n      <xs:attribute name=\"ref\" use=\"optional\" type=\"xs:anyURI\"/>\n      <xs:attribute name=\"value\" use=\"optional\"/>\n      <xs:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xs:complexType>\n  </xs:element>\n\n  <xs:element name=\"em\">\n    <!-- End Annotation Marker -->\n    <xs:complexType mixed=\"false\">\n      <xs:attribute name=\"startRef\" use=\"required\" type=\"xs:NMTOKEN\"/>\n    </xs:complexType>\n  </xs:element>\n\n</xs:schema>\n"
  },
  {
    "path": "Resources/schemas/xml.xsd",
    "content": "<?xml version='1.0'?>\n<?xml-stylesheet href=\"../2008/09/xsd.xsl\" type=\"text/xsl\"?>\n<xs:schema targetNamespace=\"http://www.w3.org/XML/1998/namespace\" \n  xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" \n  xmlns =\"http://www.w3.org/1999/xhtml\"\n  xml:lang=\"en\">\n\n <xs:annotation>\n  <xs:documentation>\n   <div>\n    <h1>About the XML namespace</h1>\n\n    <div class=\"bodytext\">\n     <p>\n\n      This schema document describes the XML namespace, in a form\n      suitable for import by other schema documents.\n     </p>\n     <p>\n      See <a href=\"http://www.w3.org/XML/1998/namespace.html\">\n      http://www.w3.org/XML/1998/namespace.html</a> and\n      <a href=\"http://www.w3.org/TR/REC-xml\">\n      http://www.w3.org/TR/REC-xml</a> for information \n      about this namespace.\n     </p>\n\n     <p>\n      Note that local names in this namespace are intended to be\n      defined only by the World Wide Web Consortium or its subgroups.\n      The names currently defined in this namespace are listed below.\n      They should not be used with conflicting semantics by any Working\n      Group, specification, or document instance.\n     </p>\n     <p>   \n      See further below in this document for more information about <a\n      href=\"#usage\">how to refer to this schema document from your own\n      XSD schema documents</a> and about <a href=\"#nsversioning\">the\n      namespace-versioning policy governing this schema document</a>.\n     </p>\n    </div>\n   </div>\n\n  </xs:documentation>\n </xs:annotation>\n\n <xs:attribute name=\"lang\">\n  <xs:annotation>\n   <xs:documentation>\n    <div>\n     \n      <h3>lang (as an attribute name)</h3>\n      <p>\n\n       denotes an attribute whose value\n       is a language code for the natural language of the content of\n       any element; its value is inherited.  This name is reserved\n       by virtue of its definition in the XML specification.</p>\n     \n    </div>\n    <div>\n     <h4>Notes</h4>\n     <p>\n      Attempting to install the relevant ISO 2- and 3-letter\n      codes as the enumerated possible values is probably never\n      going to be a realistic possibility.  \n     </p>\n     <p>\n\n      See BCP 47 at <a href=\"http://www.rfc-editor.org/rfc/bcp/bcp47.txt\">\n       http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>\n      and the IANA language subtag registry at\n      <a href=\"http://www.iana.org/assignments/language-subtag-registry\">\n       http://www.iana.org/assignments/language-subtag-registry</a>\n      for further information.\n     </p>\n     <p>\n\n      The union allows for the 'un-declaration' of xml:lang with\n      the empty string.\n     </p>\n    </div>\n   </xs:documentation>\n  </xs:annotation>\n  <xs:simpleType>\n   <xs:union memberTypes=\"xs:language\">\n    <xs:simpleType>    \n     <xs:restriction base=\"xs:string\">\n      <xs:enumeration value=\"\"/>\n\n     </xs:restriction>\n    </xs:simpleType>\n   </xs:union>\n  </xs:simpleType>\n </xs:attribute>\n\n <xs:attribute name=\"space\">\n  <xs:annotation>\n   <xs:documentation>\n\n    <div>\n     \n      <h3>space (as an attribute name)</h3>\n      <p>\n       denotes an attribute whose\n       value is a keyword indicating what whitespace processing\n       discipline is intended for the content of the element; its\n       value is inherited.  This name is reserved by virtue of its\n       definition in the XML specification.</p>\n     \n    </div>\n   </xs:documentation>\n  </xs:annotation>\n  <xs:simpleType>\n\n   <xs:restriction base=\"xs:NCName\">\n    <xs:enumeration value=\"default\"/>\n    <xs:enumeration value=\"preserve\"/>\n   </xs:restriction>\n  </xs:simpleType>\n </xs:attribute>\n \n <xs:attribute name=\"base\" type=\"xs:anyURI\"> <xs:annotation>\n   <xs:documentation>\n\n    <div>\n     \n      <h3>base (as an attribute name)</h3>\n      <p>\n       denotes an attribute whose value\n       provides a URI to be used as the base for interpreting any\n       relative URIs in the scope of the element on which it\n       appears; its value is inherited.  This name is reserved\n       by virtue of its definition in the XML Base specification.</p>\n     \n     <p>\n      See <a\n      href=\"http://www.w3.org/TR/xmlbase/\">http://www.w3.org/TR/xmlbase/</a>\n      for information about this attribute.\n     </p>\n\n    </div>\n   </xs:documentation>\n  </xs:annotation>\n </xs:attribute>\n \n <xs:attribute name=\"id\" type=\"xs:ID\">\n  <xs:annotation>\n   <xs:documentation>\n    <div>\n     \n      <h3>id (as an attribute name)</h3> \n      <p>\n\n       denotes an attribute whose value\n       should be interpreted as if declared to be of type ID.\n       This name is reserved by virtue of its definition in the\n       xml:id specification.</p>\n     \n     <p>\n      See <a\n      href=\"http://www.w3.org/TR/xml-id/\">http://www.w3.org/TR/xml-id/</a>\n      for information about this attribute.\n     </p>\n    </div>\n   </xs:documentation>\n  </xs:annotation>\n\n </xs:attribute>\n\n <xs:attributeGroup name=\"specialAttrs\">\n  <xs:attribute ref=\"xml:base\"/>\n  <xs:attribute ref=\"xml:lang\"/>\n  <xs:attribute ref=\"xml:space\"/>\n  <xs:attribute ref=\"xml:id\"/>\n </xs:attributeGroup>\n\n <xs:annotation>\n\n  <xs:documentation>\n   <div>\n   \n    <h3>Father (in any context at all)</h3> \n\n    <div class=\"bodytext\">\n     <p>\n      denotes Jon Bosak, the chair of \n      the original XML Working Group.  This name is reserved by \n      the following decision of the W3C XML Plenary and \n      XML Coordination groups:\n     </p>\n     <blockquote>\n       <p>\n\n\tIn appreciation for his vision, leadership and\n\tdedication the W3C XML Plenary on this 10th day of\n\tFebruary, 2000, reserves for Jon Bosak in perpetuity\n\tthe XML name \"xml:Father\".\n       </p>\n     </blockquote>\n    </div>\n   </div>\n  </xs:documentation>\n </xs:annotation>\n\n <xs:annotation>\n  <xs:documentation>\n\n   <div xml:id=\"usage\" id=\"usage\">\n    <h2><a name=\"usage\">About this schema document</a></h2>\n\n    <div class=\"bodytext\">\n     <p>\n      This schema defines attributes and an attribute group suitable\n      for use by schemas wishing to allow <code>xml:base</code>,\n      <code>xml:lang</code>, <code>xml:space</code> or\n      <code>xml:id</code> attributes on elements they define.\n     </p>\n\n     <p>\n      To enable this, such a schema must import this schema for\n      the XML namespace, e.g. as follows:\n     </p>\n     <pre>\n          &lt;schema.. .>\n          .. .\n           &lt;import namespace=\"http://www.w3.org/XML/1998/namespace\"\n                      schemaLocation=\"http://www.w3.org/2001/xml.xsd\"/>\n     </pre>\n     <p>\n      or\n     </p>\n     <pre>\n\n           &lt;import namespace=\"http://www.w3.org/XML/1998/namespace\"\n                      schemaLocation=\"http://www.w3.org/2009/01/xml.xsd\"/>\n     </pre>\n     <p>\n      Subsequently, qualified reference to any of the attributes or the\n      group defined below will have the desired effect, e.g.\n     </p>\n     <pre>\n          &lt;type.. .>\n          .. .\n           &lt;attributeGroup ref=\"xml:specialAttrs\"/>\n     </pre>\n     <p>\n      will define a type which will schema-validate an instance element\n      with any of those attributes.\n     </p>\n\n    </div>\n   </div>\n  </xs:documentation>\n </xs:annotation>\n\n <xs:annotation>\n  <xs:documentation>\n   <div id=\"nsversioning\" xml:id=\"nsversioning\">\n    <h2><a name=\"nsversioning\">Versioning policy for this schema document</a></h2>\n\n    <div class=\"bodytext\">\n     <p>\n      In keeping with the XML Schema WG's standard versioning\n      policy, this schema document will persist at\n      <a href=\"http://www.w3.org/2009/01/xml.xsd\">\n       http://www.w3.org/2009/01/xml.xsd</a>.\n     </p>\n     <p>\n      At the date of issue it can also be found at\n      <a href=\"http://www.w3.org/2001/xml.xsd\">\n       http://www.w3.org/2001/xml.xsd</a>.\n     </p>\n\n     <p>\n      The schema document at that URI may however change in the future,\n      in order to remain compatible with the latest version of XML\n      Schema itself, or with the XML namespace itself.  In other words,\n      if the XML Schema or XML namespaces change, the version of this\n      document at <a href=\"http://www.w3.org/2001/xml.xsd\">\n       http://www.w3.org/2001/xml.xsd \n      </a> \n      will change accordingly; the version at \n      <a href=\"http://www.w3.org/2009/01/xml.xsd\">\n       http://www.w3.org/2009/01/xml.xsd \n      </a> \n      will not change.\n     </p>\n     <p>\n\n      Previous dated (and unchanging) versions of this schema \n      document are at:\n     </p>\n     <ul>\n      <li><a href=\"http://www.w3.org/2009/01/xml.xsd\">\n\thttp://www.w3.org/2009/01/xml.xsd</a></li>\n      <li><a href=\"http://www.w3.org/2007/08/xml.xsd\">\n\thttp://www.w3.org/2007/08/xml.xsd</a></li>\n      <li><a href=\"http://www.w3.org/2004/10/xml.xsd\">\n\n\thttp://www.w3.org/2004/10/xml.xsd</a></li>\n      <li><a href=\"http://www.w3.org/2001/03/xml.xsd\">\n\thttp://www.w3.org/2001/03/xml.xsd</a></li>\n     </ul>\n    </div>\n   </div>\n  </xs:documentation>\n </xs:annotation>\n\n</xs:schema>\n"
  },
  {
    "path": "StaticMessage.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Contracts\\Translation\\TranslatableInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\nfinal class StaticMessage implements TranslatableInterface\n{\n    public function __construct(\n        private string $message,\n    ) {\n    }\n\n    public function getMessage(): string\n    {\n        return $this->message;\n    }\n\n    public function trans(TranslatorInterface $translator, ?string $locale = null): string\n    {\n        return $this->getMessage();\n    }\n}\n"
  },
  {
    "path": "Test/AbstractProviderFactoryTestCase.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Test;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Exception\\UnsupportedSchemeException;\nuse Symfony\\Component\\Translation\\Provider\\Dsn;\nuse Symfony\\Component\\Translation\\Provider\\ProviderFactoryInterface;\n\nabstract class AbstractProviderFactoryTestCase extends TestCase\n{\n    abstract public function createFactory(): ProviderFactoryInterface;\n\n    /**\n     * @return iterable<array{0: bool, 1: string}>\n     */\n    abstract public static function supportsProvider(): iterable;\n\n    /**\n     * @return iterable<array{0: string, 1: string}>\n     */\n    abstract public static function createProvider(): iterable;\n\n    /**\n     * @return iterable<array{0: string, 1?: string|null}>\n     */\n    abstract public static function unsupportedSchemeProvider(): iterable;\n\n    /**\n     * @dataProvider supportsProvider\n     */\n    #[DataProvider('supportsProvider')]\n    public function testSupports(bool $expected, string $dsn)\n    {\n        $factory = $this->createFactory();\n\n        $this->assertSame($expected, $factory->supports(new Dsn($dsn)));\n    }\n\n    /**\n     * @dataProvider createProvider\n     */\n    #[DataProvider('createProvider')]\n    public function testCreate(string $expected, string $dsn)\n    {\n        $factory = $this->createFactory();\n        $provider = $factory->create(new Dsn($dsn));\n\n        $this->assertSame($expected, (string) $provider);\n    }\n\n    /**\n     * @dataProvider unsupportedSchemeProvider\n     */\n    #[DataProvider('unsupportedSchemeProvider')]\n    public function testUnsupportedSchemeException(string $dsn, ?string $message = null)\n    {\n        $factory = $this->createFactory();\n\n        $dsn = new Dsn($dsn);\n\n        $this->expectException(UnsupportedSchemeException::class);\n        if (null !== $message) {\n            $this->expectExceptionMessage($message);\n        }\n\n        $factory->create($dsn);\n    }\n}\n"
  },
  {
    "path": "Test/IncompleteDsnTestTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Test;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Symfony\\Component\\Translation\\Exception\\IncompleteDsnException;\nuse Symfony\\Component\\Translation\\Provider\\Dsn;\n\ntrait IncompleteDsnTestTrait\n{\n    /**\n     * @return iterable<array{0: string, 1?: string|null}>\n     */\n    abstract public static function incompleteDsnProvider(): iterable;\n\n    /**\n     * @dataProvider incompleteDsnProvider\n     */\n    #[DataProvider('incompleteDsnProvider')]\n    public function testIncompleteDsnException(string $dsn, ?string $message = null)\n    {\n        $factory = $this->createFactory();\n\n        $dsn = new Dsn($dsn);\n\n        $this->expectException(IncompleteDsnException::class);\n        if (null !== $message) {\n            $this->expectExceptionMessage($message);\n        }\n\n        $factory->create($dsn);\n    }\n}\n"
  },
  {
    "path": "Test/ProviderTestCase.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Test;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\HttpClient\\MockHttpClient;\nuse Symfony\\Component\\Translation\\Dumper\\XliffFileDumper;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\Loader\\LoaderInterface;\nuse Symfony\\Component\\Translation\\Provider\\ProviderInterface;\nuse Symfony\\Component\\Translation\\TranslatorBag;\nuse Symfony\\Component\\Translation\\TranslatorBagInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * A test case to ease testing a translation provider.\n *\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nabstract class ProviderTestCase extends TestCase\n{\n    protected HttpClientInterface $client;\n    protected LoggerInterface|MockObject $logger;\n    protected string $defaultLocale;\n    protected LoaderInterface|MockObject $loader;\n    protected XliffFileDumper|MockObject $xliffFileDumper;\n    protected TranslatorBagInterface|MockObject $translatorBag;\n\n    abstract public static function createProvider(HttpClientInterface $client, LoaderInterface $loader, LoggerInterface $logger, string $defaultLocale, string $endpoint): ProviderInterface;\n\n    /**\n     * @return iterable<array{0: ProviderInterface, 1: string}>\n     */\n    abstract public static function toStringProvider(): iterable;\n\n    /**\n     * @dataProvider toStringProvider\n     */\n    #[DataProvider('toStringProvider')]\n    public function testToString(ProviderInterface $provider, string $expected)\n    {\n        $this->assertSame($expected, (string) $provider);\n    }\n\n    protected function getClient(): MockHttpClient\n    {\n        return $this->client ??= new MockHttpClient();\n    }\n\n    protected function getLoader(): LoaderInterface\n    {\n        return $this->loader ??= new ArrayLoader();\n    }\n\n    protected function getLogger(): LoggerInterface\n    {\n        return $this->logger ??= new NullLogger();\n    }\n\n    protected function getDefaultLocale(): string\n    {\n        return $this->defaultLocale ??= 'en';\n    }\n\n    protected function getXliffFileDumper(): XliffFileDumper\n    {\n        return $this->xliffFileDumper ??= new XliffFileDumper();\n    }\n\n    protected function getTranslatorBag(): TranslatorBagInterface\n    {\n        return $this->translatorBag ??= new TranslatorBag();\n    }\n}\n"
  },
  {
    "path": "Tests/Catalogue/AbstractOperationTestCase.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Catalogue;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\nabstract class AbstractOperationTestCase extends TestCase\n{\n    public function testGetEmptyDomains()\n    {\n        $this->assertEquals(\n            [],\n            $this->createOperation(\n                new MessageCatalogue('en'),\n                new MessageCatalogue('en')\n            )->getDomains()\n        );\n    }\n\n    public function testGetMergedDomains()\n    {\n        $this->assertEquals(\n            ['a', 'b', 'c'],\n            $this->createOperation(\n                new MessageCatalogue('en', ['a' => [], 'b' => []]),\n                new MessageCatalogue('en', ['b' => [], 'c' => []])\n            )->getDomains()\n        );\n    }\n\n    public function testGetMessagesFromUnknownDomain()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->createOperation(\n            new MessageCatalogue('en'),\n            new MessageCatalogue('en')\n        )->getMessages('domain');\n    }\n\n    public function testGetEmptyMessages()\n    {\n        $this->assertEquals(\n            [],\n            $this->createOperation(\n                new MessageCatalogue('en', ['a' => []]),\n                new MessageCatalogue('en')\n            )->getMessages('a')\n        );\n    }\n\n    public function testGetEmptyResult()\n    {\n        $this->assertEquals(\n            new MessageCatalogue('en'),\n            $this->createOperation(\n                new MessageCatalogue('en'),\n                new MessageCatalogue('en')\n            )->getResult()\n        );\n    }\n\n    public function testSourceAndTargetWithDifferentLocales()\n    {\n        $this->expectException(LogicException::class);\n        $this->expectExceptionMessage('Operated catalogues must belong to the same locale.');\n        $this->createOperation(\n            new MessageCatalogue('en'),\n            new MessageCatalogue('fr')\n        );\n    }\n\n    abstract protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target);\n}\n"
  },
  {
    "path": "Tests/Catalogue/MergeOperationTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Catalogue;\n\nuse Symfony\\Component\\Translation\\Catalogue\\MergeOperation;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\nclass MergeOperationTest extends AbstractOperationTestCase\n{\n    public function testGetMessagesFromSingleDomain()\n    {\n        $operation = $this->createOperation(\n            new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]),\n            new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'c' => 'new_c']])\n        );\n\n        $this->assertEquals(\n            ['a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'],\n            $operation->getMessages('messages')\n        );\n\n        $this->assertEquals(\n            ['c' => 'new_c'],\n            $operation->getNewMessages('messages')\n        );\n\n        $this->assertEquals(\n            [],\n            $operation->getObsoleteMessages('messages')\n        );\n    }\n\n    public function testGetResultFromSingleDomain()\n    {\n        $this->assertEquals(\n            new MessageCatalogue('en', [\n                'messages' => ['a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c'],\n            ]),\n            $this->createOperation(\n                new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]),\n                new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'c' => 'new_c']])\n            )->getResult()\n        );\n    }\n\n    public function testGetResultFromIntlDomain()\n    {\n        $this->assertEquals(\n            new MessageCatalogue('en', [\n                'messages' => ['b' => 'old_b'],\n                'messages+intl-icu' => ['d' => 'old_d', 'c' => 'new_c', 'a' => 'new_a'],\n            ]),\n            $this->createOperation(\n                new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b'], 'messages+intl-icu' => ['d' => 'old_d']]),\n                new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'new_a', 'c' => 'new_c']])\n            )->getResult()\n        );\n    }\n\n    public function testGetResultWithMetadata()\n    {\n        $leftCatalogue = new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]);\n        $leftCatalogue->setMetadata('a', 'foo', 'messages');\n        $leftCatalogue->setMetadata('b', 'bar', 'messages');\n        $rightCatalogue = new MessageCatalogue('en', ['messages' => ['b' => 'new_b', 'c' => 'new_c']]);\n        $rightCatalogue->setMetadata('b', 'baz', 'messages');\n        $rightCatalogue->setMetadata('c', 'qux', 'messages');\n\n        $mergedCatalogue = new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c']]);\n        $mergedCatalogue->setMetadata('a', 'foo', 'messages');\n        $mergedCatalogue->setMetadata('b', 'bar', 'messages');\n        $mergedCatalogue->setMetadata('c', 'qux', 'messages');\n\n        $this->assertEquals(\n            $mergedCatalogue,\n            $this->createOperation(\n                $leftCatalogue,\n                $rightCatalogue\n            )->getResult()\n        );\n    }\n\n    public function testGetResultWithMetadataFromIntlDomain()\n    {\n        $leftCatalogue = new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'old_a', 'b' => 'old_b']]);\n        $leftCatalogue->setMetadata('a', 'foo', 'messages+intl-icu');\n        $leftCatalogue->setMetadata('b', 'bar', 'messages+intl-icu');\n        $rightCatalogue = new MessageCatalogue('en', ['messages+intl-icu' => ['b' => 'new_b', 'c' => 'new_c']]);\n        $rightCatalogue->setMetadata('b', 'baz', 'messages+intl-icu');\n        $rightCatalogue->setMetadata('c', 'qux', 'messages+intl-icu');\n\n        $mergedCatalogue = new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'old_a', 'b' => 'old_b', 'c' => 'new_c']]);\n        $mergedCatalogue->setMetadata('a', 'foo', 'messages+intl-icu');\n        $mergedCatalogue->setMetadata('b', 'bar', 'messages+intl-icu');\n        $mergedCatalogue->setMetadata('c', 'qux', 'messages+intl-icu');\n\n        $this->assertEquals(\n            $mergedCatalogue,\n            $this->createOperation(\n                $leftCatalogue,\n                $rightCatalogue\n            )->getResult()\n        );\n    }\n\n    protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target)\n    {\n        return new MergeOperation($source, $target);\n    }\n}\n"
  },
  {
    "path": "Tests/Catalogue/MessageCatalogueTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Catalogue;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass MessageCatalogueTest extends TestCase\n{\n    public function testIcuMetadataKept()\n    {\n        $mc = new MessageCatalogue('en', ['messages' => ['a' => 'new_a']]);\n        $metadata = ['metadata' => 'value'];\n        $mc->setMetadata('a', $metadata, 'messages+intl-icu');\n        $this->assertEquals($metadata, $mc->getMetadata('a', 'messages'));\n        $this->assertEquals($metadata, $mc->getMetadata('a', 'messages+intl-icu'));\n    }\n}\n"
  },
  {
    "path": "Tests/Catalogue/TargetOperationTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Catalogue;\n\nuse Symfony\\Component\\Translation\\Catalogue\\TargetOperation;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\nclass TargetOperationTest extends AbstractOperationTestCase\n{\n    public function testGetMessagesFromSingleDomain()\n    {\n        $operation = $this->createOperation(\n            new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]),\n            new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'c' => 'new_c']])\n        );\n\n        $this->assertEquals(\n            ['a' => 'old_a', 'c' => 'new_c'],\n            $operation->getMessages('messages')\n        );\n\n        $this->assertEquals(\n            ['c' => 'new_c'],\n            $operation->getNewMessages('messages')\n        );\n\n        $this->assertEquals(\n            ['b' => 'old_b'],\n            $operation->getObsoleteMessages('messages')\n        );\n    }\n\n    public function testGetResultFromSingleDomain()\n    {\n        $this->assertEquals(\n            new MessageCatalogue('en', [\n                'messages' => ['a' => 'old_a', 'c' => 'new_c'],\n            ]),\n            $this->createOperation(\n                new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]),\n                new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'c' => 'new_c']])\n            )->getResult()\n        );\n    }\n\n    public function testGetResultFromIntlDomain()\n    {\n        $this->assertEquals(\n            new MessageCatalogue('en', [\n                'messages' => ['a' => 'old_a'],\n                'messages+intl-icu' => ['c' => 'new_c'],\n            ]),\n            $this->createOperation(\n                new MessageCatalogue('en', ['messages' => ['a' => 'old_a'], 'messages+intl-icu' => ['b' => 'old_b']]),\n                new MessageCatalogue('en', ['messages' => ['a' => 'new_a'], 'messages+intl-icu' => ['c' => 'new_c']])\n            )->getResult()\n        );\n    }\n\n    public function testGetResultWithMixedDomains()\n    {\n        $this->assertEquals(\n            new MessageCatalogue('en', [\n                'messages+intl-icu' => ['a' => 'new_a'],\n            ]),\n            $this->createOperation(\n                new MessageCatalogue('en', ['messages' => ['a' => 'old_a']]),\n                new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'new_a']])\n            )->getResult()\n        );\n\n        $this->assertEquals(\n            new MessageCatalogue('en', [\n                'messages+intl-icu' => ['a' => 'old_a'],\n            ]),\n            $this->createOperation(\n                new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'old_a']]),\n                new MessageCatalogue('en', ['messages' => ['a' => 'new_a']])\n            )->getResult()\n        );\n\n        $this->assertEquals(\n            new MessageCatalogue('en', [\n                'messages+intl-icu' => ['a' => 'old_a'],\n                'messages' => ['b' => 'new_b'],\n            ]),\n            $this->createOperation(\n                new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'old_a']]),\n                new MessageCatalogue('en', ['messages' => ['a' => 'new_a', 'b' => 'new_b']])\n            )->getResult()\n        );\n\n        $this->assertEquals(\n            new MessageCatalogue('en', [\n                'messages+intl-icu' => ['b' => 'new_b', 'a' => 'new_a'],\n            ]),\n            $this->createOperation(\n                new MessageCatalogue('en', ['messages' => ['a' => 'old_a']]),\n                new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'new_a', 'b' => 'new_b']])\n            )->getResult()\n        );\n    }\n\n    public function testGetResultWithMetadata()\n    {\n        $leftCatalogue = new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b']]);\n        $leftCatalogue->setMetadata('a', 'foo', 'messages');\n        $leftCatalogue->setMetadata('b', 'bar', 'messages');\n        $rightCatalogue = new MessageCatalogue('en', ['messages' => ['b' => 'new_b', 'c' => 'new_c']]);\n        $rightCatalogue->setMetadata('b', 'baz', 'messages');\n        $rightCatalogue->setMetadata('c', 'qux', 'messages');\n\n        $diffCatalogue = new MessageCatalogue('en', ['messages' => ['b' => 'old_b', 'c' => 'new_c']]);\n        $diffCatalogue->setMetadata('b', 'bar', 'messages');\n        $diffCatalogue->setMetadata('c', 'qux', 'messages');\n\n        $this->assertEquals(\n            $diffCatalogue,\n            $this->createOperation(\n                $leftCatalogue,\n                $rightCatalogue\n            )->getResult()\n        );\n    }\n\n    public function testGetResultWithMetadataFromIntlDomain()\n    {\n        $leftCatalogue = new MessageCatalogue('en', ['messages+intl-icu' => ['a' => 'old_a', 'b' => 'old_b']]);\n        $leftCatalogue->setMetadata('a', 'foo', 'messages+intl-icu');\n        $leftCatalogue->setMetadata('b', 'bar', 'messages+intl-icu');\n        $rightCatalogue = new MessageCatalogue('en', ['messages+intl-icu' => ['b' => 'new_b', 'c' => 'new_c']]);\n        $rightCatalogue->setMetadata('b', 'baz', 'messages+intl-icu');\n        $rightCatalogue->setMetadata('c', 'qux', 'messages+intl-icu');\n\n        $diffCatalogue = new MessageCatalogue('en', ['messages+intl-icu' => ['b' => 'old_b', 'c' => 'new_c']]);\n        $diffCatalogue->setMetadata('b', 'bar', 'messages+intl-icu');\n        $diffCatalogue->setMetadata('c', 'qux', 'messages+intl-icu');\n\n        $this->assertEquals(\n            $diffCatalogue,\n            $this->createOperation(\n                $leftCatalogue,\n                $rightCatalogue\n            )->getResult()\n        );\n    }\n\n    protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target)\n    {\n        return new TargetOperation($source, $target);\n    }\n}\n"
  },
  {
    "path": "Tests/Command/TranslationLintCommandTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Command;\n\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Tester\\CommandTester;\nuse Symfony\\Component\\Translation\\Command\\TranslationLintCommand;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\Translator;\n\nfinal class TranslationLintCommandTest extends TestCase\n{\n    #[RequiresPhpExtension('intl')]\n    public function testLintCorrectTranslations()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['hello' => 'Hello!'], 'en', 'messages');\n        $translator->addResource('array', [\n            'hello_name' => 'Hello {name}!',\n            'num_of_apples' => <<<ICU\n                    {apples, plural,\n                        =0    {There are no apples}\n                        =1    {There is one apple...}\n                        other {There are # apples!}\n                    }\n                ICU,\n        ], 'en', 'messages+intl-icu');\n        $translator->addResource('array', ['hello' => 'Bonjour !'], 'fr', 'messages');\n        $translator->addResource('array', [\n            'hello_name' => 'Bonjour {name} !',\n            'num_of_apples' => <<<ICU\n                    {apples, plural,\n                        =0    {Il n'y a pas de pommes}\n                        =1    {Il y a une pomme}\n                        other {Il y a # pommes !}\n                    }\n                ICU,\n        ], 'fr', 'messages+intl-icu');\n\n        $command = $this->createCommand($translator, ['en', 'fr']);\n        $commandTester = new CommandTester($command);\n\n        $commandTester->execute([], ['decorated' => false]);\n\n        $commandTester->assertCommandIsSuccessful();\n\n        $display = $this->getNormalizedDisplay($commandTester);\n        $this->assertStringContainsString('[OK] All translations are valid.', $display);\n    }\n\n    #[RequiresPhpExtension('intl')]\n    public function testLintMalformedIcuTranslations()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['hello' => 'Hello!'], 'en', 'messages');\n        $translator->addResource('array', [\n            'hello_name' => 'Hello {name}!',\n            // Missing \"other\" case\n            'num_of_apples' => <<<ICU\n                    {apples, plural,\n                        =0    {There are no apples}\n                        =1    {There is one apple...}\n                    }\n                ICU,\n        ], 'en', 'messages+intl-icu');\n        $translator->addResource('array', ['hello' => 'Bonjour !'], 'fr', 'messages');\n        $translator->addResource('array', [\n            // Missing \"}\"\n            'hello_name' => 'Bonjour {name !',\n            // \"other\" is translated\n            'num_of_apples' => <<<ICU\n                    {apples, plural,\n                        =0    {Il n'y a pas de pommes}\n                        =1    {Il y a une pomme}\n                        autre {Il y a # pommes !}\n                    }\n                ICU,\n        ], 'fr', 'messages+intl-icu');\n\n        $command = $this->createCommand($translator, ['en', 'fr']);\n        $commandTester = new CommandTester($command);\n\n        $this->assertSame(1, $commandTester->execute([], ['decorated' => false]));\n\n        $display = $this->getNormalizedDisplay($commandTester);\n        $this->assertStringContainsString(<<<EOF\n             -------- ---------- --------\n              Locale   Domains    Valid?\n             -------- ---------- --------\n              en       messages   No\n              fr       messages   No\n             -------- ---------- --------\n            EOF,\n            $display\n        );\n        $this->assertStringContainsString(\\sprintf(<<<EOF\n            Errors for locale \"en\" and domain \"messages\"\n            --------------------------------------------\n\n             Translation key \"num_of_apples\" is invalid:\n\n             [ERROR] Invalid message format (error #65807): %s: message formatter creation failed:\n                     U_DEFAULT_KEYWORD_MISSING\n            EOF,\n            \\PHP_VERSION_ID >= 80500 ? 'MessageFormatter::__construct()' : 'msgfmt_create'\n        ), $display);\n\n        if (\\PHP_VERSION_ID >= 80500) {\n            $this->assertStringContainsString(<<<EOF\n                Errors for locale \"fr\" and domain \"messages\"\n                --------------------------------------------\n\n                 Translation key \"hello_name\" is invalid:\n\n                 [ERROR] Invalid message format (error #65799): MessageFormatter::__construct(): pattern syntax error (parse error at\n                         offset 9, after \"Bonjour {\", before or at \"name !\"): U_PATTERN_SYNTAX_ERROR\n\n                 Translation key \"num_of_apples\" is invalid:\n\n                 [ERROR] Invalid message format (error #65807): MessageFormatter::__construct(): message formatter creation failed:\n                         U_DEFAULT_KEYWORD_MISSING\n                EOF,\n                $display\n            );\n        } else {\n            $this->assertStringContainsString(<<<EOF\n                Errors for locale \"fr\" and domain \"messages\"\n                --------------------------------------------\n\n                 Translation key \"hello_name\" is invalid:\n\n                 [ERROR] Invalid message format (error #65799): pattern syntax error (parse error at offset 9, after \"Bonjour {\", before\n                         or at \"name !\"): U_PATTERN_SYNTAX_ERROR\n\n                 Translation key \"num_of_apples\" is invalid:\n\n                 [ERROR] Invalid message format (error #65807): msgfmt_create: message formatter creation failed:\n                         U_DEFAULT_KEYWORD_MISSING\n                EOF,\n                $display\n            );\n        }\n    }\n\n    private function createCommand(Translator $translator, array $enabledLocales): Command\n    {\n        $command = new TranslationLintCommand($translator, $enabledLocales);\n\n        $application = new Application();\n        $application->addCommand($command);\n\n        return $command;\n    }\n\n    /**\n     * Normalize the CommandTester display, by removing trailing spaces for each line.\n     */\n    private function getNormalizedDisplay(CommandTester $commandTester): string\n    {\n        return implode(\"\\n\", array_map(rtrim(...), explode(\"\\n\", $commandTester->getDisplay(true))));\n    }\n}\n"
  },
  {
    "path": "Tests/Command/TranslationProviderTestCase.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Command;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Filesystem\\Filesystem;\nuse Symfony\\Component\\Translation\\Provider\\FilteringProvider;\nuse Symfony\\Component\\Translation\\Provider\\ProviderInterface;\nuse Symfony\\Component\\Translation\\Provider\\TranslationProviderCollection;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nabstract class TranslationProviderTestCase extends TestCase\n{\n    protected Filesystem $fs;\n    protected string $translationAppDir;\n    protected array $files;\n    protected string $defaultLocale;\n\n    protected function setUp(): void\n    {\n        $this->defaultLocale = \\Locale::getDefault();\n        \\Locale::setDefault('en');\n        $this->fs = new Filesystem();\n        $this->translationAppDir = tempnam(sys_get_temp_dir(), 'sf_translation_');\n        $this->fs->remove($this->translationAppDir);\n        $this->fs->mkdir($this->translationAppDir.'/translations');\n    }\n\n    protected function tearDown(): void\n    {\n        \\Locale::setDefault($this->defaultLocale);\n        $this->fs->remove($this->translationAppDir);\n    }\n\n    protected function getProviderCollection(ProviderInterface $provider, array $providerNames = ['loco'], array $locales = ['en'], array $domains = ['messages']): TranslationProviderCollection\n    {\n        $collection = [];\n\n        foreach ($providerNames as $providerName) {\n            $collection[$providerName] = new FilteringProvider($provider, $locales, $domains);\n        }\n\n        return new TranslationProviderCollection($collection);\n    }\n\n    protected function createYamlFile(array $messages = ['node' => 'NOTE'], $targetLanguage = 'en', $fileNamePattern = 'messages.%locale%.yml'): string\n    {\n        $yamlContent = '';\n        foreach ($messages as $key => $value) {\n            $yamlContent .= \"$key: $value\\n\";\n        }\n        $yamlContent .= \"\\n\";\n\n        $filename = \\sprintf('%s/%s', $this->translationAppDir.'/translations', str_replace('%locale%', $targetLanguage, $fileNamePattern));\n        file_put_contents($filename, $yamlContent);\n\n        $this->files[] = $filename;\n\n        return $filename;\n    }\n\n    protected function createFile(array $messages = ['note' => 'NOTE'], $targetLanguage = 'en', $fileNamePattern = 'messages.%locale%.xlf', string $xlfVersion = 'xlf12'): string\n    {\n        if ('xlf12' === $xlfVersion) {\n            $transUnits = '';\n            foreach ($messages as $key => $value) {\n                $transUnits .= <<<XLIFF\n                    <trans-unit id=\"$key\">\n                        <source>$key</source>\n                        <target>$value</target>\n                    </trans-unit>\n                    XLIFF;\n            }\n            $xliffContent = <<<XLIFF\n                <?xml version=\"1.0\"?>\n                <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                    <file source-language=\"en\" target-language=\"$targetLanguage\" datatype=\"plaintext\" original=\"file.ext\">\n                        <body>\n                            $transUnits\n                        </body>\n                    </file>\n                </xliff>\n                XLIFF;\n        } else {\n            $units = '';\n            foreach ($messages as $key => $value) {\n                $units .= <<<XLIFF\n                    <unit id=\"$key\">\n                      <segment>\n                        <source>$key</source>\n                        <target>$value</target>\n                      </segment>\n                    </unit>\n                    XLIFF;\n            }\n            $xliffContent = <<<XLIFF\n                <?xml version=\"1.0\" encoding=\"utf-8\"?>\n                <xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en\" trgLang=\"$targetLanguage\">\n                  <file id=\"messages.$targetLanguage\">\n                    $units\n                  </file>\n                </xliff>\n                XLIFF;\n        }\n\n        $filename = \\sprintf('%s/%s', $this->translationAppDir.'/translations', str_replace('%locale%', $targetLanguage, $fileNamePattern));\n        file_put_contents($filename, $xliffContent);\n\n        $this->files[] = $filename;\n\n        return $filename;\n    }\n}\n"
  },
  {
    "path": "Tests/Command/TranslationPullCommandTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Command;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Tester\\CommandCompletionTester;\nuse Symfony\\Component\\Console\\Tester\\CommandTester;\nuse Symfony\\Component\\Translation\\Command\\TranslationPullCommand;\nuse Symfony\\Component\\Translation\\Dumper\\XliffFileDumper;\nuse Symfony\\Component\\Translation\\Dumper\\YamlFileDumper;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\Loader\\XliffFileLoader;\nuse Symfony\\Component\\Translation\\Loader\\YamlFileLoader;\nuse Symfony\\Component\\Translation\\Provider\\ProviderInterface;\nuse Symfony\\Component\\Translation\\Reader\\TranslationReader;\nuse Symfony\\Component\\Translation\\TranslatorBag;\nuse Symfony\\Component\\Translation\\Writer\\TranslationWriter;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nclass TranslationPullCommandTest extends TranslationProviderTestCase\n{\n    private string|false $colSize;\n\n    protected function setUp(): void\n    {\n        $this->colSize = getenv('COLUMNS');\n        putenv('COLUMNS='.(119 + \\strlen(\\PHP_EOL)));\n        parent::setUp();\n    }\n\n    protected function tearDown(): void\n    {\n        parent::tearDown();\n        putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS');\n    }\n\n    public function testPullNewXlf12Messages()\n    {\n        $arrayLoader = new ArrayLoader();\n        $filenameEn = $this->createFile();\n        $filenameEnIcu = $this->createFile(['say_hello' => 'Welcome, {firstname}!'], 'en', 'messages+intl-icu.%locale%.xlf');\n        $filenameFr = $this->createFile(['note' => 'NOTE'], 'fr');\n        $filenameFrIcu = $this->createFile(['say_hello' => 'Bonjour, {firstname}!'], 'fr', 'messages+intl-icu.%locale%.xlf');\n        $locales = ['en', 'fr'];\n        $domains = ['messages', 'messages+intl-icu'];\n\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'newFoo',\n        ], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'say_hello' => 'Welcome, {firstname}!',\n        ], 'en', 'messages+intl-icu'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'say_hello' => 'Bonjour, {firstname}!',\n        ], 'fr', 'messages+intl-icu'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages', 'messages+intl-icu']]);\n\n        $this->assertStringContainsString('[OK] New translations from \"null\" has been written locally (for \"en, fr\" locale(s), and \"messages, messages+intl-icu\"', trim($tester->getDisplay()));\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>newFoo</target>\n                        </trans-unit>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>NOTE</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameEn)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"Shv46xh\" resname=\"say_hello\">\n                            <source>say_hello</source>\n                            <target>Welcome, {firstname}!</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameEnIcu)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"fr\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>nouveauFoo</target>\n                        </trans-unit>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>NOTE</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameFr)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"fr\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"Shv46xh\" resname=\"say_hello\">\n                            <source>say_hello</source>\n                            <target>Bonjour, {firstname}!</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameFrIcu)\n        );\n    }\n\n    public function testPullNewXlf20Messages()\n    {\n        $arrayLoader = new ArrayLoader();\n        $filenameEn = $this->createFile(['note' => 'NOTE'], 'en', 'messages.%locale%.xlf', 'xlf20');\n        $filenameFr = $this->createFile(['note' => 'NOTE'], 'fr', 'messages.%locale%.xlf', 'xlf20');\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'newFoo',\n        ], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages'], '--format' => 'xlf20']);\n\n        $this->assertStringContainsString('[OK] New translations from \"null\" has been written locally (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\" encoding=\"utf-8\"?>\n            <xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en\" trgLang=\"en\">\n              <file id=\"messages.en\">\n                <unit id=\"5pyqChA\" name=\"new.foo\">\n                  <segment>\n                    <source>new.foo</source>\n                    <target>newFoo</target>\n                  </segment>\n                </unit>\n                <unit id=\".DOalbi\" name=\"note\">\n                  <segment>\n                    <source>note</source>\n                    <target>NOTE</target>\n                  </segment>\n                </unit>\n              </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameEn)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\" encoding=\"utf-8\"?>\n            <xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en\" trgLang=\"fr\">\n              <file id=\"messages.fr\">\n                <unit id=\"5pyqChA\" name=\"new.foo\">\n                  <segment>\n                    <source>new.foo</source>\n                    <target>nouveauFoo</target>\n                  </segment>\n                </unit>\n                <unit id=\".DOalbi\" name=\"note\">\n                  <segment>\n                    <source>note</source>\n                    <target>NOTE</target>\n                  </segment>\n                </unit>\n              </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameFr)\n        );\n    }\n\n    public function testPullNewYamlMessagesAsInlined()\n    {\n        $arrayLoader = new ArrayLoader();\n        $filenameEn = $this->createYamlFile(['note' => 'NOTE'], 'en', 'messages.%locale%.yml');\n        $filenameFr = $this->createYamlFile(['note' => 'NOTE'], 'fr', 'messages.%locale%.yml');\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'newFoo',\n        ], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages'], '--format' => 'yml']);\n\n        $this->assertStringContainsString('[OK] New translations from \"null\" has been written locally (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertEquals(<<<YAML\n            new.foo: newFoo\n            note: NOTE\n\n            YAML,\n            file_get_contents($filenameEn)\n        );\n        $this->assertEquals(<<<YAML\n            new.foo: nouveauFoo\n            note: NOTE\n\n            YAML,\n            file_get_contents($filenameFr)\n        );\n    }\n\n    public function testPullNewYamlMessagesAsTree()\n    {\n        $arrayLoader = new ArrayLoader();\n        $filenameEn = $this->createYamlFile(['note' => 'NOTE'], 'en', 'messages.%locale%.yml');\n        $filenameFr = $this->createYamlFile(['note' => 'NOTE'], 'fr', 'messages.%locale%.yml');\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'newFoo',\n        ], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages'], '--format' => 'yml', '--as-tree' => 10]);\n\n        $this->assertStringContainsString('[OK] New translations from \"null\" has been written locally (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertEquals(<<<YAML\n            new:\n                foo: newFoo\n            note: NOTE\n\n            YAML,\n            file_get_contents($filenameEn)\n        );\n        $this->assertEquals(<<<YAML\n            new:\n                foo: nouveauFoo\n            note: NOTE\n\n            YAML,\n            file_get_contents($filenameFr)\n        );\n    }\n\n    public function testPullForceMessages()\n    {\n        $arrayLoader = new ArrayLoader();\n        $filenameMessagesEn = $this->createFile(['note' => 'NOTE'], 'en');\n        $filenameMessagesFr = $this->createFile(['note' => 'NOTE'], 'fr');\n        $filenameValidatorsEn = $this->createFile(['foo.error' => 'Wrong value'], 'en', 'validators.%locale%.xlf');\n        $filenameValidatorsFr = $this->createFile(['foo.error' => 'Valeur erronée'], 'fr', 'validators.%locale%.xlf');\n        $locales = ['en', 'fr'];\n        $domains = ['messages', 'validators'];\n\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'UPDATED NOTE',\n            'new.foo' => 'newFoo',\n        ], 'en', 'messages'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE MISE À JOUR',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr', 'messages'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'foo.error' => 'Bad value',\n            'bar.error' => 'Bar error',\n        ], 'en', 'validators'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'foo.error' => 'Valeur invalide',\n            'bar.error' => 'Bar erreur',\n        ], 'fr', 'validators'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n        $tester->execute(['--locales' => $locales, '--domains' => $domains, '--force' => true]);\n\n        $this->assertStringContainsString('[OK] Local translations has been updated from \"null\" (for \"en, fr\" locale(s), and \"messages, validators\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>UPDATED NOTE</target>\n                        </trans-unit>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>newFoo</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameMessagesEn)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"fr\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>NOTE MISE À JOUR</target>\n                        </trans-unit>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>nouveauFoo</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameMessagesFr)\n        );\n\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"nYScnTy\" resname=\"foo.error\">\n                            <source>foo.error</source>\n                            <target>Bad value</target>\n                        </trans-unit>\n                        <trans-unit id=\"fe0ouWC\" resname=\"bar.error\">\n                            <source>bar.error</source>\n                            <target>Bar error</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameValidatorsEn)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"fr\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"nYScnTy\" resname=\"foo.error\">\n                            <source>foo.error</source>\n                            <target>Valeur invalide</target>\n                        </trans-unit>\n                        <trans-unit id=\"fe0ouWC\" resname=\"bar.error\">\n                            <source>bar.error</source>\n                            <target>Bar erreur</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameValidatorsFr)\n        );\n    }\n\n    #[RequiresPhpExtension('intl')]\n    public function testPullForceIntlIcuMessages()\n    {\n        $arrayLoader = new ArrayLoader();\n        $filenameEn = $this->createFile(['note' => 'NOTE'], 'en', 'messages+intl-icu.%locale%.xlf');\n        $filenameFr = $this->createFile(['note' => 'NOTE'], 'fr', 'messages+intl-icu.%locale%.xlf');\n\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'UPDATED NOTE',\n            'new.foo' => 'newFoo',\n        ], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE MISE À JOUR',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages'], '--force' => true, '--intl-icu' => true]);\n\n        $this->assertStringContainsString('[OK] Local translations has been updated from \"null\" (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>UPDATED NOTE</target>\n                        </trans-unit>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>newFoo</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameEn)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"fr\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>NOTE MISE À JOUR</target>\n                        </trans-unit>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>nouveauFoo</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameFr)\n        );\n    }\n\n    public function testPullMessagesWithDefaultLocale()\n    {\n        $arrayLoader = new ArrayLoader();\n        $filenameFr = $this->createFile(['note' => 'NOTE'], 'fr');\n        $filenameEn = $this->createFile(['note' => 'NOTE']);\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'new.foo' => 'newFoo',\n        ], 'en'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains, 'fr');\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages']]);\n\n        $this->assertStringContainsString('[OK] New translations from \"null\" has been written locally (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"fr\" target-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>newFoo</target>\n                        </trans-unit>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>NOTE</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameEn)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"fr\" target-language=\"fr\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>nouveauFoo</target>\n                        </trans-unit>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>NOTE</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameFr)\n        );\n    }\n\n    public function testPullMessagesMultipleDomains()\n    {\n        $arrayLoader = new ArrayLoader();\n        $filenameMessages = $this->createFile(['note' => 'NOTE']);\n        $filenameDomain = $this->createFile(['note' => 'NOTE'], 'en', 'domain.%locale%.xlf');\n        $locales = ['en'];\n        $domains = ['messages', 'domain'];\n\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'new.foo' => 'newFoo',\n        ], 'en'));\n\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'new.foo' => 'newFoo',\n        ], 'en',\n            'domain'\n        ));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains, 'en');\n        $tester->execute(['--locales' => ['en'], '--domains' => ['messages', 'domain']]);\n\n        $this->assertStringContainsString('[OK] New translations from \"null\" has been written locally (for \"en\" locale(s), and \"messages, domain\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>newFoo</target>\n                        </trans-unit>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>NOTE</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameMessages)\n        );\n        $this->assertXmlStringEqualsXmlString(<<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                    <header>\n                        <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n                    </header>\n                    <body>\n                        <trans-unit id=\"5pyqChA\" resname=\"new.foo\">\n                            <source>new.foo</source>\n                            <target>newFoo</target>\n                        </trans-unit>\n                        <trans-unit id=\".DOalbi\" resname=\"note\">\n                            <source>note</source>\n                            <target>NOTE</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF,\n            file_get_contents($filenameDomain)\n        );\n    }\n\n    #[DataProvider('provideCompletionSuggestions')]\n    public function testComplete(array $input, array $expectedSuggestions)\n    {\n        $application = new Application();\n        $application->addCommand($this->createCommand($this->createStub(ProviderInterface::class), ['en', 'fr', 'it'], ['messages', 'validators'], 'en', ['loco', 'crowdin', 'lokalise']));\n\n        $tester = new CommandCompletionTester($application->get('translation:pull'));\n        $suggestions = $tester->complete($input);\n        $this->assertSame($expectedSuggestions, $suggestions);\n    }\n\n    public static function provideCompletionSuggestions(): \\Generator\n    {\n        yield 'provider' => [\n            [''],\n            ['loco', 'crowdin', 'lokalise'],\n        ];\n\n        yield '--domains' => [\n            ['loco', '--domains'],\n            ['messages', 'validators'],\n        ];\n\n        yield '--locales' => [\n            ['loco', '--locales'],\n            ['en', 'fr', 'it'],\n        ];\n    }\n\n    private function createCommandTester(ProviderInterface $provider, array $locales = ['en'], array $domains = ['messages'], $defaultLocale = 'en'): CommandTester\n    {\n        $command = $this->createCommand($provider, $locales, $domains, $defaultLocale);\n        $application = new Application();\n        $application->addCommand($command);\n\n        return new CommandTester($application->find('translation:pull'));\n    }\n\n    private function createCommand(ProviderInterface $provider, array $locales = ['en'], array $domains = ['messages'], $defaultLocale = 'en', array $providerNames = ['loco']): TranslationPullCommand\n    {\n        $writer = new TranslationWriter();\n        $writer->addDumper('xlf', new XliffFileDumper());\n        $writer->addDumper('yml', new YamlFileDumper());\n\n        $reader = new TranslationReader();\n        $reader->addLoader('xlf', new XliffFileLoader());\n        $reader->addLoader('yml', new YamlFileLoader());\n\n        return new TranslationPullCommand(\n            $this->getProviderCollection($provider, $providerNames, $locales, $domains),\n            $writer,\n            $reader,\n            $defaultLocale,\n            [$this->translationAppDir.'/translations'],\n            $locales\n        );\n    }\n}\n"
  },
  {
    "path": "Tests/Command/TranslationPushCommandTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Command;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Tester\\CommandCompletionTester;\nuse Symfony\\Component\\Console\\Tester\\CommandTester;\nuse Symfony\\Component\\Translation\\Command\\TranslationPushCommand;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\Loader\\XliffFileLoader;\nuse Symfony\\Component\\Translation\\Provider\\FilteringProvider;\nuse Symfony\\Component\\Translation\\Provider\\ProviderInterface;\nuse Symfony\\Component\\Translation\\Provider\\TranslationProviderCollection;\nuse Symfony\\Component\\Translation\\Reader\\TranslationReader;\nuse Symfony\\Component\\Translation\\TranslatorBag;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nclass TranslationPushCommandTest extends TranslationProviderTestCase\n{\n    private string|false $colSize;\n\n    protected function setUp(): void\n    {\n        $this->colSize = getenv('COLUMNS');\n        putenv('COLUMNS='.(119 + \\strlen(\\PHP_EOL)));\n        parent::setUp();\n    }\n\n    protected function tearDown(): void\n    {\n        parent::tearDown();\n        putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS');\n    }\n\n    public function testPushNewMessages()\n    {\n        $arrayLoader = new ArrayLoader();\n        $xliffLoader = new XliffFileLoader();\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        // Simulate existing messages on Provider\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'fr'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        // Create local files, with a new message\n        $filenameEn = $this->createFile([\n            'note' => 'NOTE',\n            'new.foo' => 'newFoo',\n        ]);\n        $filenameFr = $this->createFile([\n            'note' => 'NOTE',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr');\n        $localTranslatorBag = new TranslatorBag();\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameEn, 'en'));\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameFr, 'fr'));\n\n        $provider->expects($this->once())\n            ->method('write')\n            ->with($localTranslatorBag->diff($providerReadTranslatorBag));\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages']]);\n\n        $this->assertStringContainsString('[OK] New local translations has been sent to \"null\" (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n    }\n\n    public function testPushNewIntlIcuMessages()\n    {\n        $arrayLoader = new ArrayLoader();\n        $xliffLoader = new XliffFileLoader();\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        // Simulate existing messages on Provider\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'fr'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n\n        // Create local files, with a new message\n        $filenameEn = $this->createFile([\n            'note' => 'NOTE',\n            'new.foo' => 'newFooIntlIcu',\n        ], 'en', 'messages+intl-icu.%locale%.xlf');\n        $filenameFr = $this->createFile([\n            'note' => 'NOTE',\n            'new.foo' => 'nouveauFooIntlIcu',\n        ], 'fr', 'messages+intl-icu.%locale%.xlf');\n        $localTranslatorBag = new TranslatorBag();\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameEn, 'en'));\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameFr, 'fr'));\n\n        $provider->expects($this->once())\n            ->method('write')\n            ->with($localTranslatorBag->diff($providerReadTranslatorBag));\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages']]);\n\n        $this->assertStringContainsString('[OK] New local translations has been sent to \"null\" (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n    }\n\n    public function testPushForceMessages()\n    {\n        $xliffLoader = new XliffFileLoader();\n        $filenameMessagesEn = $this->createFile([\n            'note' => 'NOTE UPDATED',\n            'new.foo' => 'newFoo',\n        ], 'en');\n        $filenameMessagesFr = $this->createFile([\n            'note' => 'NOTE MISE À JOUR',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr');\n        $filenameValidatorsEn = $this->createFile([\n            'foo.error' => 'Wrong value',\n            'bar.success' => 'Form valid!',\n        ], 'en', 'validators.%locale%.xlf');\n        $filenameValidatorsFr = $this->createFile([\n            'foo.error' => 'Valeur erronée',\n            'bar.success' => 'Formulaire valide !',\n        ], 'fr', 'validators.%locale%.xlf');\n        $locales = ['en', 'fr'];\n        $domains = ['messages', 'validators'];\n\n        $provider = $this->createMock(ProviderInterface::class);\n\n        $localTranslatorBag = new TranslatorBag();\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameMessagesEn, 'en', 'messages'));\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameMessagesFr, 'fr', 'messages'));\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameValidatorsEn, 'en', 'validators'));\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameValidatorsFr, 'fr', 'validators'));\n\n        $provider->expects($this->once())\n            ->method('write')\n            ->with($localTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n\n        $tester->execute(['--locales' => $locales, '--domains' => $domains, '--force' => true]);\n\n        $this->assertStringContainsString('[OK] All local translations has been sent to \"null\" (for \"en, fr\" locale(s), and \"messages, validators\" domain(s)).', trim($tester->getDisplay()));\n    }\n\n    public function testDeleteMissingMessages()\n    {\n        $xliffLoader = new XliffFileLoader();\n        $arrayLoader = new ArrayLoader();\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        // Simulate existing messages on Provider.\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'obsolete.foo' => 'obsoleteFoo',\n        ], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'obsolete.foo' => 'obsolèteFoo',\n        ], 'fr'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider\n            ->method('read')\n            ->willReturnMap([\n                [$domains, $locales, $providerReadTranslatorBag],\n            ]);\n\n        // Create local bag, with a missing message.\n        $localTranslatorBag = new TranslatorBag();\n        $localTranslatorBag->addCatalogue($xliffLoader->load($this->createFile(), 'en'));\n        $localTranslatorBag->addCatalogue($xliffLoader->load($this->createFile(['note' => 'NOTE'], 'fr'), 'fr'));\n\n        $missingTranslatorBag = $providerReadTranslatorBag->diff($localTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('delete')\n            ->with($missingTranslatorBag);\n\n        // Read provider translations again, after missing translations deletion,\n        // to avoid push freshly deleted translations.\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'fr'));\n\n        $provider\n            ->method('read')\n            ->willReturnMap([\n                [$domains, $locales, $providerReadTranslatorBag],\n            ]);\n\n        $provider->expects($this->once())\n            ->method('write')\n            ->with($localTranslatorBag->diff($providerReadTranslatorBag));\n\n        $provider->expects($this->exactly(2))\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages'], '--delete-missing' => true]);\n\n        $this->assertStringContainsString('[OK] Missing translations on \"null\" has been deleted (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertStringContainsString('[OK] New local translations has been sent to \"null\" (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n    }\n\n    public function testPushForceAndDeleteMissingMessages()\n    {\n        $xliffLoader = new XliffFileLoader();\n        $arrayLoader = new ArrayLoader();\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        // Simulate existing messages on Provider.\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'obsolete.foo' => 'obsoleteFoo',\n        ], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load([\n            'note' => 'NOTE',\n            'obsolete.foo' => 'obsolèteFoo',\n        ], 'fr'));\n\n        $provider = $this->createMock(ProviderInterface::class);\n        $provider\n            ->method('read')\n            ->willReturnMap([\n                [$domains, $locales, $providerReadTranslatorBag],\n            ]);\n\n        // Create local bag, with a missing message, an updated one and a new one.\n        $localTranslatorBag = new TranslatorBag();\n        $localTranslatorBag->addCatalogue($xliffLoader->load($this->createFile(['note' => 'NOTE UPDATED', 'note2' => 'NOTE 2']), 'en'));\n        $localTranslatorBag->addCatalogue($xliffLoader->load($this->createFile(['note' => 'NOTE MISE À JOUR', 'note2' => 'NOTE 2'], 'fr'), 'fr'));\n\n        $missingTranslatorBag = $providerReadTranslatorBag->diff($localTranslatorBag);\n\n        $provider->expects($this->once())\n            ->method('delete')\n            ->with($missingTranslatorBag);\n\n        // Read provider translations again, after missing translations deletion,\n        // to avoid push freshly deleted translations.\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'fr'));\n\n        $provider\n            ->method('read')\n            ->willReturnMap([\n                [$domains, $locales, $providerReadTranslatorBag],\n            ]);\n\n        $translationBagToWrite = $localTranslatorBag->diff($providerReadTranslatorBag);\n        $translationBagToWrite->addBag($localTranslatorBag->intersect($providerReadTranslatorBag));\n\n        $provider->expects($this->once())\n            ->method('write')\n            ->with($translationBagToWrite);\n\n        $provider->expects($this->exactly(2))\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $tester = $this->createCommandTester($provider, $locales, $domains);\n\n        $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages'], '--force' => true, '--delete-missing' => true]);\n\n        $this->assertStringContainsString('[OK] Missing translations on \"null\" has been deleted (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n        $this->assertStringContainsString('[OK] All local translations has been sent to \"null\" (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n    }\n\n    public function testPushWithProviderDomains()\n    {\n        $arrayLoader = new ArrayLoader();\n        $xliffLoader = new XliffFileLoader();\n        $locales = ['en', 'fr'];\n        $domains = ['messages'];\n\n        // Simulate existing messages on Provider\n        $providerReadTranslatorBag = new TranslatorBag();\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'en'));\n        $providerReadTranslatorBag->addCatalogue($arrayLoader->load(['note' => 'NOTE'], 'fr'));\n\n        $provider = $this->createMock(FilteringProvider::class);\n        $provider->expects($this->once())\n            ->method('read')\n            ->with($domains, $locales)\n            ->willReturn($providerReadTranslatorBag);\n        $provider->expects($this->once())\n            ->method('getDomains')\n            ->willReturn(['messages']);\n\n        $filenameEn = $this->createFile([\n            'note' => 'NOTE',\n            'new.foo' => 'newFoo',\n        ]);\n        $filenameFr = $this->createFile([\n            'note' => 'NOTE',\n            'new.foo' => 'nouveauFoo',\n        ], 'fr');\n        $localTranslatorBag = new TranslatorBag();\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameEn, 'en'));\n        $localTranslatorBag->addCatalogue($xliffLoader->load($filenameFr, 'fr'));\n\n        $provider->expects($this->once())\n            ->method('write')\n            ->with($localTranslatorBag->diff($providerReadTranslatorBag));\n\n        $provider->expects($this->once())\n            ->method('__toString')\n            ->willReturn('null://default');\n\n        $reader = new TranslationReader();\n        $reader->addLoader('xlf', new XliffFileLoader());\n\n        $command = new TranslationPushCommand(\n            new TranslationProviderCollection([\n                'loco' => $provider,\n            ]),\n            $reader,\n            [$this->translationAppDir.'/translations'],\n            $locales\n        );\n\n        $application = new Application();\n        $application->addCommand($command);\n        $tester = new CommandTester($application->find('translation:push'));\n\n        $tester->execute(['--locales' => ['en', 'fr']]);\n\n        $this->assertStringContainsString('[OK] New local translations has been sent to \"null\" (for \"en, fr\" locale(s), and \"messages\" domain(s)).', trim($tester->getDisplay()));\n    }\n\n    #[DataProvider('provideCompletionSuggestions')]\n    public function testComplete(array $input, array $expectedSuggestions)\n    {\n        $application = new Application();\n        $application->addCommand($this->createCommand($this->createStub(ProviderInterface::class), ['en', 'fr', 'it'], ['messages', 'validators'], ['loco', 'crowdin', 'lokalise']));\n\n        $tester = new CommandCompletionTester($application->get('translation:push'));\n        $suggestions = $tester->complete($input);\n        $this->assertSame($expectedSuggestions, $suggestions);\n    }\n\n    public static function provideCompletionSuggestions(): \\Generator\n    {\n        yield 'provider' => [\n            [''],\n            ['loco', 'crowdin', 'lokalise'],\n        ];\n\n        yield '--domains' => [\n            ['loco', '--domains'],\n            ['messages', 'validators'],\n        ];\n\n        yield '--locales' => [\n            ['loco', '--locales'],\n            ['en', 'fr', 'it'],\n        ];\n    }\n\n    private function createCommandTester(ProviderInterface $provider, array $locales = ['en'], array $domains = ['messages']): CommandTester\n    {\n        $command = $this->createCommand($provider, $locales, $domains);\n        $application = new Application();\n        $application->addCommand($command);\n\n        return new CommandTester($application->find('translation:push'));\n    }\n\n    private function createCommand(ProviderInterface $provider, array $locales = ['en'], array $domains = ['messages'], array $providerNames = ['loco']): TranslationPushCommand\n    {\n        $reader = new TranslationReader();\n        $reader->addLoader('xlf', new XliffFileLoader());\n\n        return new TranslationPushCommand(\n            $this->getProviderCollection($provider, $providerNames, $locales, $domains),\n            $reader,\n            [$this->translationAppDir.'/translations'],\n            $locales\n        );\n    }\n}\n"
  },
  {
    "path": "Tests/Command/XliffLintCommandTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Command;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Tester\\CommandCompletionTester;\nuse Symfony\\Component\\Console\\Tester\\CommandTester;\nuse Symfony\\Component\\Translation\\Command\\XliffLintCommand;\n\n/**\n * Tests the XliffLintCommand.\n *\n * @author Javier Eguiluz <javier.eguiluz@gmail.com>\n */\nclass XliffLintCommandTest extends TestCase\n{\n    private array $files;\n\n    public function testLintCorrectFile()\n    {\n        $tester = $this->createCommandTester();\n        $filename = $this->createFile();\n\n        $tester->execute(\n            ['filename' => $filename],\n            ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]\n        );\n\n        $tester->assertCommandIsSuccessful('Returns 0 in case of success');\n        $this->assertStringContainsString('OK', trim($tester->getDisplay()));\n    }\n\n    public function testLintCorrectFiles()\n    {\n        $tester = $this->createCommandTester();\n        $filename1 = $this->createFile();\n        $filename2 = $this->createFile();\n\n        $tester->execute(\n            ['filename' => [$filename1, $filename2]],\n            ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]\n        );\n\n        $tester->assertCommandIsSuccessful('Returns 0 in case of success');\n        $this->assertStringContainsString('OK', trim($tester->getDisplay()));\n    }\n\n    #[DataProvider('provideStrictFilenames')]\n    public function testStrictFilenames($requireStrictFileNames, $fileNamePattern, $targetLanguage, $mustFail)\n    {\n        $tester = $this->createCommandTester($requireStrictFileNames);\n        $filename = $this->createFile('note', $targetLanguage, $fileNamePattern);\n\n        $tester->execute(\n            ['filename' => $filename],\n            ['verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false]\n        );\n\n        $this->assertEquals($mustFail ? 1 : 0, $tester->getStatusCode());\n        $this->assertStringContainsString($mustFail ? '[WARNING] 0 XLIFF files have valid syntax and 1 contain errors.' : '[OK] All 1 XLIFF files contain valid syntax.', $tester->getDisplay());\n    }\n\n    public function testLintIncorrectXmlSyntax()\n    {\n        $tester = $this->createCommandTester();\n        $filename = $this->createFile('note <target>');\n\n        $tester->execute(['filename' => $filename], ['decorated' => false]);\n\n        $this->assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error');\n        $this->assertStringContainsString('Opening and ending tag mismatch: target line 6 and source', trim($tester->getDisplay()));\n    }\n\n    public function testLintIncorrectTargetLanguage()\n    {\n        $tester = $this->createCommandTester();\n        $filename = $this->createFile('note', 'es');\n\n        $tester->execute(['filename' => $filename], ['decorated' => false]);\n\n        $this->assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error');\n        $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()));\n    }\n\n    public function testLintTargetLanguageIsCaseInsensitive()\n    {\n        $tester = $this->createCommandTester();\n        $filename = $this->createFile('note', 'zh-cn', 'messages.zh_CN.xlf');\n\n        $tester->execute(['filename' => $filename], ['decorated' => false]);\n\n        $tester->assertCommandIsSuccessful();\n        $this->assertStringContainsString('[OK] All 1 XLIFF files contain valid syntax.', trim($tester->getDisplay()));\n    }\n\n    public function testLintSucceedsWhenLocaleInFileAndInTargetLanguageNameUsesDashesInsteadOfUnderscores()\n    {\n        $tester = $this->createCommandTester();\n        $filename = $this->createFile('note', 'en-GB', 'messages.en-GB.xlf');\n\n        $tester->execute(['filename' => $filename], ['decorated' => false]);\n\n        $tester->assertCommandIsSuccessful();\n        $this->assertStringContainsString('[OK] All 1 XLIFF files contain valid syntax.', trim($tester->getDisplay()));\n    }\n\n    public function testLintFileNotReadable()\n    {\n        $tester = $this->createCommandTester();\n        $filename = $this->createFile();\n        unlink($filename);\n\n        $this->expectException(\\RuntimeException::class);\n\n        $tester->execute(['filename' => $filename], ['decorated' => false]);\n    }\n\n    public function testGetHelp()\n    {\n        $command = new XliffLintCommand();\n        $expected = <<<EOF\n            Or of a whole directory:\n\n              <info>php %command.full_name% dirname</info>\n\n            The <info>--format</info> option specifies the format of the command output:\n\n              <info>php %command.full_name% dirname --format=json</info>\n            EOF;\n\n        $this->assertStringContainsString($expected, $command->getHelp());\n    }\n\n    public function testLintIncorrectFileWithGithubFormat()\n    {\n        $filename = $this->createFile('note <target>');\n        $tester = $this->createCommandTester();\n        $tester->execute(['filename' => [$filename], '--format' => 'github'], ['decorated' => false]);\n        self::assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error');\n        self::assertStringMatchesFormat('%A::error file=%s,line=6,col=47::Opening and ending tag mismatch: target line 6 and source%A', trim($tester->getDisplay()));\n    }\n\n    public function testLintAutodetectsGithubActionEnvironment()\n    {\n        $prev = getenv('GITHUB_ACTIONS');\n        putenv('GITHUB_ACTIONS');\n\n        try {\n            putenv('GITHUB_ACTIONS=1');\n\n            $filename = $this->createFile('note <target>');\n            $tester = $this->createCommandTester();\n\n            $tester->execute(['filename' => [$filename]], ['decorated' => false]);\n            self::assertStringMatchesFormat('%A::error file=%s,line=6,col=47::Opening and ending tag mismatch: target line 6 and source%A', trim($tester->getDisplay()));\n        } finally {\n            putenv('GITHUB_ACTIONS'.($prev ? \"=$prev\" : ''));\n        }\n    }\n\n    public function testPassingClosureAndCallableToConstructor()\n    {\n        $command = new XliffLintCommand('translation:xliff:lint',\n            $this->testPassingClosureAndCallableToConstructor(...),\n            [$this, 'testPassingClosureAndCallableToConstructor']\n        );\n\n        self::assertInstanceOf(XliffLintCommand::class, $command);\n    }\n\n    private function createFile($sourceContent = 'note', $targetLanguage = 'en', $fileNamePattern = 'messages.%locale%.xlf'): string\n    {\n        $xliffContent = <<<XLIFF\n            <?xml version=\"1.0\"?>\n            <xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n                <file source-language=\"en\" target-language=\"$targetLanguage\" datatype=\"plaintext\" original=\"file.ext\">\n                    <body>\n                        <trans-unit id=\"note\">\n                            <source>$sourceContent</source>\n                            <target>NOTE</target>\n                        </trans-unit>\n                    </body>\n                </file>\n            </xliff>\n            XLIFF;\n\n        $filename = \\sprintf('%s/translation-xliff-lint-test/%s', sys_get_temp_dir(), str_replace('%locale%', 'en', $fileNamePattern));\n        file_put_contents($filename, $xliffContent);\n\n        $this->files[] = $filename;\n\n        return $filename;\n    }\n\n    private function createCommand($requireStrictFileNames = true, $application = null): Command\n    {\n        if (!$application) {\n            $application = new Application();\n            $application->addCommand(new XliffLintCommand(null, null, null, $requireStrictFileNames));\n        }\n\n        $command = $application->find('lint:xliff');\n\n        $command->setApplication($application);\n\n        return $command;\n    }\n\n    private function createCommandTester($requireStrictFileNames = true, $application = null): CommandTester\n    {\n        return new CommandTester($this->createCommand($requireStrictFileNames, $application));\n    }\n\n    protected function setUp(): void\n    {\n        $this->files = [];\n        @mkdir(sys_get_temp_dir().'/translation-xliff-lint-test');\n    }\n\n    protected function tearDown(): void\n    {\n        foreach ($this->files as $file) {\n            if (file_exists($file)) {\n                @unlink($file);\n            }\n        }\n        @rmdir(sys_get_temp_dir().'/translation-xliff-lint-test');\n    }\n\n    public static function provideStrictFilenames()\n    {\n        yield [false, 'messages.%locale%.xlf', 'en', false];\n        yield [false, 'messages.%locale%.xlf', 'es', true];\n        yield [false, '%locale%.messages.xlf', 'en', false];\n        yield [false, '%locale%.messages.xlf', 'es', true];\n        yield [true, 'messages.%locale%.xlf', 'en', false];\n        yield [true, 'messages.%locale%.xlf', 'es', true];\n        yield [true, '%locale%.messages.xlf', 'en', true];\n        yield [true, '%locale%.messages.xlf', 'es', true];\n    }\n\n    #[DataProvider('provideCompletionSuggestions')]\n    public function testComplete(array $input, array $expectedSuggestions)\n    {\n        $tester = new CommandCompletionTester($this->createCommand());\n\n        $this->assertSame($expectedSuggestions, $tester->complete($input));\n    }\n\n    public static function provideCompletionSuggestions()\n    {\n        yield 'option' => [['--format', ''], ['txt', 'json', 'github']];\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollector/TranslationDataCollectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DataCollector;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\Translation\\DataCollector\\TranslationDataCollector;\nuse Symfony\\Component\\Translation\\DataCollectorTranslator;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\Translator;\n\nclass TranslationDataCollectorTest extends TestCase\n{\n    public function testCollectEmptyMessages()\n    {\n        $dataCollector = new TranslationDataCollector(new DataCollectorTranslator(new Translator('en')));\n        $dataCollector->lateCollect();\n\n        $this->assertEquals(0, $dataCollector->getCountMissings());\n        $this->assertEquals(0, $dataCollector->getCountFallbacks());\n        $this->assertEquals(0, $dataCollector->getCountDefines());\n        $this->assertEquals([], $dataCollector->getMessages()->getValue());\n    }\n\n    public function testCollect()\n    {\n        $expectedMessages = [\n            [\n                'id' => 'foo',\n                'translation' => 'foo (en)',\n                'locale' => 'en',\n                'domain' => 'messages',\n                'state' => DataCollectorTranslator::MESSAGE_DEFINED,\n                'count' => 1,\n                'parameters' => [],\n                'transChoiceNumber' => null,\n                'fallbackLocale' => null,\n            ],\n            [\n                'id' => 'bar',\n                'translation' => 'bar (fr)',\n                'locale' => 'en',\n                'domain' => 'messages',\n                'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,\n                'count' => 1,\n                'parameters' => [],\n                'transChoiceNumber' => null,\n                'fallbackLocale' => 'fr',\n            ],\n            [\n                'id' => 'choice',\n                'translation' => 'choice',\n                'locale' => 'en',\n                'domain' => 'messages',\n                'state' => DataCollectorTranslator::MESSAGE_MISSING,\n                'count' => 3,\n                'parameters' => [\n                    ['%count%' => 3],\n                    ['%count%' => 3],\n                    ['%count%' => 4, '%foo%' => 'bar'],\n                ],\n                'transChoiceNumber' => 3,\n                'fallbackLocale' => null,\n            ],\n        ];\n\n        $translator = new Translator('en');\n        $translator->setFallbackLocales(['fr']);\n        $translator->addLoader('memory', new ArrayLoader());\n        $translator->addResource('memory', ['foo' => 'foo (en)'], 'en');\n        $translator->addResource('memory', ['bar' => 'bar (fr)'], 'fr');\n        $dataCollectorTranslator = new DataCollectorTranslator($translator);\n        $dataCollectorTranslator->trans('foo');\n        $dataCollectorTranslator->trans('bar');\n        $dataCollectorTranslator->trans('choice', ['%count%' => 3]);\n        $dataCollectorTranslator->trans('choice', ['%count%' => 3]);\n        $dataCollectorTranslator->trans('choice', ['%count%' => 4, '%foo%' => 'bar']);\n        $dataCollector = new TranslationDataCollector($dataCollectorTranslator);\n        $dataCollector->lateCollect();\n\n        $this->assertEquals(1, $dataCollector->getCountMissings());\n        $this->assertEquals(1, $dataCollector->getCountFallbacks());\n        $this->assertEquals(1, $dataCollector->getCountDefines());\n\n        $this->assertEquals($expectedMessages, array_values($dataCollector->getMessages()->getValue(true)));\n    }\n\n    public function testCollectAndReset()\n    {\n        $translator = new Translator('fr');\n        $translator->setFallbackLocales(['en']);\n        $translator->addGlobalParameter('welcome', 'Welcome {name}!');\n        $dataCollector = new TranslationDataCollector(new DataCollectorTranslator($translator));\n        $dataCollector->collect(new Request(), new Response());\n\n        $this->assertSame('fr', $dataCollector->getLocale());\n        $this->assertSame(['en'], $dataCollector->getFallbackLocales());\n        $this->assertSame(['welcome' => 'Welcome {name}!'], $dataCollector->getGlobalParameters());\n\n        $dataCollector->reset();\n\n        $this->assertNull($dataCollector->getLocale());\n        $this->assertSame([], $dataCollector->getFallbackLocales());\n        $this->assertSame([], $dataCollector->getGlobalParameters());\n    }\n}\n"
  },
  {
    "path": "Tests/DataCollectorTranslatorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\DataCollectorTranslator;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\TranslatableMessage;\nuse Symfony\\Component\\Translation\\Translator;\n\nclass DataCollectorTranslatorTest extends TestCase\n{\n    public function testCollectMessages()\n    {\n        $collector = $this->createCollector();\n        $collector->setFallbackLocales(['fr', 'ru']);\n\n        $collector->trans('foo');\n        $collector->trans('bar');\n        $collector->trans('choice', ['%count%' => 0]);\n        $collector->trans('bar_ru');\n        $collector->trans('bar_ru', ['foo' => 'bar']);\n\n        $expectedMessages = [];\n        $expectedMessages[] = [\n            'id' => 'foo',\n            'translation' => 'foo (en)',\n            'locale' => 'en',\n            'fallbackLocale' => null,\n            'domain' => 'messages',\n            'state' => DataCollectorTranslator::MESSAGE_DEFINED,\n            'parameters' => [],\n            'transChoiceNumber' => null,\n        ];\n        $expectedMessages[] = [\n            'id' => 'bar',\n            'translation' => 'bar (fr)',\n            'locale' => 'en',\n            'fallbackLocale' => 'fr',\n            'domain' => 'messages',\n            'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,\n            'parameters' => [],\n            'transChoiceNumber' => null,\n        ];\n        $expectedMessages[] = [\n            'id' => 'choice',\n            'translation' => 'choice',\n            'locale' => 'en',\n            'fallbackLocale' => null,\n            'domain' => 'messages',\n            'state' => DataCollectorTranslator::MESSAGE_MISSING,\n            'parameters' => ['%count%' => 0],\n            'transChoiceNumber' => 0,\n        ];\n        $expectedMessages[] = [\n            'id' => 'bar_ru',\n            'translation' => 'bar (ru)',\n            'locale' => 'en',\n            'fallbackLocale' => 'ru',\n            'domain' => 'messages',\n            'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,\n            'parameters' => [],\n            'transChoiceNumber' => null,\n        ];\n        $expectedMessages[] = [\n            'id' => 'bar_ru',\n            'translation' => 'bar (ru)',\n            'locale' => 'en',\n            'fallbackLocale' => 'ru',\n            'domain' => 'messages',\n            'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,\n            'parameters' => ['foo' => 'bar'],\n            'transChoiceNumber' => null,\n        ];\n\n        $this->assertEquals($expectedMessages, $collector->getCollectedMessages());\n    }\n\n    public function testGetGlobalParameters()\n    {\n        $translatable = new TranslatableMessage('url.front');\n\n        $translator = new Translator('en');\n        $translator->addGlobalParameter('app', 'My app');\n        $translator->addGlobalParameter('url', $translatable);\n        $collector = new DataCollectorTranslator($translator);\n\n        $this->assertEquals(['app' => 'My app', 'url' => $translatable], $collector->getGlobalParameters());\n    }\n\n    private function createCollector()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foo (en)'], 'en');\n        $translator->addResource('array', ['bar' => 'bar (fr)'], 'fr');\n        $translator->addResource('array', ['bar_ru' => 'bar (ru)'], 'ru');\n\n        return new DataCollectorTranslator($translator);\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/DataCollectorTranslatorPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\Translation\\DataCollector\\TranslationDataCollector;\nuse Symfony\\Component\\Translation\\DataCollectorTranslator;\nuse Symfony\\Component\\Translation\\DependencyInjection\\DataCollectorTranslatorPass;\nuse Symfony\\Component\\Translation\\Translator;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\nclass DataCollectorTranslatorPassTest extends TestCase\n{\n    private ContainerBuilder $container;\n    private DataCollectorTranslatorPass $dataCollectorTranslatorPass;\n\n    protected function setUp(): void\n    {\n        $this->container = new ContainerBuilder();\n        $this->dataCollectorTranslatorPass = new DataCollectorTranslatorPass();\n\n        $this->container->setParameter('translator_implementing_bag', Translator::class);\n        $this->container->setParameter('translator_not_implementing_bag', 'Symfony\\Bundle\\FrameworkBundle\\Tests\\DependencyInjection\\Compiler\\TranslatorWithoutTranslatorBag');\n\n        $this->container->register('translator.data_collector', DataCollectorTranslator::class)\n            ->setDecoratedService('translator')\n            ->setArguments([new Reference('translator.data_collector.inner')])\n        ;\n\n        $this->container->register('data_collector.translation', TranslationDataCollector::class)\n            ->setArguments([new Reference('translator.data_collector')])\n        ;\n    }\n\n    #[DataProvider('getImplementingTranslatorBagInterfaceTranslatorClassNames')]\n    public function testProcessKeepsDataCollectorTranslatorIfItImplementsTranslatorBagInterface($class)\n    {\n        $this->container->register('translator', $class);\n\n        $this->dataCollectorTranslatorPass->process($this->container);\n\n        $this->assertTrue($this->container->hasDefinition('translator.data_collector'));\n    }\n\n    #[DataProvider('getImplementingTranslatorBagInterfaceTranslatorClassNames')]\n    public function testProcessKeepsDataCollectorIfTranslatorImplementsTranslatorBagInterface($class)\n    {\n        $this->container->register('translator', $class);\n\n        $this->dataCollectorTranslatorPass->process($this->container);\n\n        $this->assertTrue($this->container->hasDefinition('data_collector.translation'));\n    }\n\n    public static function getImplementingTranslatorBagInterfaceTranslatorClassNames()\n    {\n        return [\n            [Translator::class],\n            ['%translator_implementing_bag%'],\n        ];\n    }\n\n    #[DataProvider('getNotImplementingTranslatorBagInterfaceTranslatorClassNames')]\n    public function testProcessRemovesDataCollectorTranslatorIfItDoesNotImplementTranslatorBagInterface($class)\n    {\n        $this->container->register('translator', $class);\n\n        $this->dataCollectorTranslatorPass->process($this->container);\n\n        $this->assertFalse($this->container->hasDefinition('translator.data_collector'));\n    }\n\n    #[DataProvider('getNotImplementingTranslatorBagInterfaceTranslatorClassNames')]\n    public function testProcessRemovesDataCollectorIfTranslatorDoesNotImplementTranslatorBagInterface($class)\n    {\n        $this->container->register('translator', $class);\n\n        $this->dataCollectorTranslatorPass->process($this->container);\n\n        $this->assertFalse($this->container->hasDefinition('data_collector.translation'));\n    }\n\n    public static function getNotImplementingTranslatorBagInterfaceTranslatorClassNames()\n    {\n        return [\n            ['Symfony\\Bundle\\FrameworkBundle\\Tests\\DependencyInjection\\Compiler\\TranslatorWithoutTranslatorBag'],\n            ['%translator_not_implementing_bag%'],\n        ];\n    }\n}\n\nclass TranslatorWithoutTranslatorBag implements TranslatorInterface\n{\n    public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string\n    {\n    }\n\n    public function getLocale(): string\n    {\n        return 'en';\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/Fixtures/ControllerArguments.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures;\n\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\nclass ControllerArguments\n{\n    public function __invoke(TranslatorInterface $translator)\n    {\n    }\n\n    public function index(TranslatorInterface $translator)\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/Fixtures/ServiceArguments.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures;\n\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\nclass ServiceArguments\n{\n    public function __construct(TranslatorInterface $translator)\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/Fixtures/ServiceMethodCalls.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures;\n\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\nclass ServiceMethodCalls\n{\n    public function setTranslator(TranslatorInterface $translator)\n    {\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/Fixtures/ServiceProperties.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures;\n\nclass ServiceProperties\n{\n    public $translator;\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/Fixtures/ServiceSubscriber.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Contracts\\Service\\ServiceSubscriberInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\nclass ServiceSubscriber implements ServiceSubscriberInterface\n{\n    public function __construct(ContainerInterface $container)\n    {\n    }\n\n    public static function getSubscribedServices(): array\n    {\n        return ['translator' => TranslatorInterface::class];\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/LoggingTranslatorPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\Translation\\DependencyInjection\\LoggingTranslatorPass;\nuse Symfony\\Component\\Translation\\Translator;\n\nclass LoggingTranslatorPassTest extends TestCase\n{\n    public function testProcess()\n    {\n        $container = new ContainerBuilder();\n        $container->setParameter('translator.logging', true);\n        $container->setParameter('translator.class', Translator::class);\n        $container->register('monolog.logger');\n        $container->setAlias('logger', 'monolog.logger');\n        $container->register('translator.default', '%translator.class%');\n        $container->register('translator.logging', '%translator.class%');\n        $container->setAlias('translator', 'translator.default');\n        $translationWarmerDefinition = $container->register('translation.warmer')\n            ->addArgument(new Reference('translator'))\n            ->addTag('container.service_subscriber', ['id' => 'translator'])\n            ->addTag('container.service_subscriber', ['id' => 'foo']);\n\n        $pass = new LoggingTranslatorPass();\n        $pass->process($container);\n\n        $this->assertEquals(\n            ['container.service_subscriber' => [\n                ['id' => 'foo'],\n                ['key' => 'translator', 'id' => 'translator.logging.inner'],\n            ]],\n            $translationWarmerDefinition->getTags()\n        );\n    }\n\n    public function testThatCompilerPassIsIgnoredIfThereIsNotLoggerDefinition()\n    {\n        $container = new ContainerBuilder();\n        $container->register('identity_translator');\n        $container->setAlias('translator', 'identity_translator');\n\n        $definitionsBefore = \\count($container->getDefinitions());\n        $aliasesBefore = \\count($container->getAliases());\n\n        $pass = new LoggingTranslatorPass();\n        $pass->process($container);\n\n        // the container is untouched (i.e. no new definitions or aliases)\n        $this->assertCount($definitionsBefore, $container->getDefinitions());\n        $this->assertCount($aliasesBefore, $container->getAliases());\n    }\n\n    public function testThatCompilerPassIsIgnoredIfThereIsNotTranslatorDefinition()\n    {\n        $container = new ContainerBuilder();\n        $container->register('monolog.logger');\n        $container->setAlias('logger', 'monolog.logger');\n\n        $definitionsBefore = \\count($container->getDefinitions());\n        $aliasesBefore = \\count($container->getAliases());\n\n        $pass = new LoggingTranslatorPass();\n        $pass->process($container);\n\n        // the container is untouched (i.e. no new definitions or aliases)\n        $this->assertCount($definitionsBefore, $container->getDefinitions());\n        $this->assertCount($aliasesBefore, $container->getAliases());\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/TranslationDumperPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\Translation\\DependencyInjection\\TranslationDumperPass;\n\nclass TranslationDumperPassTest extends TestCase\n{\n    public function testProcess()\n    {\n        $container = new ContainerBuilder();\n        $writerDefinition = $container->register('translation.writer');\n        $container->register('foo.id')\n            ->addTag('translation.dumper', ['alias' => 'bar.alias']);\n\n        $translationDumperPass = new TranslationDumperPass();\n        $translationDumperPass->process($container);\n\n        $this->assertEquals([['addDumper', ['bar.alias', new Reference('foo.id')]]], $writerDefinition->getMethodCalls());\n    }\n\n    public function testProcessNoDefinitionFound()\n    {\n        $container = new ContainerBuilder();\n\n        $definitionsBefore = \\count($container->getDefinitions());\n        $aliasesBefore = \\count($container->getAliases());\n\n        $translationDumperPass = new TranslationDumperPass();\n        $translationDumperPass->process($container);\n\n        // the container is untouched (i.e. no new definitions or aliases)\n        $this->assertCount($definitionsBefore, $container->getDefinitions());\n        $this->assertCount($aliasesBefore, $container->getAliases());\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/TranslationExtractorPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\Translation\\DependencyInjection\\TranslationExtractorPass;\n\nclass TranslationExtractorPassTest extends TestCase\n{\n    public function testProcess()\n    {\n        $container = new ContainerBuilder();\n        $extractorDefinition = $container->register('translation.extractor');\n        $container->register('foo.id')\n            ->addTag('translation.extractor', ['alias' => 'bar.alias']);\n\n        $translationDumperPass = new TranslationExtractorPass();\n        $translationDumperPass->process($container);\n\n        $this->assertEquals([['addExtractor', ['bar.alias', new Reference('foo.id')]]], $extractorDefinition->getMethodCalls());\n    }\n\n    public function testProcessNoDefinitionFound()\n    {\n        $container = new ContainerBuilder();\n\n        $definitionsBefore = \\count($container->getDefinitions());\n        $aliasesBefore = \\count($container->getAliases());\n\n        $translationDumperPass = new TranslationExtractorPass();\n        $translationDumperPass->process($container);\n\n        // the container is untouched (i.e. no new definitions or aliases)\n        $this->assertCount($definitionsBefore, $container->getDefinitions());\n        $this->assertCount($aliasesBefore, $container->getAliases());\n    }\n\n    public function testProcessMissingAlias()\n    {\n        $container = new ContainerBuilder();\n        $extractorDefinition = $container->register('translation.extractor');\n        $container->register('foo.id')\n            ->addTag('translation.extractor', []);\n\n        $translationDumperPass = new TranslationExtractorPass();\n        $translationDumperPass->process($container);\n\n        $this->assertEquals([['addExtractor', ['foo.id', new Reference('foo.id')]]], $extractorDefinition->getMethodCalls());\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/TranslationPathsPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Argument\\ServiceClosureArgument;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Definition;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\DependencyInjection\\ServiceLocator;\nuse Symfony\\Component\\Translation\\DependencyInjection\\TranslatorPathsPass;\nuse Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures\\ControllerArguments;\nuse Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures\\ServiceArguments;\nuse Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures\\ServiceMethodCalls;\nuse Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures\\ServiceProperties;\nuse Symfony\\Component\\Translation\\Tests\\DependencyInjection\\Fixtures\\ServiceSubscriber;\n\nclass TranslationPathsPassTest extends TestCase\n{\n    public function testProcess()\n    {\n        $container = new ContainerBuilder();\n        $container->register('translator');\n        $debugCommand = $container->register('console.command.translation_debug')\n            ->setArguments([null, null, null, null, null, [], []])\n        ;\n        $updateCommand = $container->register('console.command.translation_extract')\n            ->setArguments([null, null, null, null, null, null, [], []])\n        ;\n        $container->register(ControllerArguments::class, ControllerArguments::class)\n            ->setTags(['controller.service_arguments'])\n        ;\n        $container->register(ServiceArguments::class, ServiceArguments::class)\n            ->setArguments([new Reference('translator')])\n        ;\n        $container->register(ServiceProperties::class, ServiceProperties::class)\n            ->setProperties([new Reference('translator')])\n        ;\n        $container->register(ServiceMethodCalls::class, ServiceMethodCalls::class)\n            ->setMethodCalls([['setTranslator', [new Reference('translator')]]])\n        ;\n        $container->register('service_rc')\n            ->setArguments([new Definition(), new Reference(ServiceMethodCalls::class)])\n        ;\n        $serviceLocator1 = $container->register('.service_locator.foo', ServiceLocator::class)\n            ->setArguments([new ServiceClosureArgument(new Reference('translator'))])\n        ;\n        $serviceLocator2 = (new Definition(ServiceLocator::class))\n            ->setArguments([ServiceSubscriber::class, new Reference('service_container')])\n            ->setFactory([$serviceLocator1, 'withContext'])\n        ;\n        $container->register('service_subscriber', ServiceSubscriber::class)\n            ->setArguments([$serviceLocator2])\n        ;\n        $container->register('.service_locator.bar', ServiceLocator::class)\n            ->setArguments([[\n                ControllerArguments::class.'::index' => new ServiceClosureArgument(new Reference('.service_locator.foo')),\n                ControllerArguments::class.'::__invoke' => new ServiceClosureArgument(new Reference('.service_locator.foo')),\n                ControllerArguments::class => new ServiceClosureArgument(new Reference('.service_locator.foo')),\n            ]])\n        ;\n        $container->register('argument_resolver.service')\n            ->setArguments([new Reference('.service_locator.bar')])\n        ;\n\n        $pass = new TranslatorPathsPass();\n        $pass->process($container);\n\n        $expectedPaths = [\n            $container->getReflectionClass(ServiceArguments::class)->getFileName(),\n            $container->getReflectionClass(ServiceProperties::class)->getFileName(),\n            $container->getReflectionClass(ServiceMethodCalls::class)->getFileName(),\n            $container->getReflectionClass(ControllerArguments::class)->getFileName(),\n            $container->getReflectionClass(ServiceSubscriber::class)->getFileName(),\n        ];\n\n        $this->assertSame($expectedPaths, $debugCommand->getArgument(6));\n        $this->assertSame($expectedPaths, $updateCommand->getArgument(7));\n    }\n}\n"
  },
  {
    "path": "Tests/DependencyInjection/TranslatorPassTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\DependencyInjection;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\DependencyInjection\\Argument\\ServiceClosureArgument;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Definition;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\Translation\\DependencyInjection\\TranslatorPass;\nuse Symfony\\Component\\Translation\\Extractor\\Visitor\\ConstraintVisitor;\nuse Symfony\\Component\\Validator\\Constraints\\IsbnValidator;\nuse Symfony\\Component\\Validator\\Constraints\\LengthValidator;\nuse Symfony\\Component\\Validator\\Constraints\\NotBlankValidator;\nuse Symfony\\Component\\Validator\\Constraints\\TimeValidator;\n\nclass TranslatorPassTest extends TestCase\n{\n    public function testValidCollector()\n    {\n        $loader = (new Definition())\n            ->addTag('translation.loader', ['alias' => 'xliff', 'legacy-alias' => 'xlf']);\n\n        $reader = new Definition();\n\n        $translator = (new Definition())\n            ->setArguments([null, null, null, null]);\n\n        $container = new ContainerBuilder();\n        $container->setDefinition('translator.default', $translator);\n        $container->setDefinition('translation.reader', $reader);\n        $container->setDefinition('translation.xliff_loader', $loader);\n\n        $pass = new TranslatorPass();\n        $pass->process($container);\n\n        $expectedReader = (new Definition())\n            ->addMethodCall('addLoader', ['xliff', new Reference('translation.xliff_loader')])\n            ->addMethodCall('addLoader', ['xlf', new Reference('translation.xliff_loader')])\n        ;\n        $this->assertEquals($expectedReader, $reader);\n\n        $expectedLoader = (new Definition())\n            ->addTag('translation.loader', ['alias' => 'xliff', 'legacy-alias' => 'xlf'])\n        ;\n        $this->assertEquals($expectedLoader, $loader);\n\n        $this->assertSame(['translation.xliff_loader' => ['xliff', 'xlf']], $translator->getArgument(3));\n\n        $expected = ['translation.xliff_loader' => new ServiceClosureArgument(new Reference('translation.xliff_loader'))];\n        $this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));\n    }\n\n    public function testValidCommandsViewPathsArgument()\n    {\n        $container = new ContainerBuilder();\n        $container->register('translator.default')\n            ->setArguments([null, null, null, null])\n        ;\n        $debugCommand = $container->register('console.command.translation_debug')\n            ->setArguments([null, null, null, null, null, [], []])\n        ;\n        $updateCommand = $container->register('console.command.translation_extract')\n            ->setArguments([null, null, null, null, null, null, [], []])\n        ;\n        $container->register('twig.template_iterator')\n            ->setArguments([null, ['other/templates' => null, 'tpl' => 'App']])\n        ;\n        $container->setParameter('twig.default_path', 'templates');\n\n        $pass = new TranslatorPass();\n        $pass->process($container);\n\n        $expectedViewPaths = ['other/templates', 'tpl'];\n\n        $this->assertSame('templates', $debugCommand->getArgument(4));\n        $this->assertSame('templates', $updateCommand->getArgument(5));\n        $this->assertSame($expectedViewPaths, $debugCommand->getArgument(6));\n        $this->assertSame($expectedViewPaths, $updateCommand->getArgument(7));\n    }\n\n    public function testCommandsViewPathsArgumentsAreIgnoredWithOldServiceDefinitions()\n    {\n        $container = new ContainerBuilder();\n        $container->register('translator.default')\n            ->setArguments([null, null, null, null])\n        ;\n        $debugCommand = $container->register('console.command.translation_debug')\n            ->setArguments([\n                new Reference('translator'),\n                new Reference('translation.reader'),\n                new Reference('translation.extractor'),\n                '%translator.default_path%',\n                null,\n            ])\n        ;\n        $updateCommand = $container->register('console.command.translation_extract')\n            ->setArguments([\n                new Reference('translation.writer'),\n                new Reference('translation.reader'),\n                new Reference('translation.extractor'),\n                '%kernel.default_locale%',\n                '%translator.default_path%',\n                null,\n            ])\n        ;\n        $container->register('twig.template_iterator')\n            ->setArguments([null, ['other/templates' => null, 'tpl' => 'App']])\n        ;\n        $container->setParameter('twig.default_path', 'templates');\n\n        $pass = new TranslatorPass();\n        $pass->process($container);\n\n        $this->assertSame('templates', $debugCommand->getArgument(4));\n        $this->assertSame('templates', $updateCommand->getArgument(5));\n    }\n\n    public function testValidPhpAstExtractorConstraintVisitorArguments()\n    {\n        $container = new ContainerBuilder();\n        $container->register('translator.default')\n            ->setArguments([null, null, null, null]);\n        $container->register('validator');\n        $constraintVisitor = $container->register('translation.extractor.visitor.constraint', ConstraintVisitor::class);\n        $container->register('validator.not_blank', NotBlankValidator::class)\n            ->addTag('validator.constraint_validator');\n        $container->register('validator.isbn', IsbnValidator::class)\n            ->addTag('validator.constraint_validator');\n        $container->register('validator.length', LengthValidator::class)\n            ->addTag('validator.constraint_validator');\n        $container->register('validator.time', '%foo.time.validator.class%')\n            ->addTag('validator.constraint_validator');\n        $container->setParameter('foo.time.validator.class', TimeValidator::class);\n\n        $pass = new TranslatorPass();\n        $pass->process($container);\n\n        $this->assertSame(['NotBlank', 'Isbn', 'Length', 'Time'], $constraintVisitor->getArgument(0));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/CsvFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\CsvFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass CsvFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar', 'bar' => 'foo\nfoo', 'foo;foo' => 'bar']);\n\n        $dumper = new CsvFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/valid.csv', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/FileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\FileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass FileDumperTest extends TestCase\n{\n    public function testDump()\n    {\n        $tempDir = sys_get_temp_dir();\n\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar']);\n\n        $dumper = new ConcreteFileDumper();\n        $dumper->dump($catalogue, ['path' => $tempDir]);\n\n        $this->assertFileExists($tempDir.'/messages.en.concrete');\n\n        @unlink($tempDir.'/messages.en.concrete');\n    }\n\n    public function testDumpIntl()\n    {\n        $tempDir = sys_get_temp_dir();\n\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar'], 'd1');\n        $catalogue->add(['bar' => 'foo'], 'd1+intl-icu');\n        $catalogue->add(['bar' => 'foo'], 'd2+intl-icu');\n\n        $dumper = new ConcreteFileDumper();\n        @unlink($tempDir.'/d2.en.concrete');\n        $dumper->dump($catalogue, ['path' => $tempDir]);\n\n        $this->assertStringEqualsFile($tempDir.'/d1.en.concrete', 'foo=bar');\n        @unlink($tempDir.'/d1.en.concrete');\n\n        $this->assertStringEqualsFile($tempDir.'/d1+intl-icu.en.concrete', 'bar=foo');\n        @unlink($tempDir.'/d1+intl-icu.en.concrete');\n\n        $this->assertFileDoesNotExist($tempDir.'/d2.en.concrete');\n        $this->assertStringEqualsFile($tempDir.'/d2+intl-icu.en.concrete', 'bar=foo');\n        @unlink($tempDir.'/d2+intl-icu.en.concrete');\n    }\n\n    public function testDumpCreatesNestedDirectoriesAndFile()\n    {\n        $tempDir = sys_get_temp_dir();\n        $translationsDir = $tempDir.'/test/translations';\n        $file = $translationsDir.'/messages.en.concrete';\n\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar']);\n\n        $dumper = new ConcreteFileDumper();\n        $dumper->setRelativePathTemplate('test/translations/%domain%.%locale%.%extension%');\n        $dumper->dump($catalogue, ['path' => $tempDir]);\n\n        $this->assertFileExists($file);\n\n        @unlink($file);\n        @rmdir($translationsDir);\n    }\n}\n\nclass ConcreteFileDumper extends FileDumper\n{\n    public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = []): string\n    {\n        return http_build_query($messages->all($domain), '', '&');\n    }\n\n    protected function getExtension(): string\n    {\n        return 'concrete';\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/IcuResFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\IcuResFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass IcuResFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar']);\n\n        $dumper = new IcuResFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/resourcebundle/res/en.res', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/IniFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\IniFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass IniFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar']);\n\n        $dumper = new IniFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/resources.ini', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/JsonFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\JsonFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass JsonFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar']);\n\n        $dumper = new JsonFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/resources.json', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n\n    public function testDumpWithCustomEncoding()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => '\"bar\"']);\n\n        $dumper = new JsonFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/resources.dump.json', $dumper->formatCatalogue($catalogue, 'messages', ['json_encoding' => \\JSON_HEX_QUOT]));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/MoFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\MoFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass MoFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar']);\n\n        $dumper = new MoFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/resources.mo', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/PhpFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\PhpFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass PhpFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar']);\n\n        $dumper = new PhpFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/resources.php', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/PoFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\PoFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass PoFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar', 'bar' => 'foo', 'foo_bar' => 'foobar', 'bar_foo' => 'barfoo']);\n        $catalogue->setMetadata('foo_bar', [\n            'comments' => [\n                'Comment 1',\n                'Comment 2',\n            ],\n            'flags' => [\n                'fuzzy',\n                'another',\n            ],\n            'sources' => [\n                'src/file_1',\n                'src/file_2:50',\n            ],\n        ]);\n        $catalogue->setMetadata('bar_foo', [\n            'comments' => 'Comment',\n            'flags' => 'fuzzy',\n            'sources' => 'src/file_1',\n        ]);\n\n        $dumper = new PoFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/resources.po', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n\n    public function testDumpPlurals()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add([\n            'foo|foos' => 'bar|bars',\n            '{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',\n        ]);\n\n        $dumper = new PoFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/plurals.po', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/QtFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\QtFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass QtFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add(['foo' => 'bar', 'foo_bar' => 'foobar', 'bar_foo' => 'barfoo'], 'resources');\n        $catalogue->setMetadata('foo_bar', [\n            'comments' => [\n                'Comment 1',\n                'Comment 2',\n            ],\n            'flags' => [\n                'fuzzy',\n                'another',\n            ],\n            'sources' => [\n                'src/file_1',\n                'src/file_2:50',\n            ],\n        ], 'resources');\n        $catalogue->setMetadata('bar_foo', [\n            'comments' => 'Comment',\n            'flags' => 'fuzzy',\n            'sources' => 'src/file_1',\n        ], 'resources');\n\n        $dumper = new QtFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/resources.ts', $dumper->formatCatalogue($catalogue, 'resources'));\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/XliffFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\XliffFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass XliffFileDumperTest extends TestCase\n{\n    public function testFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add([\n            'foo' => 'bar',\n            'key' => '',\n            'key.with.cdata' => '<source> & <target>',\n        ]);\n        $catalogue->setMetadata('foo', ['notes' => [['priority' => 1, 'from' => 'bar', 'content' => 'baz']]]);\n        $catalogue->setMetadata('key', ['notes' => [['content' => 'baz'], ['content' => 'qux']]]);\n\n        $dumper = new XliffFileDumper();\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-clean.xlf',\n            $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR'])\n        );\n    }\n\n    public function testFormatCatalogueXliff2()\n    {\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add([\n            'foo' => 'bar',\n            'key' => '',\n            'key.with.cdata' => '<source> & <target>',\n            'translation.key.that.is.longer.than.eighty.characters.should.not.have.name.attribute' => 'value',\n        ]);\n        $catalogue->setMetadata('key', ['target-attributes' => ['order' => 1]]);\n\n        $dumper = new XliffFileDumper();\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-2.0-clean.xlf',\n            $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR', 'xliff_version' => '2.0'])\n        );\n    }\n\n    public function testFormatIcuCatalogueXliff2()\n    {\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add([\n            'foo' => 'bar',\n        ], 'messages'.MessageCatalogue::INTL_DOMAIN_SUFFIX);\n\n        $dumper = new XliffFileDumper();\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-2.0+intl-icu.xlf',\n            $dumper->formatCatalogue($catalogue, 'messages'.MessageCatalogue::INTL_DOMAIN_SUFFIX, ['default_locale' => 'fr_FR', 'xliff_version' => '2.0'])\n        );\n    }\n\n    public function testFormatCatalogueWithCustomToolInfo()\n    {\n        $options = [\n            'default_locale' => 'en_US',\n            'tool_info' => ['tool-id' => 'foo', 'tool-name' => 'foo', 'tool-version' => '0.0', 'tool-company' => 'Foo'],\n        ];\n\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add(['foo' => 'bar']);\n\n        $dumper = new XliffFileDumper();\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-tool-info.xlf',\n            $dumper->formatCatalogue($catalogue, 'messages', $options)\n        );\n    }\n\n    public function testFormatCatalogueWithTargetAttributesMetadata()\n    {\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add([\n            'foo' => 'bar',\n        ]);\n        $catalogue->setMetadata('foo', ['target-attributes' => ['state' => 'needs-translation']]);\n\n        $dumper = new XliffFileDumper();\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-target-attributes.xlf',\n            $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR'])\n        );\n    }\n\n    public function testFormatCatalogueWithNotesMetadata()\n    {\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add([\n            'foo' => 'bar',\n            'baz' => 'biz',\n        ]);\n        $catalogue->setMetadata('foo', ['notes' => [\n            ['category' => 'state', 'content' => 'new'],\n            ['category' => 'approved', 'content' => 'true'],\n            ['category' => 'section', 'content' => 'user login', 'priority' => '1'],\n        ]]);\n        $catalogue->setMetadata('baz', ['notes' => [\n            ['id' => 'x', 'content' => 'x_content'],\n            ['appliesTo' => 'target', 'category' => 'quality', 'content' => 'Fuzzy'],\n        ]]);\n\n        $dumper = new XliffFileDumper();\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-notes-meta.xlf',\n            $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR', 'xliff_version' => '2.0'])\n        );\n    }\n\n    public function testDumpCatalogueWithXliffExtension()\n    {\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add([\n            'foo' => 'bar',\n            'key' => '',\n            'key.with.cdata' => '<source> & <target>',\n        ]);\n        $catalogue->setMetadata('foo', ['notes' => [['priority' => 1, 'from' => 'bar', 'content' => 'baz']]]);\n        $catalogue->setMetadata('key', ['notes' => [['content' => 'baz'], ['content' => 'qux']]]);\n\n        $dumper = new XliffFileDumper('xliff');\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-clean.xliff',\n            $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR'])\n        );\n    }\n\n    public function testEmptyMetadataNotes()\n    {\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add([\n            'empty' => 'notes',\n            'full' => 'notes',\n        ]);\n        $catalogue->setMetadata('empty', ['notes' => []]);\n        $catalogue->setMetadata('full', ['notes' => [['category' => 'file-source', 'priority' => 1, 'content' => 'test/path/to/translation/Example.1.html.twig:27']]]);\n\n        $dumper = new XliffFileDumper();\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-2.0-empty-notes.xlf',\n            $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR', 'xliff_version' => '2.0'])\n        );\n    }\n\n    public function testFormatCatalogueXliff2WithSegmentAttributes()\n    {\n        $catalogue = new MessageCatalogue('en_US');\n        $catalogue->add([\n            'foo' => 'bar',\n            'key' => '',\n        ]);\n        $catalogue->setMetadata('foo', ['segment-attributes' => ['state' => 'translated']]);\n        $catalogue->setMetadata('key', ['segment-attributes' => ['state' => 'translated', 'subState' => 'My Value']]);\n\n        $dumper = new XliffFileDumper();\n\n        $this->assertStringEqualsFile(\n            __DIR__.'/../Fixtures/resources-2.0-segment-attributes.xlf',\n            $dumper->formatCatalogue($catalogue, 'messages', ['default_locale' => 'fr_FR', 'xliff_version' => '2.0'])\n        );\n    }\n}\n"
  },
  {
    "path": "Tests/Dumper/YamlFileDumperTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Dumper;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\YamlFileDumper;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass YamlFileDumperTest extends TestCase\n{\n    public function testTreeFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add([\n            'foo.bar1' => 'value1',\n            'foo.bar2' => 'value2',\n        ]);\n\n        $dumper = new YamlFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/messages.yml', $dumper->formatCatalogue($catalogue, 'messages', ['as_tree' => true, 'inline' => 999]));\n    }\n\n    public function testLinearFormatCatalogue()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->add([\n            'foo.bar1' => 'value1',\n            'foo.bar2' => 'value2',\n        ]);\n\n        $dumper = new YamlFileDumper();\n\n        $this->assertStringEqualsFile(__DIR__.'/../Fixtures/messages_linear.yml', $dumper->formatCatalogue($catalogue, 'messages'));\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/ProviderExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Exception\\ProviderException;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\nclass ProviderExceptionTest extends TestCase\n{\n    public function testExceptionWithDebugMessage()\n    {\n        $mock = $this->createStub(ResponseInterface::class);\n        $mock->method('getInfo')->willReturn('debug');\n\n        $exception = new ProviderException('Exception message', $mock, 503);\n        $this->assertSame('debug', $exception->getDebug());\n    }\n\n    public function testExceptionWithNullAsDebugMessage()\n    {\n        $mock = $this->createStub(ResponseInterface::class);\n        $mock->method('getInfo')->willReturn(null);\n\n        $exception = new ProviderException('Exception message', $mock, 503);\n        $this->assertSame('', $exception->getDebug());\n    }\n}\n"
  },
  {
    "path": "Tests/Exception/UnsupportedSchemeExceptionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\RunTestsInSeparateProcesses;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Bridge\\PhpUnit\\ClassExistsMock;\nuse Symfony\\Component\\Translation\\Bridge\\Crowdin\\CrowdinProviderFactory;\nuse Symfony\\Component\\Translation\\Bridge\\Loco\\LocoProviderFactory;\nuse Symfony\\Component\\Translation\\Bridge\\Lokalise\\LokaliseProviderFactory;\nuse Symfony\\Component\\Translation\\Bridge\\Phrase\\PhraseProviderFactory;\nuse Symfony\\Component\\Translation\\Exception\\UnsupportedSchemeException;\nuse Symfony\\Component\\Translation\\Provider\\Dsn;\n\n#[RunTestsInSeparateProcesses]\nfinal class UnsupportedSchemeExceptionTest extends TestCase\n{\n    public static function setUpBeforeClass(): void\n    {\n        ClassExistsMock::register(__CLASS__);\n        ClassExistsMock::withMockedClasses([\n            CrowdinProviderFactory::class => false,\n            LocoProviderFactory::class => false,\n            LokaliseProviderFactory::class => false,\n            PhraseProviderFactory::class => false,\n        ]);\n    }\n\n    #[DataProvider('messageWhereSchemeIsPartOfSchemeToPackageMapProvider')]\n    public function testMessageWhereSchemeIsPartOfSchemeToPackageMap(string $scheme, string $package)\n    {\n        $dsn = new Dsn(\\sprintf('%s://localhost', $scheme));\n\n        $this->assertSame(\n            \\sprintf('Unable to synchronize translations via \"%s\" as the provider is not installed. Try running \"composer require %s\".', $scheme, $package),\n            (new UnsupportedSchemeException($dsn))->getMessage()\n        );\n    }\n\n    public static function messageWhereSchemeIsPartOfSchemeToPackageMapProvider(): \\Generator\n    {\n        yield ['crowdin', 'symfony/crowdin-translation-provider'];\n        yield ['loco', 'symfony/loco-translation-provider'];\n        yield ['lokalise', 'symfony/lokalise-translation-provider'];\n        yield ['phrase', 'symfony/phrase-translation-provider'];\n    }\n\n    #[DataProvider('messageWhereSchemeIsNotPartOfSchemeToPackageMapProvider')]\n    public function testMessageWhereSchemeIsNotPartOfSchemeToPackageMap(string $expected, Dsn $dsn, ?string $name, array $supported)\n    {\n        $this->assertSame(\n            $expected,\n            (new UnsupportedSchemeException($dsn, $name, $supported))->getMessage()\n        );\n    }\n\n    public static function messageWhereSchemeIsNotPartOfSchemeToPackageMapProvider(): \\Generator\n    {\n        yield [\n            'The \"somethingElse\" scheme is not supported.',\n            new Dsn('somethingElse://localhost'),\n            null,\n            [],\n        ];\n\n        yield [\n            'The \"somethingElse\" scheme is not supported.',\n            new Dsn('somethingElse://localhost'),\n            'foo',\n            [],\n        ];\n\n        yield [\n            'The \"somethingElse\" scheme is not supported; supported schemes for translation provider \"one\" are: \"one\", \"two\".',\n            new Dsn('somethingElse://localhost'),\n            'one',\n            ['one', 'two'],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/Extractor/PhpAstExtractorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Extractor;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Extractor\\PhpAstExtractor;\nuse Symfony\\Component\\Translation\\Extractor\\Visitor\\ConstraintVisitor;\nuse Symfony\\Component\\Translation\\Extractor\\Visitor\\TranslatableMessageVisitor;\nuse Symfony\\Component\\Translation\\Extractor\\Visitor\\TransMethodVisitor;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nfinal class PhpAstExtractorTest extends TestCase\n{\n    public const OTHER_DOMAIN = 'not_messages';\n\n    #[DataProvider('resourcesProvider')]\n    public function testExtraction(iterable|string $resource)\n    {\n        $extractor = new PhpAstExtractor([\n            new TransMethodVisitor(),\n            new TranslatableMessageVisitor(),\n            new ConstraintVisitor([\n                'NotBlank',\n                'Isbn',\n                'Length',\n            ], new TranslatableMessageVisitor()),\n        ]);\n        $extractor->setPrefix('prefix');\n        $catalogue = new MessageCatalogue('en');\n\n        $extractor->extract($resource, $catalogue);\n\n        $expectedHeredoc = <<<EOF\n            heredoc key with whitespace and escaped \\$\\n sequences\n            EOF;\n        $expectedNowdoc = <<<'EOF'\n            nowdoc key with whitespace and nonescaped \\$\\n sequences\n            EOF;\n        $expectedCatalogue = [\n            'messages' => [\n                'translatable single-quoted key' => 'prefixtranslatable single-quoted key',\n                'translatable double-quoted key' => 'prefixtranslatable double-quoted key',\n                'translatable heredoc key' => 'prefixtranslatable heredoc key',\n                'translatable nowdoc key' => 'prefixtranslatable nowdoc key',\n                \"translatable double-quoted key with whitespace and escaped \\$\\n\\\" sequences\" => \"prefixtranslatable double-quoted key with whitespace and escaped \\$\\n\\\" sequences\",\n                'translatable single-quoted key with whitespace and nonescaped \\$\\n\\' sequences' => 'prefixtranslatable single-quoted key with whitespace and nonescaped \\$\\n\\' sequences',\n                'translatable single-quoted key with \"quote mark at the end\"' => 'prefixtranslatable single-quoted key with \"quote mark at the end\"',\n                'translatable '.$expectedHeredoc => 'prefixtranslatable '.$expectedHeredoc,\n                'translatable '.$expectedNowdoc => 'prefixtranslatable '.$expectedNowdoc,\n                'translatable concatenated message with heredoc and nowdoc' => 'prefixtranslatable concatenated message with heredoc and nowdoc',\n                'translatable default domain' => 'prefixtranslatable default domain',\n                'translatable-fqn single-quoted key' => 'prefixtranslatable-fqn single-quoted key',\n                'translatable-fqn double-quoted key' => 'prefixtranslatable-fqn double-quoted key',\n                'translatable-fqn heredoc key' => 'prefixtranslatable-fqn heredoc key',\n                'translatable-fqn nowdoc key' => 'prefixtranslatable-fqn nowdoc key',\n                \"translatable-fqn double-quoted key with whitespace and escaped \\$\\n\\\" sequences\" => \"prefixtranslatable-fqn double-quoted key with whitespace and escaped \\$\\n\\\" sequences\",\n                'translatable-fqn single-quoted key with whitespace and nonescaped \\$\\n\\' sequences' => 'prefixtranslatable-fqn single-quoted key with whitespace and nonescaped \\$\\n\\' sequences',\n                'translatable-fqn single-quoted key with \"quote mark at the end\"' => 'prefixtranslatable-fqn single-quoted key with \"quote mark at the end\"',\n                'translatable-fqn '.$expectedHeredoc => 'prefixtranslatable-fqn '.$expectedHeredoc,\n                'translatable-fqn '.$expectedNowdoc => 'prefixtranslatable-fqn '.$expectedNowdoc,\n                'translatable-fqn concatenated message with heredoc and nowdoc' => 'prefixtranslatable-fqn concatenated message with heredoc and nowdoc',\n                'translatable-fqn default domain' => 'prefixtranslatable-fqn default domain',\n                'translatable-short single-quoted key' => 'prefixtranslatable-short single-quoted key',\n                'translatable-short double-quoted key' => 'prefixtranslatable-short double-quoted key',\n                'translatable-short heredoc key' => 'prefixtranslatable-short heredoc key',\n                'translatable-short nowdoc key' => 'prefixtranslatable-short nowdoc key',\n                \"translatable-short double-quoted key with whitespace and escaped \\$\\n\\\" sequences\" => \"prefixtranslatable-short double-quoted key with whitespace and escaped \\$\\n\\\" sequences\",\n                'translatable-short single-quoted key with whitespace and nonescaped \\$\\n\\' sequences' => 'prefixtranslatable-short single-quoted key with whitespace and nonescaped \\$\\n\\' sequences',\n                'translatable-short single-quoted key with \"quote mark at the end\"' => 'prefixtranslatable-short single-quoted key with \"quote mark at the end\"',\n                'translatable-short '.$expectedHeredoc => 'prefixtranslatable-short '.$expectedHeredoc,\n                'translatable-short '.$expectedNowdoc => 'prefixtranslatable-short '.$expectedNowdoc,\n                'translatable-short concatenated message with heredoc and nowdoc' => 'prefixtranslatable-short concatenated message with heredoc and nowdoc',\n                'translatable-short default domain' => 'prefixtranslatable-short default domain',\n                'translatable-short-fqn single-quoted key' => 'prefixtranslatable-short-fqn single-quoted key',\n                'translatable-short-fqn double-quoted key' => 'prefixtranslatable-short-fqn double-quoted key',\n                'translatable-short-fqn heredoc key' => 'prefixtranslatable-short-fqn heredoc key',\n                'translatable-short-fqn nowdoc key' => 'prefixtranslatable-short-fqn nowdoc key',\n                \"translatable-short-fqn double-quoted key with whitespace and escaped \\$\\n\\\" sequences\" => \"prefixtranslatable-short-fqn double-quoted key with whitespace and escaped \\$\\n\\\" sequences\",\n                'translatable-short-fqn single-quoted key with whitespace and nonescaped \\$\\n\\' sequences' => 'prefixtranslatable-short-fqn single-quoted key with whitespace and nonescaped \\$\\n\\' sequences',\n                'translatable-short-fqn single-quoted key with \"quote mark at the end\"' => 'prefixtranslatable-short-fqn single-quoted key with \"quote mark at the end\"',\n                'translatable-short-fqn '.$expectedHeredoc => 'prefixtranslatable-short-fqn '.$expectedHeredoc,\n                'translatable-short-fqn '.$expectedNowdoc => 'prefixtranslatable-short-fqn '.$expectedNowdoc,\n                'translatable-short-fqn concatenated message with heredoc and nowdoc' => 'prefixtranslatable-short-fqn concatenated message with heredoc and nowdoc',\n                'translatable-short-fqn default domain' => 'prefixtranslatable-short-fqn default domain',\n                'single-quoted key' => 'prefixsingle-quoted key',\n                'double-quoted key' => 'prefixdouble-quoted key',\n                'heredoc key' => 'prefixheredoc key',\n                'nowdoc key' => 'prefixnowdoc key',\n                \"double-quoted key with whitespace and escaped \\$\\n\\\" sequences\" => \"prefixdouble-quoted key with whitespace and escaped \\$\\n\\\" sequences\",\n                'single-quoted key with whitespace and nonescaped \\$\\n\\' sequences' => 'prefixsingle-quoted key with whitespace and nonescaped \\$\\n\\' sequences',\n                'single-quoted key with \"quote mark at the end\"' => 'prefixsingle-quoted key with \"quote mark at the end\"',\n                $expectedHeredoc => 'prefix'.$expectedHeredoc,\n                $expectedNowdoc => 'prefix'.$expectedNowdoc,\n                'concatenated message with heredoc and nowdoc' => 'prefixconcatenated message with heredoc and nowdoc',\n                'default domain' => 'prefixdefault domain',\n                'mix-named-arguments' => 'prefixmix-named-arguments',\n                'mix-named-arguments-locale' => 'prefixmix-named-arguments-locale',\n                'mix-named-arguments-without-domain' => 'prefixmix-named-arguments-without-domain',\n            ],\n            'not_messages' => [\n                'translatable other-domain-test-no-params-short-array' => 'prefixtranslatable other-domain-test-no-params-short-array',\n                'translatable other-domain-test-no-params-long-array' => 'prefixtranslatable other-domain-test-no-params-long-array',\n                'translatable other-domain-test-params-short-array' => 'prefixtranslatable other-domain-test-params-short-array',\n                'translatable other-domain-test-params-long-array' => 'prefixtranslatable other-domain-test-params-long-array',\n                'translatable typecast' => 'prefixtranslatable typecast',\n                'translatable-fqn other-domain-test-no-params-short-array' => 'prefixtranslatable-fqn other-domain-test-no-params-short-array',\n                'translatable-fqn other-domain-test-no-params-long-array' => 'prefixtranslatable-fqn other-domain-test-no-params-long-array',\n                'translatable-fqn other-domain-test-params-short-array' => 'prefixtranslatable-fqn other-domain-test-params-short-array',\n                'translatable-fqn other-domain-test-params-long-array' => 'prefixtranslatable-fqn other-domain-test-params-long-array',\n                'translatable-fqn typecast' => 'prefixtranslatable-fqn typecast',\n                'translatable-short other-domain-test-no-params-short-array' => 'prefixtranslatable-short other-domain-test-no-params-short-array',\n                'translatable-short other-domain-test-no-params-long-array' => 'prefixtranslatable-short other-domain-test-no-params-long-array',\n                'translatable-short other-domain-test-params-short-array' => 'prefixtranslatable-short other-domain-test-params-short-array',\n                'translatable-short other-domain-test-params-long-array' => 'prefixtranslatable-short other-domain-test-params-long-array',\n                'translatable-short typecast' => 'prefixtranslatable-short typecast',\n                'translatable-short-fqn other-domain-test-no-params-short-array' => 'prefixtranslatable-short-fqn other-domain-test-no-params-short-array',\n                'translatable-short-fqn other-domain-test-no-params-long-array' => 'prefixtranslatable-short-fqn other-domain-test-no-params-long-array',\n                'translatable-short-fqn other-domain-test-params-short-array' => 'prefixtranslatable-short-fqn other-domain-test-params-short-array',\n                'translatable-short-fqn other-domain-test-params-long-array' => 'prefixtranslatable-short-fqn other-domain-test-params-long-array',\n                'translatable-short-fqn typecast' => 'prefixtranslatable-short-fqn typecast',\n                'other-domain-test-no-params-short-array' => 'prefixother-domain-test-no-params-short-array',\n                'other-domain-test-no-params-long-array' => 'prefixother-domain-test-no-params-long-array',\n                'other-domain-test-params-short-array' => 'prefixother-domain-test-params-short-array',\n                'other-domain-test-params-long-array' => 'prefixother-domain-test-params-long-array',\n                'typecast' => 'prefixtypecast',\n                'ordered-named-arguments-in-trans-method' => 'prefixordered-named-arguments-in-trans-method',\n                'disordered-named-arguments-in-trans-method' => 'prefixdisordered-named-arguments-in-trans-method',\n                'variable-assignation-inlined-in-trans-method-call1' => 'prefixvariable-assignation-inlined-in-trans-method-call1',\n                'variable-assignation-inlined-in-trans-method-call2' => 'prefixvariable-assignation-inlined-in-trans-method-call2',\n                'variable-assignation-inlined-in-trans-method-call3' => 'prefixvariable-assignation-inlined-in-trans-method-call3',\n                'variable-assignation-inlined-with-named-arguments-in-trans-method' => 'prefixvariable-assignation-inlined-with-named-arguments-in-trans-method',\n                'mix-named-arguments-without-parameters' => 'prefixmix-named-arguments-without-parameters',\n                'mix-named-arguments-disordered' => 'prefixmix-named-arguments-disordered',\n                'const-domain' => 'prefixconst-domain',\n            ],\n            'validators' => [\n                'message-in-constraint-attribute' => 'prefixmessage-in-constraint-attribute',\n                // 'custom Isbn message from attribute' => 'prefixcustom Isbn message from attribute',\n                'custom Isbn message from attribute with options as array' => 'prefixcustom Isbn message from attribute with options as array',\n                'custom Length exact message from attribute from named argument' => 'prefixcustom Length exact message from attribute from named argument',\n                'custom Length exact message from attribute from named argument 1/2' => 'prefixcustom Length exact message from attribute from named argument 1/2',\n                'custom Length min message from attribute from named argument 2/2' => 'prefixcustom Length min message from attribute from named argument 2/2',\n                // 'custom Isbn message' => 'prefixcustom Isbn message',\n                'custom Isbn message with options as array' => 'prefixcustom Isbn message with options as array',\n                'custom Isbn message from named argument' => 'prefixcustom Isbn message from named argument',\n                'custom Length exact message from named argument' => 'prefixcustom Length exact message from named argument',\n                'custom Length exact message from named argument 1/2' => 'prefixcustom Length exact message from named argument 1/2',\n                'custom Length min message from named argument 2/2' => 'prefixcustom Length min message from named argument 2/2',\n            ],\n        ];\n        $actualCatalogue = $catalogue->all();\n\n        $this->assertEquals($expectedCatalogue, $actualCatalogue);\n\n        $filename = str_replace(\\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translatable.html.php';\n        $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('translatable single-quoted key'));\n        $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('translatable other-domain-test-no-params-short-array', 'not_messages'));\n\n        $filename = str_replace(\\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translatable-fqn.html.php';\n        $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('translatable-fqn single-quoted key'));\n        $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('translatable-fqn other-domain-test-no-params-short-array', 'not_messages'));\n\n        $filename = str_replace(\\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translatable-short.html.php';\n        $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('translatable-short single-quoted key'));\n        $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('translatable-short other-domain-test-no-params-short-array', 'not_messages'));\n\n        $filename = str_replace(\\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translatable-short-fqn.html.php';\n        $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('translatable-short-fqn single-quoted key'));\n        $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('translatable-short-fqn other-domain-test-no-params-short-array', 'not_messages'));\n\n        $filename = str_replace(\\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translation.html.php';\n        $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('single-quoted key'));\n        $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('other-domain-test-no-params-short-array', 'not_messages'));\n    }\n\n    public function testExtractionFromIndentedHeredocNowdoc()\n    {\n        $catalogue = new MessageCatalogue('en');\n\n        $extractor = new PhpAstExtractor([\n            new TransMethodVisitor(),\n            new TranslatableMessageVisitor(),\n            new ConstraintVisitor([\n                'NotBlank',\n                'Isbn',\n                'Length',\n            ], new TranslatableMessageVisitor()),\n        ]);\n        $extractor->setPrefix('prefix');\n        $extractor->extract(__DIR__.'/../Fixtures/extractor-7.3/translation.html.php', $catalogue);\n\n        $expectedCatalogue = [\n            'messages' => [\n                \"heredoc\\nindented\\n  further\" => \"prefixheredoc\\nindented\\n  further\",\n                \"nowdoc\\nindented\\n  further\" => \"prefixnowdoc\\nindented\\n  further\",\n            ],\n        ];\n\n        $this->assertEquals($expectedCatalogue, $catalogue->all());\n    }\n\n    public static function resourcesProvider(): array\n    {\n        $directory = __DIR__.'/../Fixtures/extractor-ast/';\n        $phpFiles = [];\n        $splFiles = [];\n        foreach (new \\DirectoryIterator($directory) as $fileInfo) {\n            if ($fileInfo->isDot()) {\n                continue;\n            }\n            if (\\in_array($fileInfo->getBasename(), ['translatable.html.php', 'translatable-fqn.html.php', 'translatable-short.html.php', 'translatable-short-fqn.html.php', 'translation.html.php', 'validator-constraints.php'], true)) {\n                $phpFiles[] = $fileInfo->getPathname();\n            }\n            $splFiles[] = $fileInfo->getFileInfo();\n        }\n\n        return [\n            [$directory],\n            [$phpFiles],\n            [glob($directory.'*')],\n            [$splFiles],\n            [new \\ArrayObject(glob($directory.'*'))],\n            [new \\ArrayObject($splFiles)],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/empty-translation.po",
    "content": "msgid \"foo\"\nmsgstr \"\"\n\n"
  },
  {
    "path": "Tests/Fixtures/empty.csv",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/empty.ini",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/empty.json",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/empty.mo",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/empty.po",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/empty.xlf",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/empty.yml",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/encoding.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n    <body>\n      <trans-unit id=\"1\" resname=\"foo\">\n        <source>foo</source>\n        <target>br</target>\n        <note>bz</note>\n      </trans-unit>\n      <trans-unit id=\"2\" resname=\"bar\">\n        <source>bar</source>\n        <target>f</target>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/escaped-id-plurals.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: en\\n\"\n\nmsgid \"escaped \\\"foo\\\"\"\nmsgid_plural \"escaped \\\"foos\\\"\"\nmsgstr[0] \"escaped \\\"bar\\\"\"\nmsgstr[1] \"escaped \\\"bars\\\"\"\n"
  },
  {
    "path": "Tests/Fixtures/escaped-id.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: en\\n\"\n\nmsgid \"escaped \\\"foo\\\"\"\nmsgstr \"escaped \\\"bar\\\"\"\n"
  },
  {
    "path": "Tests/Fixtures/extractor/resource.format.engine",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/extractor/this.is.a.template.format.engine",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/extractor/translatable-fqn.html.php",
    "content": "This template is used for translation message extraction tests\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn single-quoted key'); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn double-quoted key'); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(<<<EOF\ntranslatable-fqn heredoc key\nEOF\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(<<<'EOF'\ntranslatable-fqn nowdoc key\nEOF\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(\n    \"translatable-fqn double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(\n    'translatable-fqn single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(<<<EOF\ntranslatable-fqn heredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(<<<'EOF'\ntranslatable-fqn nowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn default domain', [], null); ?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor/translatable-short.html.php",
    "content": "This template is used for translation message extraction tests\n<?php t('translatable-short single-quoted key'); ?>\n<?php t('translatable-short double-quoted key'); ?>\n<?php t(<<<EOF\ntranslatable-short heredoc key\nEOF\n); ?>\n<?php t(<<<'EOF'\ntranslatable-short nowdoc key\nEOF\n); ?>\n<?php t(\n    \"translatable-short double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php t(\n    'translatable-short single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php t(<<<EOF\ntranslatable-short heredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php t(<<<'EOF'\ntranslatable-short nowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php t('translatable-short single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php t('translatable-short concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php t('translatable-short other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php t('translatable-short other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php t('translatable-short other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php t('translatable-short other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php t('translatable-short typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php t('translatable-short default domain', [], null); ?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor/translatable.html.php",
    "content": "This template is used for translation message extraction tests\n<?php new TranslatableMessage('translatable single-quoted key'); ?>\n<?php new TranslatableMessage('translatable double-quoted key'); ?>\n<?php new TranslatableMessage(<<<EOF\ntranslatable heredoc key\nEOF\n); ?>\n<?php new TranslatableMessage(<<<'EOF'\ntranslatable nowdoc key\nEOF\n); ?>\n<?php new TranslatableMessage(\n    \"translatable double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php new TranslatableMessage(\n    'translatable single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php new TranslatableMessage(<<<EOF\ntranslatable heredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php new TranslatableMessage(<<<'EOF'\ntranslatable nowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php new TranslatableMessage('translatable single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php new TranslatableMessage('translatable concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php new TranslatableMessage('translatable other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable default domain', [], null); ?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor/translation.html.php",
    "content": "This template is used for translation message extraction tests\n<?php echo $view['translator']->trans('single-quoted key'); ?>\n<?php echo $view['translator']->trans('double-quoted key'); ?>\n<?php echo $view['translator']->trans(<<<EOF\nheredoc key\nEOF\n); ?>\n<?php echo $view['translator']->trans(<<<'EOF'\nnowdoc key\nEOF\n); ?>\n<?php echo $view['translator']->trans(\n    \"double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php echo $view['translator']->trans(\n    'single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php echo $view['translator']->trans(<<<EOF\nheredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php echo $view['translator']->trans(<<<'EOF'\nnowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php echo $view['translator']->trans('single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php echo $view['translator']->trans('concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php echo $view['translator']->trans('other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('default domain', [], null); ?>\n\n"
  },
  {
    "path": "Tests/Fixtures/extractor-7.3/translation.html.php",
    "content": "This template is used for translation message extraction tests\n<?php echo $view['translator']->trans(<<<EOF\n    heredoc\n    indented\n      further\n    EOF\n); ?>\n<?php echo $view['translator']->trans(<<<'EOF'\n    nowdoc\n    indented\n      further\n    EOF\n); ?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor-ast/resource.format.engine",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/extractor-ast/this.is.a.template.format.engine",
    "content": ""
  },
  {
    "path": "Tests/Fixtures/extractor-ast/translatable-fqn.html.php",
    "content": "This template is used for translation message extraction tests\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn single-quoted key'); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn double-quoted key'); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(<<<EOF\ntranslatable-fqn heredoc key\nEOF\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(<<<'EOF'\ntranslatable-fqn nowdoc key\nEOF\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(\n    \"translatable-fqn double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(\n    'translatable-fqn single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(<<<EOF\ntranslatable-fqn heredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage(<<<'EOF'\ntranslatable-fqn nowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php new \\Symfony\\Component\\Translation\\TranslatableMessage('translatable-fqn default domain', [], null); ?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor-ast/translatable-short-fqn.html.php",
    "content": "This template is used for translation message extraction tests\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn single-quoted key'); ?>\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn double-quoted key'); ?>\n<?php \\Symfony\\Component\\Translation\\t(<<<EOF\ntranslatable-short-fqn heredoc key\nEOF\n); ?>\n<?php \\Symfony\\Component\\Translation\\t(<<<'EOF'\ntranslatable-short-fqn nowdoc key\nEOF\n); ?>\n<?php \\Symfony\\Component\\Translation\\t(\n    \"translatable-short-fqn double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php \\Symfony\\Component\\Translation\\t(\n    'translatable-short-fqn single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php \\Symfony\\Component\\Translation\\t(<<<EOF\ntranslatable-short-fqn heredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php \\Symfony\\Component\\Translation\\t(<<<'EOF'\ntranslatable-short-fqn nowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php \\Symfony\\Component\\Translation\\t('translatable-short-fqn default domain', [], null); ?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor-ast/translatable-short.html.php",
    "content": "This template is used for translation message extraction tests\n<?php t('translatable-short single-quoted key'); ?>\n<?php t('translatable-short double-quoted key'); ?>\n<?php t(<<<EOF\ntranslatable-short heredoc key\nEOF\n); ?>\n<?php t(<<<'EOF'\ntranslatable-short nowdoc key\nEOF\n); ?>\n<?php t(\n    \"translatable-short double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php t(\n    'translatable-short single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php t(<<<EOF\ntranslatable-short heredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php t(<<<'EOF'\ntranslatable-short nowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php t('translatable-short single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php t('translatable-short concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php t('translatable-short other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php t('translatable-short other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php t('translatable-short other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php t('translatable-short other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php t('translatable-short typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php t('translatable-short default domain', [], null); ?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor-ast/translatable.html.php",
    "content": "This template is used for translation message extraction tests\n<?php new TranslatableMessage('translatable single-quoted key'); ?>\n<?php new TranslatableMessage('translatable double-quoted key'); ?>\n<?php new TranslatableMessage(<<<EOF\ntranslatable heredoc key\nEOF\n); ?>\n<?php new TranslatableMessage(<<<'EOF'\ntranslatable nowdoc key\nEOF\n); ?>\n<?php new TranslatableMessage(\n    \"translatable double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php new TranslatableMessage(\n    'translatable single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php new TranslatableMessage(<<<EOF\ntranslatable heredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php new TranslatableMessage(<<<'EOF'\ntranslatable nowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php new TranslatableMessage('translatable single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php new TranslatableMessage('translatable concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php new TranslatableMessage('translatable other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php new TranslatableMessage('translatable default domain', [], null); ?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor-ast/translation.html.php",
    "content": "This template is used for translation message extraction tests\n<?php echo $view['translator']->trans('single-quoted key'); ?>\n<?php echo $view['translator']->trans('double-quoted key'); ?>\n<?php echo $view['translator']->trans(<<<EOF\nheredoc key\nEOF\n); ?>\n<?php echo $view['translator']->trans(<<<'EOF'\nnowdoc key\nEOF\n); ?>\n<?php echo $view['translator']->trans(\n    \"double-quoted key with whitespace and escaped \\$\\n\\\" sequences\"\n); ?>\n<?php echo $view['translator']->trans(\n    'single-quoted key with whitespace and nonescaped \\$\\n\\' sequences'\n); ?>\n<?php echo $view['translator']->trans(<<<EOF\nheredoc key with whitespace and escaped \\$\\n sequences\nEOF\n); ?>\n<?php echo $view['translator']->trans(<<<'EOF'\nnowdoc key with whitespace and nonescaped \\$\\n sequences\nEOF\n); ?>\n\n<?php echo $view['translator']->trans('single-quoted key with \"quote mark at the end\"'); ?>\n\n<?php echo $view['translator']->trans('concatenated'.' message'.<<<EOF\n with heredoc\nEOF\n.<<<'EOF'\n and nowdoc\nEOF\n); ?>\n\n<?php echo $view['translator']->trans('other-domain-test-no-params-short-array', [], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('other-domain-test-no-params-long-array', [], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('typecast', ['a' => (int) '123'], 'not_messages'); ?>\n\n<?php echo $view['translator']->trans('default domain', [], null); ?>\n\n<?php echo $view['translator']->trans(id: 'ordered-named-arguments-in-trans-method', parameters: [], domain: 'not_messages'); ?>\n<?php echo $view['translator']->trans(domain: 'not_messages', id: 'disordered-named-arguments-in-trans-method', parameters: []); ?>\n\n<?php echo $view['translator']->trans($key = 'variable-assignation-inlined-in-trans-method-call1', $parameters = [], $domain = 'not_messages'); ?>\n<?php echo $view['translator']->trans('variable-assignation-inlined-in-trans-method-call2', $parameters = [], $domain = 'not_messages'); ?>\n<?php echo $view['translator']->trans('variable-assignation-inlined-in-trans-method-call3', [], $domain = 'not_messages'); ?>\n\n<?php echo $view['translator']->trans(domain: $domain = 'not_messages', id: $key = 'variable-assignation-inlined-with-named-arguments-in-trans-method', parameters: $parameters = []); ?>\n\n<?php echo $view['translator']->trans('mix-named-arguments', parameters: ['foo' => 'bar']); ?>\n<?php echo $view['translator']->trans('mix-named-arguments-locale', parameters: ['foo' => 'bar'], locale: 'de'); ?>\n<?php echo $view['translator']->trans('mix-named-arguments-without-domain', parameters: ['foo' => 'bar']); ?>\n<?php echo $view['translator']->trans('mix-named-arguments-without-parameters', domain: 'not_messages'); ?>\n<?php echo $view['translator']->trans('mix-named-arguments-disordered', domain: 'not_messages', parameters: []); ?>\n\n<?php echo $view['translator']->trans(...); // should not fail ?>\n\n<?php\nuse Symfony\\Component\\Translation\\Tests\\Extractor\\PhpAstExtractorTest;\necho $view['translator']->trans('const-domain', [], PhpAstExtractorTest::OTHER_DOMAIN);\n?>\n"
  },
  {
    "path": "Tests/Fixtures/extractor-ast/validator-constraints.php",
    "content": "This template is used for translation message extraction tests\n<?php\n\nuse Symfony\\Component\\Validator\\Constraints as Assert;\n\nclass Foo\n{\n    #[Assert\\NotBlank(message: 'message-in-constraint-attribute')]\n    public string $bar;\n\n    #[Assert\\Length(exactMessage: 'custom Length exact message from attribute from named argument')]\n    public string $bar2;\n\n    #[Assert\\Length(exactMessage: 'custom Length exact message from attribute from named argument 1/2', minMessage: 'custom Length min message from attribute from named argument 2/2')]\n    public string $bar3;\n\n    #[Assert\\Isbn('isbn10', 'custom Isbn message from attribute')] // no way to handle those arguments (not named, not in associative array).\n    public string $isbn;\n\n    #[Assert\\Isbn([\n        'type' => 'isbn10',\n        'message' => 'custom Isbn message from attribute with options as array',\n    ])]\n    public string $isbn2;\n}\n\nclass Foo2\n{\n    public function index()\n    {\n        $constraint1 = new Assert\\Isbn('isbn10', 'custom Isbn message'); // no way to handle those arguments (not named, not in associative array).\n        $constraint2 = new Assert\\Isbn([\n            'type' => 'isbn10',\n            'message' => 'custom Isbn message with options as array',\n        ]);\n        $constraint3 = new Assert\\Isbn(message: 'custom Isbn message from named argument');\n        $constraint4 = new Assert\\Length(exactMessage: 'custom Length exact message from named argument');\n        $constraint5 = new Assert\\Length(exactMessage: 'custom Length exact message from named argument 1/2', minMessage: 'custom Length min message from named argument 2/2');\n    }\n}\n"
  },
  {
    "path": "Tests/Fixtures/fuzzy-translations.po",
    "content": "#, php-format\nmsgid \"foo1\"\nmsgstr \"bar1\"\n\n#, fuzzy, php-format\nmsgid \"foo2\"\nmsgstr \"fuzzy bar2\"\n\nmsgid \"foo3\"\nmsgstr \"bar3\"\n"
  },
  {
    "path": "Tests/Fixtures/invalid-xml-resources.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n    <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n        <body>\n            <trans-unit id=\"1\">\n                <source>foo</source>\n                <target>bar\n            </trans-unit>\n            <trans-unit id=\"2\">\n                <source>extra</source>\n            </trans-unit>\n            <trans-unit id=\"3\">\n                <source>key</source>\n                <target></target>\n            </trans-unit>\n            <trans-unit id=\"4\">\n                <source>test</source>\n                <target>with</target>\n                <note>note</note>\n            </trans-unit>\n        </body>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/malformed.json",
    "content": "{\n    \"foo\" \"bar\"\n}"
  },
  {
    "path": "Tests/Fixtures/messages.yml",
    "content": "foo:\n    bar1: value1\n    bar2: value2\n"
  },
  {
    "path": "Tests/Fixtures/messages_linear.yml",
    "content": "foo.bar1: value1\nfoo.bar2: value2\n"
  },
  {
    "path": "Tests/Fixtures/missing-plurals.po",
    "content": "msgid \"foo\"\nmsgid_plural \"foos\"\nmsgstr[3] \"bars\"\nmsgstr[1] \"bar\"\n"
  },
  {
    "path": "Tests/Fixtures/non-string.yml",
    "content": "root:\n  foo1:\n  foo2: ''\n  bar: 'bar'\n"
  },
  {
    "path": "Tests/Fixtures/non-valid.xlf",
    "content": "<?xml version=\"1.0\"?>\n<xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n        <body>\n            <trans-unit>\n                <source>foo</source>\n                <target>bar</target>\n            </trans-unit>\n        </body>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/non-valid.yml",
    "content": "foo\n"
  },
  {
    "path": "Tests/Fixtures/plurals.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: en\\n\"\n\nmsgid \"foo\"\nmsgid_plural \"foos\"\nmsgstr[0] \"bar\"\nmsgstr[1] \"bars\"\n\nmsgid \"{0} no foos|one foo|%count% foos\"\nmsgstr \"{0} no bars|one bar|%count% bars\"\n"
  },
  {
    "path": "Tests/Fixtures/resname.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n    <body>\n      <trans-unit id=\"1\" resname=\"foo\">\n        <source></source>\n        <target>bar</target>\n      </trans-unit>\n      <trans-unit id=\"2\" resname=\"bar\">\n        <source>bar source</source>\n        <target>baz</target>\n      </trans-unit>\n      <trans-unit id=\"3\">\n        <source>baz</source>\n        <target>foo</target>\n      </trans-unit>\n      <trans-unit id=\"4\" resname=\"qux\">\n        <source>qux source</source>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resourcebundle/dat/en.txt",
    "content": "en{\n    symfony{\"Symfony is great\"}\n}"
  },
  {
    "path": "Tests/Fixtures/resourcebundle/dat/fr.txt",
    "content": "fr{\n    symfony{\"Symfony est génial\"}\n}"
  },
  {
    "path": "Tests/Fixtures/resourcebundle/dat/packagelist.txt",
    "content": "en.res\nfr.res\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.0+intl-icu.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR\" trgLang=\"en-US\">\n  <file id=\"messages.en_US\">\n    <unit id=\"ea75LoN\" name=\"foo\">\n      <segment>\n        <source>foo</source>\n        <target>bar</target>\n      </segment>\n    </unit>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.0-clean.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR\" trgLang=\"en-US\">\n  <file id=\"messages.en_US\">\n    <unit id=\"ea75LoN\" name=\"foo\">\n      <segment>\n        <source>foo</source>\n        <target>bar</target>\n      </segment>\n    </unit>\n    <unit id=\"pL305WR\" name=\"key\">\n      <segment>\n        <source>key</source>\n        <target order=\"1\"></target>\n      </segment>\n    </unit>\n    <unit id=\"FrtCNPU\" name=\"key.with.cdata\">\n      <segment>\n        <source>key.with.cdata</source>\n        <target><![CDATA[<source> & <target>]]></target>\n      </segment>\n    </unit>\n    <unit id=\"UJTTgBF\">\n      <segment>\n        <source>translation.key.that.is.longer.than.eighty.characters.should.not.have.name.attribute</source>\n        <target>value</target>\n      </segment>\n    </unit>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.0-empty-notes.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR\" trgLang=\"en-US\">\n  <file id=\"messages.en_US\">\n    <unit id=\"Ll7LrI6\" name=\"empty\">\n      <segment>\n        <source>empty</source>\n        <target>notes</target>\n      </segment>\n    </unit>\n    <unit id=\"hU8PAYC\" name=\"full\">\n      <notes>\n        <note category=\"file-source\" priority=\"1\">test/path/to/translation/Example.1.html.twig:27</note>\n      </notes>\n      <segment>\n        <source>full</source>\n        <target>notes</target>\n      </segment>\n    </unit>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.0-multi-segment-unit.xlf",
    "content": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en-US\" trgLang=\"en-US\">\n    <file id=\"f1\">\n        <unit id=\"1\">\n            <notes>\n                <note category=\"processed\">true</note>\n            </notes>\n            <segment id=\"id-foo\">\n                <source>foo</source>\n                <target>foo (translated)</target>\n            </segment>\n            <segment id=\"id-bar\">\n                <source>bar</source>\n                <target>bar (translated)</target>\n            </segment>\n        </unit>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.0-name.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en-US\">\n    <file id=\"f1\" original=\"Graphic Example.psd\">\n        <unit id=\"1\" name=\"foo\">\n            <segment>\n                <source></source>\n                <target>bar</target>\n            </segment>\n        </unit>\n        <unit id=\"2\" name=\"bar\">\n            <segment>\n                <source>bar source</source>\n                <target>baz</target>\n            </segment>\n        </unit>\n        <unit id=\"3\">\n            <segment>\n                <source>baz</source>\n                <target>foo</target>\n            </segment>\n        </unit>\n        <unit id=\"4\" name=\"qux\">\n            <segment>\n                <source>qux source</source>\n            </segment>\n        </unit>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.0-segment-attributes.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR\" trgLang=\"en-US\">\n  <file id=\"messages.en_US\">\n    <unit id=\"ea75LoN\" name=\"foo\">\n      <segment state=\"translated\">\n        <source>foo</source>\n        <target>bar</target>\n      </segment>\n    </unit>\n    <unit id=\"pL305WR\" name=\"key\">\n      <segment state=\"translated\" subState=\"My Value\">\n        <source>key</source>\n        <target></target>\n      </segment>\n    </unit>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.0.xlf",
    "content": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en-US\" trgLang=\"ja-JP\">\n    <file id=\"f1\" original=\"Graphic Example.psd\">\n        <skeleton href=\"Graphic Example.psd.skl\"/>\n        <unit id=\"1\">\n            <segment>\n                <source>Quetzal</source>\n                <target>Quetzal</target>\n            </segment>\n        </unit>\n        <group id=\"1\">\n            <unit id=\"2\">\n                <segment>\n                    <source>foo</source>\n                    <target>XLIFF 文書を編集、または処理 するアプリケーションです。</target>\n                </segment>\n            </unit>\n            <unit id=\"3\">\n                <segment>\n                    <source>bar</source>\n                    <target order=\"1\">XLIFF データ・マネージャ</target>\n                </segment>\n            </unit>\n        </group>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.1.xlf",
    "content": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.1\" srcLang=\"en-US\" trgLang=\"ja-JP\">\n    <file id=\"f1\" original=\"Graphic Example.psd\">\n        <skeleton href=\"Graphic Example.psd.skl\"/>\n        <unit id=\"1\">\n            <segment>\n                <source>Quetzal</source>\n                <target>Quetzal</target>\n            </segment>\n        </unit>\n        <group id=\"1\">\n            <unit id=\"2\">\n                <segment>\n                    <source>foo</source>\n                    <target>XLIFF 文書を編集、または処理 するアプリケーションです。</target>\n                </segment>\n            </unit>\n            <unit id=\"3\">\n                <segment>\n                    <source>bar</source>\n                    <target order=\"1\">XLIFF データ・マネージャ</target>\n                </segment>\n            </unit>\n        </group>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.2-pgs-combined.xlf",
    "content": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" xmlns:pgs=\"urn:oasis:names:tc:xliff:pgs:1.0\"\n       version=\"2.2\" srcLang=\"en\" trgLang=\"fr\">\n    <file id=\"f1\">\n        <unit id=\"tu1\" name=\"party_host\" pgs:switch=\"gender:host_gender plural:guest_count\">\n            <segment id=\"seg1\" pgs:case=\"feminine 0\">\n                <source><ph id=\"ph1\" disp=\"host_name\"/> did not invite anyone to her party.</source>\n                <target><ph id=\"ph1\" disp=\"host_name\"/> n'a invité personne à sa fête.</target>\n            </segment>\n            <segment id=\"seg2\" pgs:case=\"feminine 1\">\n                <source><ph id=\"ph2\" disp=\"host_name\"/> invited one guest to her party.</source>\n                <target><ph id=\"ph2\" disp=\"host_name\"/> a invité un convive à sa fête.</target>\n            </segment>\n            <segment id=\"seg3\" pgs:case=\"feminine other\">\n                <source><ph id=\"ph3\" disp=\"host_name\"/> invited <ph id=\"ph4\" disp=\"guest_count\"/> guests to her party.</source>\n                <target><ph id=\"ph3\" disp=\"host_name\"/> a invité <ph id=\"ph4\" disp=\"guest_count\"/> convives à sa fête.</target>\n            </segment>\n            <segment id=\"seg4\" pgs:case=\"masculine 0\">\n                <source><ph id=\"ph5\" disp=\"host_name\"/> did not invite anyone to his party.</source>\n                <target><ph id=\"ph5\" disp=\"host_name\"/> n'a invité personne à sa fête.</target>\n            </segment>\n            <segment id=\"seg5\" pgs:case=\"masculine 1\">\n                <source><ph id=\"ph6\" disp=\"host_name\"/> invited one guest to his party.</source>\n                <target><ph id=\"ph6\" disp=\"host_name\"/> a invité un convive à sa fête.</target>\n            </segment>\n            <segment id=\"seg6\" pgs:case=\"masculine other\">\n                <source><ph id=\"ph7\" disp=\"host_name\"/> invited <ph id=\"ph8\" disp=\"guest_count\"/> guests to his party.</source>\n                <target><ph id=\"ph7\" disp=\"host_name\"/> a invité <ph id=\"ph8\" disp=\"guest_count\"/> convives à sa fête.</target>\n            </segment>\n            <segment id=\"seg7\" pgs:case=\"other 0\">\n                <source><ph id=\"ph9\" disp=\"host_name\"/> did not invite anyone to their party.</source>\n                <target><ph id=\"ph9\" disp=\"host_name\"/> n'a invité personne à leur fête.</target>\n            </segment>\n            <segment id=\"seg8\" pgs:case=\"other 1\">\n                <source><ph id=\"ph10\" disp=\"host_name\"/> invited one guest to their party.</source>\n                <target><ph id=\"ph10\" disp=\"host_name\"/> a invité un convive à leur fête.</target>\n            </segment>\n            <segment id=\"seg9\" pgs:case=\"other other\">\n                <source><ph id=\"ph11\" disp=\"host_name\"/> invited <ph id=\"ph12\" disp=\"guest_count\"/> guests to their party.</source>\n                <target><ph id=\"ph11\" disp=\"host_name\"/> a invité <ph id=\"ph12\" disp=\"guest_count\"/> convives à leur fête.</target>\n            </segment>\n        </unit>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.2-pgs-gender.xlf",
    "content": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" xmlns:pgs=\"urn:oasis:names:tc:xliff:pgs:1.0\"\n       version=\"2.2\" srcLang=\"en\" trgLang=\"fr\">\n    <file id=\"f1\">\n        <unit id=\"tu1\" name=\"party_invite\" pgs:switch=\"gender:host_gender\">\n            <segment id=\"seg1\" pgs:case=\"feminine\">\n                <source>You are invited to her party</source>\n                <target>Vous êtes invité à sa fête</target>\n            </segment>\n            <segment id=\"seg2\" pgs:case=\"masculine\">\n                <source>You are invited to his party</source>\n                <target>Vous êtes invité à sa fête</target>\n            </segment>\n            <segment id=\"seg3\" pgs:case=\"other\">\n                <source>You are invited to their party</source>\n                <target>Vous êtes invité à leur fête</target>\n            </segment>\n        </unit>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.2-pgs-plural.xlf",
    "content": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" xmlns:pgs=\"urn:oasis:names:tc:xliff:pgs:1.0\"\n       version=\"2.2\" srcLang=\"en\" trgLang=\"fr\">\n    <file id=\"f1\">\n        <unit id=\"tu1\" name=\"file_deleted\" pgs:switch=\"plural:file_count\">\n            <segment id=\"seg1\" pgs:case=\"0\">\n                <source>You deleted no file.</source>\n                <target>Vous n'avez supprimé aucun fichier.</target>\n            </segment>\n            <segment id=\"seg2\" pgs:case=\"1\">\n                <source>You deleted one file.</source>\n                <target>Vous avez supprimé un fichier.</target>\n            </segment>\n            <segment id=\"seg3\" pgs:case=\"other\">\n                <source>You deleted <ph id=\"1\" disp=\"file_count\"/> files.</source>\n                <target>Vous avez supprimé <ph id=\"1\" disp=\"file_count\"/> fichiers.</target>\n            </segment>\n        </unit>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-2.2.xlf",
    "content": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.2\" srcLang=\"en-US\" trgLang=\"ja-JP\">\n    <file id=\"f1\" original=\"Graphic Example.psd\">\n        <skeleton href=\"Graphic Example.psd.skl\"/>\n        <unit id=\"1\">\n            <segment>\n                <source>Quetzal</source>\n                <target>Quetzal</target>\n            </segment>\n        </unit>\n        <group id=\"1\">\n            <unit id=\"2\">\n                <segment>\n                    <source>foo</source>\n                    <target>XLIFF 文書を編集、または処理 するアプリケーションです。</target>\n                </segment>\n            </unit>\n            <unit id=\"3\">\n                <segment>\n                    <source>bar</source>\n                    <target order=\"1\">XLIFF データ・マネージャ</target>\n                </segment>\n            </unit>\n        </group>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-clean.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"fr-FR\" target-language=\"en-US\" datatype=\"plaintext\" original=\"file.ext\">\n    <header>\n      <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n    </header>\n    <body>\n      <trans-unit id=\"ea75LoN\" resname=\"foo\">\n        <source>foo</source>\n        <target>bar</target>\n        <note priority=\"1\" from=\"bar\">baz</note>\n      </trans-unit>\n      <trans-unit id=\"pL305WR\" resname=\"key\">\n        <source>key</source>\n        <target></target>\n        <note>baz</note>\n        <note>qux</note>\n      </trans-unit>\n      <trans-unit id=\"FrtCNPU\" resname=\"key.with.cdata\">\n        <source>key.with.cdata</source>\n        <target><![CDATA[<source> & <target>]]></target>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-clean.xliff",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"fr-FR\" target-language=\"en-US\" datatype=\"plaintext\" original=\"file.ext\">\n    <header>\n      <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n    </header>\n    <body>\n      <trans-unit id=\"ea75LoN\" resname=\"foo\">\n        <source>foo</source>\n        <target>bar</target>\n        <note priority=\"1\" from=\"bar\">baz</note>\n      </trans-unit>\n      <trans-unit id=\"pL305WR\" resname=\"key\">\n        <source>key</source>\n        <target></target>\n        <note>baz</note>\n        <note>qux</note>\n      </trans-unit>\n      <trans-unit id=\"FrtCNPU\" resname=\"key.with.cdata\">\n        <source>key.with.cdata</source>\n        <target><![CDATA[<source> & <target>]]></target>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-multi-files.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n    <body>\n      <trans-unit id=\"1\">\n        <source>foo</source>\n        <target>bar</target>\n      </trans-unit>\n    </body>\n  </file>\n  <file source-language=\"en\" datatype=\"plaintext\" original=\"otherfile.ext\">\n    <body>\n      <trans-unit id=\"2\">\n        <source>extra</source>\n      </trans-unit>\n      <trans-unit id=\"3\">\n        <source>key</source>\n        <target></target>\n      </trans-unit>\n      <trans-unit id=\"4\">\n        <source>test</source>\n        <target>with</target>\n        <note>note</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-notes-meta.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR\" trgLang=\"en-US\">\n  <file id=\"messages.en_US\">\n    <unit id=\"ea75LoN\" name=\"foo\">\n      <notes>\n        <note category=\"state\">new</note>\n        <note category=\"approved\">true</note>\n        <note category=\"section\" priority=\"1\">user login</note>\n      </notes>\n      <segment>\n        <source>foo</source>\n        <target>bar</target>\n      </segment>\n    </unit>\n    <unit id=\".Odr9ig\" name=\"baz\">\n      <notes>\n        <note id=\"x\">x_content</note>\n        <note appliesTo=\"target\" category=\"quality\">Fuzzy</note>\n      </notes>\n      <segment>\n        <source>baz</source>\n        <target>biz</target>\n      </segment>\n    </unit>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-target-attributes.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"fr-FR\" target-language=\"en-US\" datatype=\"plaintext\" original=\"file.ext\">\n    <header>\n      <tool tool-id=\"symfony\" tool-name=\"Symfony\"/>\n    </header>\n    <body>\n      <trans-unit id=\"ea75LoN\" resname=\"foo\">\n        <source>foo</source>\n        <target state=\"needs-translation\">bar</target>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources-tool-info.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"en-US\" target-language=\"en-US\" datatype=\"plaintext\" original=\"file.ext\">\n    <header>\n      <tool tool-id=\"foo\" tool-name=\"foo\" tool-version=\"0.0\" tool-company=\"Foo\"/>\n    </header>\n    <body>\n      <trans-unit id=\"ea75LoN\" resname=\"foo\">\n        <source>foo</source>\n        <target>bar</target>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources.csv",
    "content": "\"foo\"; \"bar\"\n#\"bar\"; \"foo\"\n\n# all incorrect examples:\n\"incorrect\"; \"number\"; \"columns\"; \"will\"; \"be\"; \"ignored\"\n\"incorrect\"\n"
  },
  {
    "path": "Tests/Fixtures/resources.dump.json",
    "content": "{\"foo\":\"\\u0022bar\\u0022\"}"
  },
  {
    "path": "Tests/Fixtures/resources.ini",
    "content": "foo=\"bar\"\n"
  },
  {
    "path": "Tests/Fixtures/resources.json",
    "content": "{\n    \"foo\": \"bar\"\n}"
  },
  {
    "path": "Tests/Fixtures/resources.php",
    "content": "<?php\n\nreturn array (\n  'foo' => 'bar',\n);\n"
  },
  {
    "path": "Tests/Fixtures/resources.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: en\\n\"\n\nmsgid \"foo\"\nmsgstr \"bar\"\n\nmsgid \"bar\"\nmsgstr \"foo\"\n\n# Comment 1\n# Comment 2\n#, fuzzy,another\n#: src/file_1 src/file_2:50\nmsgid \"foo_bar\"\nmsgstr \"foobar\"\n\n# Comment\n#, fuzzy\n#: src/file_1\nmsgid \"bar_foo\"\nmsgstr \"barfoo\"\n"
  },
  {
    "path": "Tests/Fixtures/resources.ts",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TS>\n  <context>\n    <name>resources</name>\n    <message>\n      <source>foo</source>\n      <translation>bar</translation>\n    </message>\n    <message>\n      <location filename=\"src/file_1\"/>\n      <location filename=\"src/file_2\" line=\"50\"/>\n      <source>foo_bar</source>\n      <translation>foobar</translation>\n    </message>\n    <message>\n      <location filename=\"src/file_1\"/>\n      <source>bar_foo</source>\n      <translation>barfoo</translation>\n    </message>\n  </context>\n</TS>\n"
  },
  {
    "path": "Tests/Fixtures/resources.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n    <body>\n      <trans-unit id=\"1\">\n        <source>foo</source>\n        <target>bar</target>\n      </trans-unit>\n      <trans-unit id=\"2\">\n        <source>extra</source>\n      </trans-unit>\n      <trans-unit id=\"3\">\n        <source>key</source>\n        <target></target>\n      </trans-unit>\n      <trans-unit id=\"4\">\n        <source>test</source>\n        <target>with</target>\n        <note>note</note>\n      </trans-unit>\n      <trans-unit id=\"5\">\n        <source>skipped</source>\n        <target state=\"needs-translation\">skipped</target>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/resources.yml",
    "content": "foo: bar\n"
  },
  {
    "path": "Tests/Fixtures/valid.csv",
    "content": "foo;bar\nbar;\"foo\nfoo\"\n\"foo;foo\";bar\n"
  },
  {
    "path": "Tests/Fixtures/with-attributes.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n    <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n        <body>\n            <trans-unit id=\"1\">\n                <source>foo</source>\n                <target state=\"translated\">bar</target>\n            </trans-unit>\n            <trans-unit id=\"2\">\n                <source>extra</source>\n                <target state=\"needs-translation\">bar</target>\n            </trans-unit>\n            <trans-unit id=\"3\">\n                <source>key</source>\n                <target></target>\n                <note>baz</note>\n                <note priority=\"2\" from=\"bar\">qux</note>\n            </trans-unit>\n        </body>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/withdoctype.xlf",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE foo>\n<xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n        <body>\n            <trans-unit id=\"1\">\n                <source>foo</source>\n                <target>bar</target>\n            </trans-unit>\n        </body>\n    </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Fixtures/withnote.xlf",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n  <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n    <body>\n      <trans-unit id=\"1\">\n        <source>foo</source>\n        <target>bar</target>\n        <note priority=\"1\">foo</note>\n      </trans-unit>\n      <trans-unit id=\"2\" resname=\"extra\">\n        <source>extrasource</source>\n        <note from=\"foo\">bar</note>\n      </trans-unit>\n      <trans-unit id=\"123\">\n        <source>key</source>\n        <target></target>\n        <note>baz</note>\n        <note priority=\"2\" from=\"bar\">qux</note>\n      </trans-unit>\n    </body>\n  </file>\n</xliff>\n"
  },
  {
    "path": "Tests/Formatter/IntlFormatterTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Formatter;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Formatter\\IntlFormatter;\nuse Symfony\\Component\\Translation\\Formatter\\IntlFormatterInterface;\n\n#[RequiresPhpExtension('intl')]\nclass IntlFormatterTest extends TestCase\n{\n    #[DataProvider('provideDataForFormat')]\n    public function testFormat($expected, $message, $arguments)\n    {\n        $this->assertEquals($expected, trim((new IntlFormatter())->formatIntl($message, 'en', $arguments)));\n    }\n\n    public function testInvalidFormat()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        (new IntlFormatter())->formatIntl('{foo', 'en', [2]);\n    }\n\n    public function testFormatWithNamedArguments()\n    {\n        if (version_compare(\\INTL_ICU_VERSION, '4.8', '<')) {\n            $this->markTestSkipped('Format with named arguments can only be run with ICU 4.8 or higher and PHP >= 5.5');\n        }\n\n        $chooseMessage = <<<'_MSG_'\n            {gender_of_host, select,\n              female {{num_guests, plural, offset:1\n                  =0 {{host} does not give a party.}\n                  =1 {{host} invites {guest} to her party.}\n                  =2 {{host} invites {guest} and one other person to her party.}\n                 other {{host} invites {guest} as one of the # people invited to her party.}}}\n              male   {{num_guests, plural, offset:1\n                  =0 {{host} does not give a party.}\n                  =1 {{host} invites {guest} to his party.}\n                  =2 {{host} invites {guest} and one other person to his party.}\n                 other {{host} invites {guest} as one of the # people invited to his party.}}}\n              other {{num_guests, plural, offset:1\n                  =0 {{host} does not give a party.}\n                  =1 {{host} invites {guest} to their party.}\n                  =2 {{host} invites {guest} and one other person to their party.}\n                 other {{host} invites {guest} as one of the # people invited to their party.}}}}\n            _MSG_;\n\n        $message = (new IntlFormatter())->formatIntl($chooseMessage, 'en', [\n            'gender_of_host' => 'male',\n            'num_guests' => 10,\n            'host' => 'Fabien',\n            'guest' => 'Guilherme',\n        ]);\n\n        $this->assertEquals('Fabien invites Guilherme as one of the 9 people invited to his party.', $message);\n    }\n\n    public static function provideDataForFormat()\n    {\n        return [\n            [\n                'There is one apple',\n                'There is one apple',\n                [],\n            ],\n            [\n                '4,560 monkeys on 123 trees make 37.073 monkeys per tree',\n                '{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree',\n                [4560, 123, 4560 / 123],\n            ],\n            [\n                '',\n                '',\n                [],\n            ],\n        ];\n    }\n\n    #[DataProvider('percentAndBracketsAreTrimmedProvider')]\n    public function testPercentsAndBracketsAreTrimmed(string $expected, string $message, array $parameters)\n    {\n        $formatter = new IntlFormatter();\n        $this->assertInstanceof(IntlFormatterInterface::class, $formatter);\n        $this->assertSame($expected, $formatter->formatIntl($message, 'en', $parameters));\n    }\n\n    public static function percentAndBracketsAreTrimmedProvider(): array\n    {\n        return [\n            ['Hello Fab', 'Hello {name}', ['name' => 'Fab']],\n            ['Hello Fab', 'Hello {name}', ['%name%' => 'Fab']],\n            ['Hello Fab', 'Hello {name}', ['{{ name }}' => 'Fab']],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/Formatter/MessageFormatterTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Formatter;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatter;\n\nclass MessageFormatterTest extends TestCase\n{\n    #[DataProvider('getTransMessages')]\n    public function testFormat($expected, $message, $parameters = [])\n    {\n        $this->assertEquals($expected, $this->getMessageFormatter()->format($message, 'en', $parameters));\n    }\n\n    public static function getTransMessages()\n    {\n        return [\n            [\n                'There is one apple',\n                'There is one apple',\n            ],\n            [\n                'There are 5 apples',\n                'There are %count% apples',\n                ['%count%' => 5],\n            ],\n            [\n                'There are 5 apples',\n                'There are {{count}} apples',\n                ['{{count}}' => 5],\n            ],\n        ];\n    }\n\n    private function getMessageFormatter()\n    {\n        return new MessageFormatter();\n    }\n}\n"
  },
  {
    "path": "Tests/IdentityTranslatorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse Symfony\\Component\\Translation\\IdentityTranslator;\nuse Symfony\\Contracts\\Translation\\Test\\TranslatorTest;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\nclass IdentityTranslatorTest extends TranslatorTest\n{\n    private string $defaultLocale;\n\n    protected function setUp(): void\n    {\n        parent::setUp();\n\n        $this->defaultLocale = \\Locale::getDefault();\n        \\Locale::setDefault('en');\n    }\n\n    protected function tearDown(): void\n    {\n        parent::tearDown();\n\n        \\Locale::setDefault($this->defaultLocale);\n    }\n\n    public function getTranslator(): TranslatorInterface\n    {\n        return new IdentityTranslator();\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/CsvFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\CsvFileLoader;\n\nclass CsvFileLoaderTest extends TestCase\n{\n    public function testLoad()\n    {\n        $loader = new CsvFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.csv';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadDoesNothingIfEmpty()\n    {\n        $loader = new CsvFileLoader();\n        $resource = __DIR__.'/../Fixtures/empty.csv';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals([], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new CsvFileLoader())->load(__DIR__.'/../Fixtures/not-exists.csv', 'en', 'domain1');\n    }\n\n    public function testLoadNonLocalResource()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new CsvFileLoader())->load('http://example.com/resources.csv', 'en', 'domain1');\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/IcuDatFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\IcuDatFileLoader;\n\n#[RequiresPhpExtension('intl')]\nclass IcuDatFileLoaderTest extends LocalizedTestCase\n{\n    public function testLoadInvalidResource()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new IcuDatFileLoader())->load(__DIR__.'/../Fixtures/resourcebundle/corrupted/resources', 'es', 'domain2');\n    }\n\n    public function testDatEnglishLoad()\n    {\n        // bundled resource is build using pkgdata command which at least in ICU 4.2 comes in extremely! buggy form\n        // you must specify an temporary build directory which is not the same as current directory and\n        // MUST reside on the same partition. pkgdata -p resources -T /srv -d.packagelist.txt\n        $loader = new IcuDatFileLoader();\n        $resource = __DIR__.'/../Fixtures/resourcebundle/dat/resources';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['symfony' => 'Symfony 2 is great'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource.'.dat')], $catalogue->getResources());\n    }\n\n    public function testDatFrenchLoad()\n    {\n        $loader = new IcuDatFileLoader();\n        $resource = __DIR__.'/../Fixtures/resourcebundle/dat/resources';\n        $catalogue = $loader->load($resource, 'fr', 'domain1');\n\n        $this->assertEquals(['symfony' => 'Symfony 2 est génial'], $catalogue->all('domain1'));\n        $this->assertEquals('fr', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource.'.dat')], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new IcuDatFileLoader())->load(__DIR__.'/../Fixtures/non-existing.txt', 'en', 'domain1');\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/IcuResFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse Symfony\\Component\\Config\\Resource\\DirectoryResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\IcuResFileLoader;\n\n#[RequiresPhpExtension('intl')]\nclass IcuResFileLoaderTest extends LocalizedTestCase\n{\n    public function testLoad()\n    {\n        // resource is build using genrb command\n        $loader = new IcuResFileLoader();\n        $resource = __DIR__.'/../Fixtures/resourcebundle/res';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new DirectoryResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new IcuResFileLoader())->load(__DIR__.'/../Fixtures/non-existing.txt', 'en', 'domain1');\n    }\n\n    public function testLoadInvalidResource()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new IcuResFileLoader())->load(__DIR__.'/../Fixtures/resourcebundle/corrupted', 'en', 'domain1');\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/IniFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\IniFileLoader;\n\nclass IniFileLoaderTest extends TestCase\n{\n    public function testLoad()\n    {\n        $loader = new IniFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.ini';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadDoesNothingIfEmpty()\n    {\n        $loader = new IniFileLoader();\n        $resource = __DIR__.'/../Fixtures/empty.ini';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals([], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new IniFileLoader())->load(__DIR__.'/../Fixtures/non-existing.ini', 'en', 'domain1');\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/JsonFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\JsonFileLoader;\n\nclass JsonFileLoaderTest extends TestCase\n{\n    public function testLoad()\n    {\n        $loader = new JsonFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.json';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadDoesNothingIfEmpty()\n    {\n        $loader = new JsonFileLoader();\n        $resource = __DIR__.'/../Fixtures/empty.json';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals([], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new JsonFileLoader())->load(__DIR__.'/../Fixtures/non-existing.json', 'en', 'domain1');\n    }\n\n    public function testParseException()\n    {\n        $this->expectException(InvalidResourceException::class);\n        $this->expectExceptionMessage('Error parsing JSON: Syntax error, malformed JSON');\n\n        (new JsonFileLoader())->load(__DIR__.'/../Fixtures/malformed.json', 'en', 'domain1');\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/LocalizedTestCase.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\n\nabstract class LocalizedTestCase extends TestCase\n{\n    protected function setUp(): void\n    {\n        if (!\\extension_loaded('intl')) {\n            $this->markTestSkipped('Extension intl is required.');\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/MoFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\MoFileLoader;\n\nclass MoFileLoaderTest extends TestCase\n{\n    public function testLoad()\n    {\n        $loader = new MoFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.mo';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadPlurals()\n    {\n        $loader = new MoFileLoader();\n        $resource = __DIR__.'/../Fixtures/plurals.mo';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals([\n            'foo|foos' => 'bar|bars',\n            '{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',\n        ], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new MoFileLoader())->load(__DIR__.'/../Fixtures/non-existing.mo', 'en', 'domain1');\n    }\n\n    public function testLoadInvalidResource()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new MoFileLoader())->load(__DIR__.'/../Fixtures/empty.mo', 'en', 'domain1');\n    }\n\n    public function testLoadEmptyTranslation()\n    {\n        $loader = new MoFileLoader();\n        $resource = __DIR__.'/../Fixtures/empty-translation.mo';\n        $catalogue = $loader->load($resource, 'en', 'message');\n\n        $this->assertEquals([], $catalogue->all('message'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/PhpFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\PhpFileLoader;\n\nclass PhpFileLoaderTest extends TestCase\n{\n    public function testLoad()\n    {\n        $loader = new PhpFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.php';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new PhpFileLoader())->load(__DIR__.'/../Fixtures/non-existing.php', 'en', 'domain1');\n    }\n\n    public function testLoadThrowsAnExceptionIfFileNotLocal()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new PhpFileLoader())->load('http://example.com/resources.php', 'en', 'domain1');\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/PoFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\PoFileLoader;\n\nclass PoFileLoaderTest extends TestCase\n{\n    public function testLoad()\n    {\n        $loader = new PoFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.po';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar', 'bar' => 'foo'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadPlurals()\n    {\n        $loader = new PoFileLoader();\n        $resource = __DIR__.'/../Fixtures/plurals.po';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals([\n            'foo|foos' => 'bar|bars',\n            '{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',\n        ], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadDoesNothingIfEmpty()\n    {\n        $loader = new PoFileLoader();\n        $resource = __DIR__.'/../Fixtures/empty.po';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals([], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new PoFileLoader())->load(__DIR__.'/../Fixtures/non-existing.po', 'en', 'domain1');\n    }\n\n    public function testLoadEmptyTranslation()\n    {\n        $loader = new PoFileLoader();\n        $resource = __DIR__.'/../Fixtures/empty-translation.po';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => ''], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testEscapedId()\n    {\n        $loader = new PoFileLoader();\n        $resource = __DIR__.'/../Fixtures/escaped-id.po';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $messages = $catalogue->all('domain1');\n        $this->assertArrayHasKey('escaped \"foo\"', $messages);\n        $this->assertEquals('escaped \"bar\"', $messages['escaped \"foo\"']);\n    }\n\n    public function testEscapedIdPlurals()\n    {\n        $loader = new PoFileLoader();\n        $resource = __DIR__.'/../Fixtures/escaped-id-plurals.po';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $messages = $catalogue->all('domain1');\n        $this->assertArrayHasKey('escaped \"foo\"|escaped \"foos\"', $messages);\n        $this->assertEquals('escaped \"bar\"|escaped \"bars\"', $messages['escaped \"foo\"|escaped \"foos\"']);\n    }\n\n    public function testSkipFuzzyTranslations()\n    {\n        $loader = new PoFileLoader();\n        $resource = __DIR__.'/../Fixtures/fuzzy-translations.po';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $messages = $catalogue->all('domain1');\n        $this->assertArrayHasKey('foo1', $messages);\n        $this->assertArrayNotHasKey('foo2', $messages);\n        $this->assertArrayHasKey('foo3', $messages);\n    }\n\n    public function testMissingPlurals()\n    {\n        $loader = new PoFileLoader();\n        $resource = __DIR__.'/../Fixtures/missing-plurals.po';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals([\n            'foo|foos' => '-|bar|-|bars',\n        ], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/QtFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\QtFileLoader;\n\nclass QtFileLoaderTest extends TestCase\n{\n    public function testLoad()\n    {\n        $loader = new QtFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.ts';\n        $catalogue = $loader->load($resource, 'en', 'resources');\n\n        $this->assertEquals([\n            'foo' => 'bar',\n            'foo_bar' => 'foobar',\n            'bar_foo' => 'barfoo',\n        ], $catalogue->all('resources'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new QtFileLoader())->load(__DIR__.'/../Fixtures/non-existing.ts', 'en', 'domain1');\n    }\n\n    public function testLoadNonLocalResource()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new QtFileLoader())->load('http://domain1.com/resources.ts', 'en', 'domain1');\n    }\n\n    public function testLoadInvalidResource()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new QtFileLoader())->load(__DIR__.'/../Fixtures/invalid-xml-resources.xlf', 'en', 'domain1');\n    }\n\n    public function testLoadEmptyResource()\n    {\n        $resource = __DIR__.'/../Fixtures/empty.xlf';\n\n        $this->expectException(InvalidResourceException::class);\n        $this->expectExceptionMessage(\\sprintf('Unable to load \"%s\".', $resource));\n\n        (new QtFileLoader())->load($resource, 'en', 'domain1');\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/XliffFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\XliffFileLoader;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\nclass XliffFileLoaderTest extends TestCase\n{\n    public function testLoadFile()\n    {\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.xlf';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n        $this->assertSame([], libxml_get_errors());\n        $this->assertContainsOnlyString($catalogue->all('domain1'));\n    }\n\n    public function testLoadRawXliff()\n    {\n        $loader = new XliffFileLoader();\n        $resource = <<<XLIFF\n            <?xml version=\"1.0\" encoding=\"utf-8\"?>\n            <xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n              <file source-language=\"en\" datatype=\"plaintext\" original=\"file.ext\">\n                <body>\n                  <trans-unit id=\"1\">\n                    <source>foo</source>\n                    <target>bar</target>\n                  </trans-unit>\n                  <trans-unit id=\"2\">\n                    <source>extra</source>\n                  </trans-unit>\n                  <trans-unit id=\"3\">\n                    <source>key</source>\n                    <target></target>\n                  </trans-unit>\n                  <trans-unit id=\"4\">\n                    <source>test</source>\n                    <target state=\"needs-translation\">with</target>\n                    <note>note</note>\n                  </trans-unit>\n                  <trans-unit id=\"5\">\n                    <source>baz</source>\n                    <target state=\"needs-translation\">baz</target>\n                  </trans-unit>\n                  <trans-unit id=\"6\" resname=\"buz\">\n                    <source>baz</source>\n                    <target state=\"needs-translation\">buz</target>\n                  </trans-unit>\n                </body>\n              </file>\n            </xliff>\n            XLIFF;\n\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertSame([], libxml_get_errors());\n        $this->assertContainsOnlyString($catalogue->all('domain1'));\n        $this->assertSame(['foo', 'extra', 'key', 'test'], array_keys($catalogue->all('domain1')));\n    }\n\n    public function testLoadWithInternalErrorsEnabled()\n    {\n        $internalErrors = libxml_use_internal_errors(true);\n\n        $this->assertSame([], libxml_get_errors());\n\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.xlf';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n        $this->assertSame([], libxml_get_errors());\n\n        libxml_clear_errors();\n        libxml_use_internal_errors($internalErrors);\n    }\n\n    public function testLoadWithExternalEntitiesDisabled()\n    {\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.xlf';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadWithResname()\n    {\n        $loader = new XliffFileLoader();\n        $catalogue = $loader->load(__DIR__.'/../Fixtures/resname.xlf', 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo', 'qux' => 'qux source'], $catalogue->all('domain1'));\n    }\n\n    public function testIncompleteResource()\n    {\n        $loader = new XliffFileLoader();\n        $catalogue = $loader->load(__DIR__.'/../Fixtures/resources.xlf', 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar', 'extra' => 'extra', 'key' => '', 'test' => 'with'], $catalogue->all('domain1'));\n    }\n\n    public function testEncoding()\n    {\n        $loader = new XliffFileLoader();\n        $catalogue = $loader->load(__DIR__.'/../Fixtures/encoding.xlf', 'en', 'domain1');\n\n        $this->assertEquals(mb_convert_encoding('föö', 'ISO-8859-1', 'UTF-8'), $catalogue->get('bar', 'domain1'));\n        $this->assertEquals(mb_convert_encoding('bär', 'ISO-8859-1', 'UTF-8'), $catalogue->get('foo', 'domain1'));\n        $this->assertEquals(\n            [\n                'source' => 'foo',\n                'notes' => [['content' => mb_convert_encoding('bäz', 'ISO-8859-1', 'UTF-8')]],\n                'id' => '1',\n                'file' => [\n                    'original' => 'file.ext',\n                ],\n            ],\n            $catalogue->getMetadata('foo', 'domain1')\n        );\n    }\n\n    public function testTargetAttributesAreStoredCorrectly()\n    {\n        $loader = new XliffFileLoader();\n        $catalogue = $loader->load(__DIR__.'/../Fixtures/with-attributes.xlf', 'en', 'domain1');\n\n        $metadata = $catalogue->getMetadata('foo', 'domain1');\n        $this->assertEquals('translated', $metadata['target-attributes']['state']);\n    }\n\n    public function testLoadInvalidResource()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new XliffFileLoader())->load(__DIR__.'/../Fixtures/resources.php', 'en', 'domain1');\n    }\n\n    public function testLoadResourceDoesNotValidate()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new XliffFileLoader())->load(__DIR__.'/../Fixtures/non-valid.xlf', 'en', 'domain1');\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $this->expectException(NotFoundResourceException::class);\n\n        (new XliffFileLoader())->load(__DIR__.'/../Fixtures/non-existing.xlf', 'en', 'domain1');\n    }\n\n    public function testLoadThrowsAnExceptionIfFileNotLocal()\n    {\n        $this->expectException(InvalidResourceException::class);\n\n        (new XliffFileLoader())->load('http://example.com/resources.xlf', 'en', 'domain1');\n    }\n\n    public function testDocTypeIsNotAllowed()\n    {\n        $this->expectException(InvalidResourceException::class);\n        $this->expectExceptionMessage('Document types are not allowed.');\n\n        (new XliffFileLoader())->load(__DIR__.'/../Fixtures/withdoctype.xlf', 'en', 'domain1');\n    }\n\n    public function testParseEmptyFile()\n    {\n        $resource = __DIR__.'/../Fixtures/empty.xlf';\n\n        $this->expectException(InvalidResourceException::class);\n        $this->expectExceptionMessage(\\sprintf('Unable to load \"%s\":', $resource));\n\n        (new XliffFileLoader())->load($resource, 'en', 'domain1');\n    }\n\n    public function testLoadNotes()\n    {\n        $loader = new XliffFileLoader();\n        $catalogue = $loader->load(__DIR__.'/../Fixtures/withnote.xlf', 'en', 'domain1');\n\n        $this->assertEquals(\n            [\n                'source' => 'foo',\n                'notes' => [['priority' => 1, 'content' => 'foo']],\n                'id' => '1',\n                'file' => [\n                    'original' => 'file.ext',\n                ],\n            ],\n            $catalogue->getMetadata('foo', 'domain1')\n        );\n        // message without target\n        $this->assertEquals(\n            [\n                'source' => 'extrasource',\n                'notes' => [['content' => 'bar', 'from' => 'foo']],\n                'id' => '2',\n                'file' => [\n                    'original' => 'file.ext',\n                ],\n            ],\n            $catalogue->getMetadata('extra', 'domain1')\n        );\n        // message with empty target\n        $this->assertEquals(\n            [\n                'source' => 'key',\n                'notes' => [\n                    ['content' => 'baz'],\n                    ['priority' => 2, 'from' => 'bar', 'content' => 'qux'],\n                ],\n                'id' => '123',\n                'file' => [\n                    'original' => 'file.ext',\n                ],\n            ],\n            $catalogue->getMetadata('key', 'domain1')\n        );\n    }\n\n    public function testLoadVersion2()\n    {\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources-2.0.xlf';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n        $this->assertSame([], libxml_get_errors());\n\n        $domains = $catalogue->all();\n        $this->assertCount(3, $domains['domain1']);\n        $this->assertContainsOnlyString($catalogue->all('domain1'));\n\n        // target attributes\n        $this->assertEquals(['target-attributes' => ['order' => 1]], $catalogue->getMetadata('bar', 'domain1'));\n    }\n\n    public function testLoadVersion21()\n    {\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources-2.1.xlf';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n        $this->assertSame([], libxml_get_errors());\n\n        $domains = $catalogue->all();\n        $this->assertCount(3, $domains['domain1']);\n        $this->assertContainsOnlyString($catalogue->all('domain1'));\n\n        // target attributes\n        $this->assertEquals(['target-attributes' => ['order' => 1]], $catalogue->getMetadata('bar', 'domain1'));\n    }\n\n    public function testLoadVersion22()\n    {\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources-2.2.xlf';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n        $this->assertSame([], libxml_get_errors());\n\n        $domains = $catalogue->all();\n        $this->assertCount(3, $domains['domain1']);\n        $this->assertContainsOnlyString($catalogue->all('domain1'));\n\n        // target attributes\n        $this->assertEquals(['target-attributes' => ['order' => 1]], $catalogue->getMetadata('bar', 'domain1'));\n    }\n\n    public function testLoadVersion2WithNoteMeta()\n    {\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources-notes-meta.xlf';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n        $this->assertSame([], libxml_get_errors());\n\n        // test for \"foo\" metadata\n        $this->assertTrue($catalogue->defines('foo', 'domain1'));\n        $metadata = $catalogue->getMetadata('foo', 'domain1');\n        $this->assertNotEmpty($metadata);\n        $this->assertCount(3, $metadata['notes']);\n\n        $this->assertEquals('state', $metadata['notes'][0]['category']);\n        $this->assertEquals('new', $metadata['notes'][0]['content']);\n\n        $this->assertEquals('approved', $metadata['notes'][1]['category']);\n        $this->assertEquals('true', $metadata['notes'][1]['content']);\n\n        $this->assertEquals('section', $metadata['notes'][2]['category']);\n        $this->assertEquals('1', $metadata['notes'][2]['priority']);\n        $this->assertEquals('user login', $metadata['notes'][2]['content']);\n\n        // test for \"baz\" metadata\n        $this->assertTrue($catalogue->defines('baz', 'domain1'));\n        $metadata = $catalogue->getMetadata('baz', 'domain1');\n        $this->assertNotEmpty($metadata);\n        $this->assertCount(2, $metadata['notes']);\n\n        $this->assertEquals('x', $metadata['notes'][0]['id']);\n        $this->assertEquals('x_content', $metadata['notes'][0]['content']);\n\n        $this->assertEquals('target', $metadata['notes'][1]['appliesTo']);\n        $this->assertEquals('quality', $metadata['notes'][1]['category']);\n        $this->assertEquals('Fuzzy', $metadata['notes'][1]['content']);\n    }\n\n    public function testLoadVersion2WithMultiSegmentUnit()\n    {\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources-2.0-multi-segment-unit.xlf';\n        $catalog = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertSame('en', $catalog->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalog->getResources());\n        $this->assertFalse(libxml_get_last_error());\n\n        // test for \"foo\" metadata\n        $this->assertTrue($catalog->defines('foo', 'domain1'));\n        $metadata = $catalog->getMetadata('foo', 'domain1');\n        $this->assertNotEmpty($metadata);\n        $this->assertCount(1, $metadata['notes']);\n\n        $this->assertSame('processed', $metadata['notes'][0]['category']);\n        $this->assertSame('true', $metadata['notes'][0]['content']);\n\n        // test for \"bar\" metadata\n        $this->assertTrue($catalog->defines('bar', 'domain1'));\n        $metadata = $catalog->getMetadata('bar', 'domain1');\n        $this->assertNotEmpty($metadata);\n        $this->assertCount(1, $metadata['notes']);\n\n        $this->assertSame('processed', $metadata['notes'][0]['category']);\n        $this->assertSame('true', $metadata['notes'][0]['content']);\n    }\n\n    public function testLoadWithMultipleFileNodes()\n    {\n        $loader = new XliffFileLoader();\n        $catalogue = $loader->load(__DIR__.'/../Fixtures/resources-multi-files.xlf', 'en', 'domain1');\n\n        $this->assertEquals(\n            [\n                'source' => 'foo',\n                'id' => '1',\n                'file' => [\n                    'original' => 'file.ext',\n                ],\n            ],\n            $catalogue->getMetadata('foo', 'domain1')\n        );\n        $this->assertEquals(\n            [\n                'source' => 'test',\n                'notes' => [['content' => 'note']],\n                'id' => '4',\n                'file' => [\n                    'original' => 'otherfile.ext',\n                ],\n            ],\n            $catalogue->getMetadata('test', 'domain1')\n        );\n    }\n\n    public function testLoadVersion2WithName()\n    {\n        $loader = new XliffFileLoader();\n        $catalogue = $loader->load(__DIR__.'/../Fixtures/resources-2.0-name.xlf', 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo', 'qux' => 'qux source'], $catalogue->all('domain1'));\n    }\n\n    public function testLoadVersion2WithSegmentAttributes()\n    {\n        $loader = new XliffFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources-2.0-segment-attributes.xlf';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        // test for \"foo\" metadata\n        $this->assertTrue($catalogue->defines('foo', 'domain1'));\n        $metadata = $catalogue->getMetadata('foo', 'domain1');\n        $this->assertNotEmpty($metadata);\n        $this->assertCount(1, $metadata['segment-attributes']);\n        $this->assertArrayHasKey('state', $metadata['segment-attributes']);\n        $this->assertSame('translated', $metadata['segment-attributes']['state']);\n\n        // test for \"key\" metadata\n        $this->assertTrue($catalogue->defines('key', 'domain1'));\n        $metadata = $catalogue->getMetadata('key', 'domain1');\n        $this->assertNotEmpty($metadata);\n        $this->assertCount(2, $metadata['segment-attributes']);\n        $this->assertArrayHasKey('state', $metadata['segment-attributes']);\n        $this->assertSame('translated', $metadata['segment-attributes']['state']);\n        $this->assertArrayHasKey('subState', $metadata['segment-attributes']);\n        $this->assertSame('My Value', $metadata['segment-attributes']['subState']);\n    }\n\n    public function testLoadVersion22WithPgsPlural()\n    {\n        $catalogue = new XliffFileLoader()->load(__DIR__.'/../Fixtures/resources-2.2-pgs-plural.xlf', 'fr', 'domain1');\n\n        $intlDomain = 'domain1'.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n\n        $this->assertTrue($catalogue->defines('file_deleted', $intlDomain));\n        $this->assertSame(\n            '{file_count, plural, =0 {Vous n\\'avez supprimé aucun fichier.} =1 {Vous avez supprimé un fichier.} other {Vous avez supprimé # fichiers.}}',\n            $catalogue->get('file_deleted', $intlDomain)\n        );\n\n        $this->assertSame('plural:file_count', $catalogue->getMetadata('file_deleted', $intlDomain)['pgs-switch']);\n    }\n\n    public function testLoadVersion22WithPgsGender()\n    {\n        $catalogue = new XliffFileLoader()->load(__DIR__.'/../Fixtures/resources-2.2-pgs-gender.xlf', 'fr', 'domain1');\n\n        $intlDomain = 'domain1'.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n\n        $this->assertTrue($catalogue->defines('party_invite', $intlDomain));\n        $this->assertSame(\n            '{host_gender, select, feminine {Vous êtes invité à sa fête} masculine {Vous êtes invité à sa fête} other {Vous êtes invité à leur fête}}',\n            $catalogue->get('party_invite', $intlDomain)\n        );\n    }\n\n    public function testLoadVersion22WithPgsCombined()\n    {\n        $catalogue = new XliffFileLoader()->load(__DIR__.'/../Fixtures/resources-2.2-pgs-combined.xlf', 'fr', 'domain1');\n\n        $intlDomain = 'domain1'.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n\n        $this->assertTrue($catalogue->defines('party_host', $intlDomain));\n\n        $expected = <<<ICU\n            {host_gender, select, feminine {{guest_count, plural, =0 {{host_name} n'a invité personne à sa fête.} =1 {{host_name} a invité un convive à sa fête.} other {{host_name} a invité # convives à sa fête.}}} masculine {{guest_count, plural, =0 {{host_name} n'a invité personne à sa fête.} =1 {{host_name} a invité un convive à sa fête.} other {{host_name} a invité # convives à sa fête.}}} other {{guest_count, plural, =0 {{host_name} n'a invité personne à leur fête.} =1 {{host_name} a invité un convive à leur fête.} other {{host_name} a invité # convives à leur fête.}}}}\n            ICU;\n\n        $this->assertSame($expected, $catalogue->get('party_host', $intlDomain));\n    }\n}\n"
  },
  {
    "path": "Tests/Loader/YamlFileLoaderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Loader;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\FileResource;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Loader\\YamlFileLoader;\n\nclass YamlFileLoaderTest extends TestCase\n{\n    public function testLoad()\n    {\n        $loader = new YamlFileLoader();\n        $resource = __DIR__.'/../Fixtures/resources.yml';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonStringMessages()\n    {\n        $loader = new YamlFileLoader();\n        $resource = __DIR__.'/../Fixtures/non-string.yml';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertSame(['root.foo2' => '', 'root.bar' => 'bar'], $catalogue->all('domain1'));\n    }\n\n    public function testLoadDoesNothingIfEmpty()\n    {\n        $loader = new YamlFileLoader();\n        $resource = __DIR__.'/../Fixtures/empty.yml';\n        $catalogue = $loader->load($resource, 'en', 'domain1');\n\n        $this->assertEquals([], $catalogue->all('domain1'));\n        $this->assertEquals('en', $catalogue->getLocale());\n        $this->assertEquals([new FileResource($resource)], $catalogue->getResources());\n    }\n\n    public function testLoadNonExistingResource()\n    {\n        $loader = new YamlFileLoader();\n        $resource = __DIR__.'/../Fixtures/non-existing.yml';\n\n        $this->expectException(NotFoundResourceException::class);\n\n        $loader->load($resource, 'en', 'domain1');\n    }\n\n    public function testLoadThrowsAnExceptionIfFileNotLocal()\n    {\n        $loader = new YamlFileLoader();\n        $resource = 'http://example.com/resources.yml';\n\n        $this->expectException(InvalidResourceException::class);\n\n        $loader->load($resource, 'en', 'domain1');\n    }\n\n    public function testLoadThrowsAnExceptionIfNotAnArray()\n    {\n        $loader = new YamlFileLoader();\n        $resource = __DIR__.'/../Fixtures/non-valid.yml';\n\n        $this->expectException(InvalidResourceException::class);\n\n        $loader->load($resource, 'en', 'domain1');\n    }\n}\n"
  },
  {
    "path": "Tests/LocaleFallbackProviderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\LocaleFallbackProvider;\n\nclass LocaleFallbackProviderTest extends TestCase\n{\n    public function testConstructorValidatesLocales()\n    {\n        $this->expectException(InvalidArgumentException::class);\n\n        new LocaleFallbackProvider(['en', 'invalid locale!']);\n    }\n\n    public function testComputeFallbackLocalesValidatesLocale()\n    {\n        $this->expectException(InvalidArgumentException::class);\n\n        (new LocaleFallbackProvider())->computeFallbackLocales('invalid locale!');\n    }\n\n    public function testComputeFallbackLocalesShortensSubTags()\n    {\n        $provider = new LocaleFallbackProvider();\n\n        $this->assertSame(['en'], $provider->computeFallbackLocales('en_US'));\n    }\n\n    #[DataProvider('provideIcuParentLocales')]\n    public function testComputeFallbackLocalesUsesIcuParents(string $locale, array $expected)\n    {\n        $provider = new LocaleFallbackProvider();\n\n        $this->assertSame($expected, $provider->computeFallbackLocales($locale));\n    }\n\n    public static function provideIcuParentLocales(): array\n    {\n        return [\n            'ICU root parent terminates chain' => ['az_Cyrl', []],\n            'ICU explicit parent chain' => ['en_150', ['en_001', 'en']],\n            'locale sub-tag shortening' => ['sl_Latn_IT', ['sl_Latn', 'sl']],\n        ];\n    }\n\n    public function testComputeFallbackLocalesAppendsUltimateFallbacks()\n    {\n        $provider = new LocaleFallbackProvider(['de', 'fr']);\n\n        $result = $provider->computeFallbackLocales('en_US');\n\n        $this->assertSame(['en', 'de', 'fr'], $result);\n    }\n\n    public function testComputeFallbackLocalesExcludesOriginFromUltimateFallbacks()\n    {\n        $provider = new LocaleFallbackProvider(['en_US', 'fr']);\n\n        $result = $provider->computeFallbackLocales('en_US');\n\n        $this->assertSame(['en', 'fr'], $result);\n    }\n\n    public function testComputeFallbackLocalesReturnsUniqueLocales()\n    {\n        $provider = new LocaleFallbackProvider(['en', 'fr']);\n\n        // en_US -> en (sub-tag shortening) -> en (ultimate fallback, duplicate)\n        $result = $provider->computeFallbackLocales('en_US');\n\n        $this->assertSame(['en', 'fr'], $result);\n    }\n\n    public function testComputeFallbackLocalesForRootIcuParentReturnsEmpty()\n    {\n        // az_Cyrl has ICU explicit parent 'root', meaning no fallback chain\n        $provider = new LocaleFallbackProvider();\n\n        $this->assertSame([], $provider->computeFallbackLocales('az_Cyrl'));\n    }\n\n    #[DataProvider('provideValidLocales')]\n    public function testValidateLocalePassesForValidLocales(string $locale)\n    {\n        LocaleFallbackProvider::validateLocale($locale);\n\n        $this->addToAssertionCount(1);\n    }\n\n    public static function provideValidLocales(): array\n    {\n        return [\n            ['en'],\n            ['en_US'],\n            ['en-US'],\n            ['fr_FR.UTF8'],\n            ['sr@latin'],\n            [''],\n        ];\n    }\n\n    #[DataProvider('provideInvalidLocales')]\n    public function testValidateLocaleThrowsForInvalidLocales(string $locale)\n    {\n        $this->expectException(InvalidArgumentException::class);\n\n        LocaleFallbackProvider::validateLocale($locale);\n    }\n\n    public static function provideInvalidLocales(): array\n    {\n        return [\n            ['fr FR'],\n            ['français'],\n            ['fr+en'],\n            ['utf#8'],\n            ['fr&en'],\n            ['fr~FR'],\n            [' fr'],\n            ['fr '],\n            ['fr*'],\n            ['fr/FR'],\n            ['fr\\\\FR'],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/LocaleSwitcherTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Routing\\RequestContext;\nuse Symfony\\Component\\Translation\\LocaleSwitcher;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\n\n#[RequiresPhpExtension('intl')]\nclass LocaleSwitcherTest extends TestCase\n{\n    private string $intlLocale;\n\n    protected function setUp(): void\n    {\n        $this->intlLocale = \\Locale::getDefault();\n    }\n\n    protected function tearDown(): void\n    {\n        \\Locale::setDefault($this->intlLocale);\n    }\n\n    public function testCanSwitchLocale()\n    {\n        \\Locale::setDefault('en');\n\n        $service = new DummyLocaleAware('en');\n        $switcher = new LocaleSwitcher('en', [$service]);\n\n        $this->assertSame('en', \\Locale::getDefault());\n        $this->assertSame('en', $service->getLocale());\n        $this->assertSame('en', $switcher->getLocale());\n\n        $switcher->setLocale('fr');\n\n        $this->assertSame('fr', \\Locale::getDefault());\n        $this->assertSame('fr', $service->getLocale());\n        $this->assertSame('fr', $switcher->getLocale());\n    }\n\n    public function testCanSwitchLocaleForCallback()\n    {\n        \\Locale::setDefault('en');\n\n        $service = new DummyLocaleAware('en');\n        $switcher = new LocaleSwitcher('en', [$service]);\n\n        $this->assertSame('en', \\Locale::getDefault());\n        $this->assertSame('en', $service->getLocale());\n        $this->assertSame('en', $switcher->getLocale());\n\n        $switcher->runWithLocale('fr', function (string $locale) use ($switcher, $service) {\n            $this->assertSame('fr', \\Locale::getDefault());\n            $this->assertSame('fr', $service->getLocale());\n            $this->assertSame('fr', $switcher->getLocale());\n            $this->assertSame('fr', $locale);\n        });\n\n        $this->assertSame('en', \\Locale::getDefault());\n        $this->assertSame('en', $service->getLocale());\n        $this->assertSame('en', $switcher->getLocale());\n    }\n\n    public function testWithRequestContext()\n    {\n        $context = new RequestContext();\n        $service = new LocaleSwitcher('en', [], $context);\n\n        $this->assertSame('en', $service->getLocale());\n\n        $service->setLocale('fr');\n\n        $this->assertSame('fr', $service->getLocale());\n        $this->assertSame('fr', $context->getParameter('_locale'));\n\n        $service->reset();\n\n        $this->assertSame('en', $service->getLocale());\n        $this->assertSame('en', $context->getParameter('_locale'));\n    }\n}\n\nclass DummyLocaleAware implements LocaleAwareInterface\n{\n    public function __construct(private string $locale)\n    {\n    }\n\n    public function setLocale(string $locale): void\n    {\n        $this->locale = $locale;\n    }\n\n    public function getLocale(): string\n    {\n        return $this->locale;\n    }\n}\n"
  },
  {
    "path": "Tests/LoggingTranslatorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\Translation\\LoggingTranslator;\nuse Symfony\\Component\\Translation\\Translator;\n\nclass LoggingTranslatorTest extends TestCase\n{\n    public function testTransWithNoTranslationIsLogged()\n    {\n        $logger = $this->createMock(LoggerInterface::class);\n        $logger->expects($this->exactly(1))\n            ->method('warning')\n            ->with('Translation not found.')\n        ;\n\n        $translator = new Translator('ar');\n        $loggableTranslator = new LoggingTranslator($translator, $logger);\n        $loggableTranslator->trans('bar');\n    }\n}\n"
  },
  {
    "path": "Tests/MessageCatalogueTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\ResourceInterface;\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\nclass MessageCatalogueTest extends TestCase\n{\n    public function testGetLocale()\n    {\n        $catalogue = new MessageCatalogue('en');\n\n        $this->assertEquals('en', $catalogue->getLocale());\n    }\n\n    public function testGetDomains()\n    {\n        $catalogue = new MessageCatalogue('en', ['domain1' => [], 'domain2' => [], 'domain2+intl-icu' => [], 'domain3+intl-icu' => []]);\n\n        $this->assertEquals(['domain1', 'domain2', 'domain3'], $catalogue->getDomains());\n    }\n\n    public function testAll()\n    {\n        $catalogue = new MessageCatalogue('en', $messages = ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar']]);\n\n        $this->assertEquals(['foo' => 'foo'], $catalogue->all('domain1'));\n        $this->assertEquals([], $catalogue->all('domain88'));\n        $this->assertEquals($messages, $catalogue->all());\n\n        $messages = ['domain1+intl-icu' => ['foo' => 'bar']] + $messages + [\n            'domain2+intl-icu' => ['bar' => 'foo'],\n            'domain3+intl-icu' => ['biz' => 'biz'],\n        ];\n        $catalogue = new MessageCatalogue('en', $messages);\n\n        $this->assertEquals(['foo' => 'bar'], $catalogue->all('domain1'));\n        $this->assertEquals(['bar' => 'foo'], $catalogue->all('domain2'));\n        $this->assertEquals(['biz' => 'biz'], $catalogue->all('domain3'));\n\n        $messages = [\n            'domain1' => ['foo' => 'bar'],\n            'domain2' => ['bar' => 'foo'],\n            'domain3' => ['biz' => 'biz'],\n        ];\n        $this->assertEquals($messages, $catalogue->all());\n    }\n\n    public function testAllIntlIcu()\n    {\n        $messages = [\n            'domain1+intl-icu' => ['foo' => 'bar'],\n            'domain2+intl-icu' => ['bar' => 'foo'],\n            'domain2' => ['biz' => 'biz'],\n        ];\n        $catalogue = new MessageCatalogue('en', $messages);\n\n        // separated domains\n        $this->assertSame(['foo' => 'bar'], $catalogue->all('domain1+intl-icu'));\n        $this->assertSame(['bar' => 'foo'], $catalogue->all('domain2+intl-icu'));\n\n        // merged, intl-icu ignored\n        $this->assertSame(['bar' => 'foo', 'biz' => 'biz'], $catalogue->all('domain2'));\n\n        // intl-icu ignored\n        $messagesExpected = [\n            'domain1' => ['foo' => 'bar'],\n            'domain2' => ['bar' => 'foo', 'biz' => 'biz'],\n        ];\n        $this->assertSame($messagesExpected, $catalogue->all());\n    }\n\n    public function testHas()\n    {\n        $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2+intl-icu' => ['bar' => 'bar']]);\n\n        $this->assertTrue($catalogue->has('foo', 'domain1'));\n        $this->assertTrue($catalogue->has('bar', 'domain2'));\n        $this->assertFalse($catalogue->has('bar', 'domain1'));\n        $this->assertFalse($catalogue->has('foo', 'domain88'));\n    }\n\n    public function testGetSet()\n    {\n        $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar'], 'domain2+intl-icu' => ['bar' => 'foo']]);\n        $catalogue->set('foo1', 'foo1', 'domain1');\n\n        $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));\n        $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));\n        $this->assertEquals('foo', $catalogue->get('bar', 'domain2'));\n    }\n\n    public function testAdd()\n    {\n        $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar']]);\n        $catalogue->add(['foo1' => 'foo1'], 'domain1');\n\n        $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));\n        $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));\n\n        $catalogue->add(['foo' => 'bar'], 'domain1');\n        $this->assertEquals('bar', $catalogue->get('foo', 'domain1'));\n        $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));\n\n        $catalogue->add(['foo' => 'bar'], 'domain88');\n        $this->assertEquals('bar', $catalogue->get('foo', 'domain88'));\n    }\n\n    public function testAddIntlIcu()\n    {\n        $catalogue = new MessageCatalogue('en', ['domain1+intl-icu' => ['foo' => 'foo']]);\n        $catalogue->add(['foo1' => 'foo1'], 'domain1');\n        $catalogue->add(['foo' => 'bar'], 'domain1');\n\n        $this->assertSame('bar', $catalogue->get('foo', 'domain1'));\n        $this->assertSame('foo1', $catalogue->get('foo1', 'domain1'));\n    }\n\n    public function testReplace()\n    {\n        $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain1+intl-icu' => ['bar' => 'bar']]);\n        $catalogue->replace($messages = ['foo1' => 'foo1'], 'domain1');\n\n        $this->assertEquals($messages, $catalogue->all('domain1'));\n    }\n\n    public function testAddCatalogue()\n    {\n        $r = $this->createStub(ResourceInterface::class);\n        $r->method('__toString')->willReturn('r');\n\n        $r1 = $this->createStub(ResourceInterface::class);\n        $r1->method('__toString')->willReturn('r1');\n\n        $catalogue = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo']]);\n        $catalogue->addResource($r);\n\n        $catalogue1 = new MessageCatalogue('en', ['domain1' => ['foo1' => 'foo1'], 'domain2+intl-icu' => ['bar' => 'bar']]);\n        $catalogue1->addResource($r1);\n\n        $catalogue->addCatalogue($catalogue1);\n\n        $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));\n        $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));\n        $this->assertEquals('bar', $catalogue->get('bar', 'domain2'));\n        $this->assertEquals('bar', $catalogue->get('bar', 'domain2+intl-icu'));\n\n        $this->assertEquals([$r, $r1], $catalogue->getResources());\n    }\n\n    public function testAddFallbackCatalogue()\n    {\n        $r = $this->createStub(ResourceInterface::class);\n        $r->method('__toString')->willReturn('r');\n\n        $r1 = $this->createStub(ResourceInterface::class);\n        $r1->method('__toString')->willReturn('r1');\n\n        $r2 = $this->createStub(ResourceInterface::class);\n        $r2->method('__toString')->willReturn('r2');\n\n        $catalogue = new MessageCatalogue('fr_FR', ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar']]);\n        $catalogue->addResource($r);\n\n        $catalogue1 = new MessageCatalogue('fr', ['domain1' => ['foo' => 'bar', 'foo1' => 'foo1']]);\n        $catalogue1->addResource($r1);\n\n        $catalogue2 = new MessageCatalogue('en');\n        $catalogue2->addResource($r2);\n\n        $catalogue->addFallbackCatalogue($catalogue1);\n        $catalogue1->addFallbackCatalogue($catalogue2);\n\n        $this->assertEquals('foo', $catalogue->get('foo', 'domain1'));\n        $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));\n\n        $this->assertEquals([$r, $r1, $r2], $catalogue->getResources());\n    }\n\n    public function testAddFallbackCatalogueWithParentCircularReference()\n    {\n        $main = new MessageCatalogue('en_US');\n        $fallback = new MessageCatalogue('fr_FR');\n\n        $fallback->addFallbackCatalogue($main);\n\n        $this->expectException(LogicException::class);\n\n        $main->addFallbackCatalogue($fallback);\n    }\n\n    public function testAddFallbackCatalogueWithFallbackCircularReference()\n    {\n        $fr = new MessageCatalogue('fr');\n        $en = new MessageCatalogue('en');\n        $es = new MessageCatalogue('es');\n\n        $fr->addFallbackCatalogue($en);\n        $es->addFallbackCatalogue($en);\n\n        $this->expectException(LogicException::class);\n\n        $en->addFallbackCatalogue($fr);\n    }\n\n    public function testAddCatalogueWhenLocaleIsNotTheSameAsTheCurrentOne()\n    {\n        $catalogue = new MessageCatalogue('en');\n\n        $this->expectException(LogicException::class);\n\n        $catalogue->addCatalogue(new MessageCatalogue('fr', []));\n    }\n\n    public function testGetAddResource()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $r = $this->createStub(ResourceInterface::class);\n        $r->method('__toString')->willReturn('r');\n        $catalogue->addResource($r);\n        $catalogue->addResource($r);\n        $r1 = $this->createStub(ResourceInterface::class);\n        $r1->method('__toString')->willReturn('r1');\n        $catalogue->addResource($r1);\n\n        $this->assertEquals([$r, $r1], $catalogue->getResources());\n    }\n\n    public function testMetadataDelete()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $this->assertEquals([], $catalogue->getMetadata('', ''), 'Metadata is empty');\n        $catalogue->deleteMetadata('key', 'messages');\n        $catalogue->deleteMetadata('', 'messages');\n        $catalogue->deleteMetadata();\n    }\n\n    public function testMetadataSetGetDelete()\n    {\n        $catalogue = new MessageCatalogue('en');\n        $catalogue->setMetadata('key', 'value');\n        $this->assertEquals('value', $catalogue->getMetadata('key', 'messages'), \"Metadata 'key' = 'value'\");\n\n        $catalogue->setMetadata('key2', []);\n        $this->assertEquals([], $catalogue->getMetadata('key2', 'messages'), 'Metadata key2 is array');\n\n        $catalogue->deleteMetadata('key2', 'messages');\n        $this->assertNull($catalogue->getMetadata('key2', 'messages'), 'Metadata key2 should is deleted.');\n\n        $catalogue->deleteMetadata('key2', 'domain');\n        $this->assertNull($catalogue->getMetadata('key2', 'domain'), 'Metadata key2 should is deleted.');\n    }\n\n    public function testMetadataMerge()\n    {\n        $cat1 = new MessageCatalogue('en');\n        $cat1->setMetadata('a', 'b');\n        $this->assertEquals(['messages' => ['a' => 'b']], $cat1->getMetadata('', ''), 'Cat1 contains messages metadata.');\n\n        $cat2 = new MessageCatalogue('en');\n        $cat2->setMetadata('b', 'c', 'domain');\n        $this->assertEquals(['domain' => ['b' => 'c']], $cat2->getMetadata('', ''), 'Cat2 contains domain metadata.');\n\n        $cat1->addCatalogue($cat2);\n        $this->assertEquals(['messages' => ['a' => 'b'], 'domain' => ['b' => 'c']], $cat1->getMetadata('', ''), 'Cat1 contains merged metadata.');\n    }\n}\n"
  },
  {
    "path": "Tests/Provider/DsnTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Provider;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\MissingRequiredOptionException;\nuse Symfony\\Component\\Translation\\Provider\\Dsn;\n\nfinal class DsnTest extends TestCase\n{\n    #[DataProvider('constructProvider')]\n    public function testConstruct(string $dsnString, string $scheme, string $host, ?string $user = null, ?string $password = null, ?int $port = null, array $options = [], ?string $path = null)\n    {\n        $dsn = new Dsn($dsnString);\n        $this->assertSame($dsnString, $dsn->getOriginalDsn());\n\n        $this->assertSame($scheme, $dsn->getScheme());\n        $this->assertSame($host, $dsn->getHost());\n        $this->assertSame($user, $dsn->getUser());\n        $this->assertSame($password, $dsn->getPassword());\n        $this->assertSame($port, $dsn->getPort());\n        $this->assertSame($path, $dsn->getPath());\n        $this->assertSame($options, $dsn->getOptions());\n    }\n\n    public static function constructProvider(): iterable\n    {\n        yield 'simple dsn' => [\n            'scheme://localhost',\n            'scheme',\n            'localhost',\n        ];\n\n        yield 'simple dsn including @ sign, but no user/password/token' => [\n            'scheme://@localhost',\n            'scheme',\n            'localhost',\n        ];\n\n        yield 'simple dsn including : sign and @ sign, but no user/password/token' => [\n            'scheme://:@localhost',\n            'scheme',\n            'localhost',\n        ];\n\n        yield 'simple dsn including user, : sign and @ sign, but no password' => [\n            'scheme://user1:@localhost',\n            'scheme',\n            'localhost',\n            'user1',\n        ];\n\n        yield 'simple dsn including : sign, password, and @ sign, but no user' => [\n            'scheme://:pass@localhost',\n            'scheme',\n            'localhost',\n            null,\n            'pass',\n        ];\n\n        yield 'dsn with user and pass' => [\n            'scheme://u$er:pa$s@localhost',\n            'scheme',\n            'localhost',\n            'u$er',\n            'pa$s',\n        ];\n\n        yield 'dsn with user and pass and custom port' => [\n            'scheme://u$er:pa$s@localhost:8000',\n            'scheme',\n            'localhost',\n            'u$er',\n            'pa$s',\n            8000,\n        ];\n\n        yield 'dsn with user and pass, custom port and custom path' => [\n            'scheme://u$er:pa$s@localhost:8000/channel',\n            'scheme',\n            'localhost',\n            'u$er',\n            'pa$s',\n            8000,\n            [],\n            '/channel',\n        ];\n\n        yield 'dsn with user and pass, custom port, custom path and custom option' => [\n            'scheme://u$er:pa$s@localhost:8000/channel?from=FROM',\n            'scheme',\n            'localhost',\n            'u$er',\n            'pa$s',\n            8000,\n            [\n                'from' => 'FROM',\n            ],\n            '/channel',\n        ];\n\n        yield 'dsn with user and pass, custom port, custom path and custom options' => [\n            'scheme://u$er:pa$s@localhost:8000/channel?from=FROM&to=TO',\n            'scheme',\n            'localhost',\n            'u$er',\n            'pa$s',\n            8000,\n            [\n                'from' => 'FROM',\n                'to' => 'TO',\n            ],\n            '/channel',\n        ];\n\n        yield 'dsn with user and pass, custom port, custom path and custom options and custom options keep the same order' => [\n            'scheme://u$er:pa$s@localhost:8000/channel?to=TO&from=FROM',\n            'scheme',\n            'localhost',\n            'u$er',\n            'pa$s',\n            8000,\n            [\n                'to' => 'TO',\n                'from' => 'FROM',\n            ],\n            '/channel',\n        ];\n    }\n\n    #[DataProvider('invalidDsnProvider')]\n    public function testInvalidDsn(string $dsnString, string $exceptionMessage)\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage($exceptionMessage);\n\n        new Dsn($dsnString);\n    }\n\n    public static function invalidDsnProvider(): iterable\n    {\n        yield [\n            'some://',\n            'The translation provider DSN is invalid.',\n        ];\n\n        yield [\n            '//loco',\n            'The translation provider DSN must contain a scheme.',\n        ];\n\n        yield [\n            'file:///some/path',\n            'The translation provider DSN must contain a host (use \"default\" by default).',\n        ];\n    }\n\n    #[DataProvider('getOptionProvider')]\n    public function testGetOption($expected, string $dsnString, string $option, ?string $default = null)\n    {\n        $dsn = new Dsn($dsnString);\n\n        $this->assertSame($expected, $dsn->getOption($option, $default));\n    }\n\n    public static function getOptionProvider(): iterable\n    {\n        yield [\n            'foo',\n            'scheme://localhost?with_value=foo',\n            'with_value',\n        ];\n\n        yield [\n            '',\n            'scheme://localhost?empty=',\n            'empty',\n        ];\n\n        yield [\n            '0',\n            'scheme://localhost?zero=0',\n            'zero',\n        ];\n\n        yield [\n            'default-value',\n            'scheme://localhost?option=value',\n            'non_existent_property',\n            'default-value',\n        ];\n    }\n\n    #[DataProvider('getRequiredOptionProvider')]\n    public function testGetRequiredOption(string $expectedValue, string $options, string $option)\n    {\n        $dsn = new Dsn(\\sprintf('scheme://localhost?%s', $options));\n\n        $this->assertSame($expectedValue, $dsn->getRequiredOption($option));\n    }\n\n    public static function getRequiredOptionProvider(): iterable\n    {\n        yield [\n            'value',\n            'with_value=value',\n            'with_value',\n        ];\n\n        yield [\n            '0',\n            'timeout=0',\n            'timeout',\n        ];\n    }\n\n    #[DataProvider('getRequiredOptionThrowsMissingRequiredOptionExceptionProvider')]\n    public function testGetRequiredOptionThrowsMissingRequiredOptionException(string $expectedExceptionMessage, string $options, string $option)\n    {\n        $dsn = new Dsn(\\sprintf('scheme://localhost?%s', $options));\n\n        $this->expectException(MissingRequiredOptionException::class);\n        $this->expectExceptionMessage($expectedExceptionMessage);\n\n        $dsn->getRequiredOption($option);\n    }\n\n    public static function getRequiredOptionThrowsMissingRequiredOptionExceptionProvider(): iterable\n    {\n        yield [\n            'The option \"foo_bar\" is required but missing.',\n            'with_value=value',\n            'foo_bar',\n        ];\n\n        yield [\n            'The option \"with_empty_string\" is required but missing.',\n            'with_empty_string=',\n            'with_empty_string',\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/Provider/FilteringProviderTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Provider;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Provider\\FilteringProvider;\nuse Symfony\\Component\\Translation\\Provider\\ProviderInterface;\nuse Symfony\\Component\\Translation\\TranslatorBag;\n\nclass FilteringProviderTest extends TestCase\n{\n    public function testReadDelegatesWithFilteredLocales()\n    {\n        $innerProvider = $this->createMock(ProviderInterface::class);\n        $expectedBag = new TranslatorBag();\n        $innerProvider->expects($this->once())\n            ->method('read')\n            ->with(['messages'], ['en', 'fr'])\n            ->willReturn($expectedBag);\n\n        $filteringProvider = new FilteringProvider(\n            $innerProvider,\n            ['en', 'fr', null, ''],\n            ['messages', 'validators']\n        );\n\n        $result = $filteringProvider->read(['messages', 'custom'], ['', null, 'en', 'fr']);\n\n        $this->assertSame($expectedBag, $result);\n    }\n}\n"
  },
  {
    "path": "Tests/Provider/NullProviderFactoryTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Provider;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Exception\\UnsupportedSchemeException;\nuse Symfony\\Component\\Translation\\Provider\\Dsn;\nuse Symfony\\Component\\Translation\\Provider\\NullProvider;\nuse Symfony\\Component\\Translation\\Provider\\NullProviderFactory;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\nclass NullProviderFactoryTest extends TestCase\n{\n    public function testCreateThrowsUnsupportedSchemeException()\n    {\n        $this->expectException(UnsupportedSchemeException::class);\n\n        (new NullProviderFactory())->create(new Dsn('foo://localhost'));\n    }\n\n    public function testCreate()\n    {\n        $this->assertInstanceOf(NullProvider::class, (new NullProviderFactory())->create(new Dsn('null://null')));\n    }\n}\n"
  },
  {
    "path": "Tests/Provider/TranslationProviderCollectionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Provider;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Provider\\NullProvider;\nuse Symfony\\Component\\Translation\\Provider\\TranslationProviderCollection;\n\nclass TranslationProviderCollectionTest extends TestCase\n{\n    public function testKeys()\n    {\n        $this->assertSame(['foo', 'baz'], $this->createProviderCollection()->keys());\n    }\n\n    public function testKeysWithGenerator()\n    {\n        $this->assertSame(['foo', 'baz'], (new TranslationProviderCollection(\n            (static function () {\n                yield 'foo' => new NullProvider();\n\n                yield 'baz' => new NullProvider();\n            })()\n        ))->keys());\n    }\n\n    public function testToString()\n    {\n        $this->assertSame('[foo,baz]', (string) $this->createProviderCollection());\n    }\n\n    public function testHas()\n    {\n        $this->assertTrue($this->createProviderCollection()->has('foo'));\n    }\n\n    public function testGet()\n    {\n        $provider = new NullProvider();\n\n        $this->assertSame($provider, (new TranslationProviderCollection([\n            'foo' => $provider,\n            'baz' => new NullProvider(),\n        ]))->get('foo'));\n    }\n\n    public function testGetThrowsException()\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->expectExceptionMessage('Provider \"invalid\" not found. Available: \"[foo,baz]\".');\n\n        $this->createProviderCollection()->get('invalid');\n    }\n\n    private function createProviderCollection(): TranslationProviderCollection\n    {\n        return new TranslationProviderCollection([\n            'foo' => new NullProvider(),\n            'baz' => new NullProvider(),\n        ]);\n    }\n}\n"
  },
  {
    "path": "Tests/PseudoLocalizationTranslatorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\IdentityTranslator;\nuse Symfony\\Component\\Translation\\PseudoLocalizationTranslator;\n\nfinal class PseudoLocalizationTranslatorTest extends TestCase\n{\n    #[DataProvider('provideTrans')]\n    public function testTrans(string $expected, string $input, array $options = [])\n    {\n        mt_srand(987);\n        $this->assertSame($expected, (new PseudoLocalizationTranslator(new IdentityTranslator(), $options))->trans($input));\n    }\n\n    public static function provideTrans(): array\n    {\n        return [\n            ['[ƒöö⭐ ≤þ≥ƁÅŔ≤⁄þ≥]', 'foo⭐ <p>BAR</p>'], // Test defaults\n            ['before <div data-label=\"fcy\"><a href=\"#\" title=\"bar\" data-content=\"ccc\">foo</a></div> after', 'before <div data-label=\"fcy\"><a href=\"#\" title=\"bar\" data-content=\"ccc\">foo</a></div> after', self::getIsolatedOptions(['parse_html' => true])],\n            ['ƀéƒöŕé <div data-label=\"fcyéé\"><a href=\"#\" title=\"bar\" data-content=\"ccc\">ƒöö éé</a></div> åƒţéŕ', 'before <div data-label=\"fcyéé\"><a href=\"#\" title=\"bar\" data-content=\"ccc\">foo éé</a></div> after', self::getIsolatedOptions(['parse_html' => true, 'accents' => true])],\n            ['ƀéƒöŕé <div data-label=\"ƒçý\"><a href=\"#\" title=\"ƀåŕ\" data-content=\"ccc\">ƒöö</a></div> åƒţéŕ', 'before <div data-label=\"fcy\"><a href=\"#\" title=\"bar\" data-content=\"ccc\">foo</a></div> after', self::getIsolatedOptions(['parse_html' => true, 'localizable_html_attributes' => ['data-label', 'title'], 'accents' => true])],\n            [' ¡″♯€‰⅋´{}⁎⁺،‐·⁄⓪①②③④⑤⑥⑦⑧⑨∶⁏≤≂≥¿՞ÅƁÇÐÉƑĜĤÎĴĶĻṀÑÖÞǪŔŠŢÛṼŴẊÝŽ⁅∖⁆˄‿‵åƀçðéƒĝĥîĵķļɱñöþǫŕšţûṽŵẋýž(¦)˞', ' !\"#$%&\\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', self::getIsolatedOptions(['accents' => true])],\n            ['foo <p>bar</p> ~~~~~~~~~~ ~~', 'foo <p>bar</p>', self::getIsolatedOptions(['expansion_factor' => 2.0])],\n            ['foo <p>bar</p> ~~~ ~~', 'foo <p>bar</p>', self::getIsolatedOptions(['parse_html' => true, 'expansion_factor' => 2.0])], // Only the visible text length is expanded\n            ['foobar ~~', 'foobar', self::getIsolatedOptions(['expansion_factor' => 1.35])], // 6*1.35 = 8.1 but we round up to 9\n            ['[foobar]', 'foobar', self::getIsolatedOptions(['brackets' => true])],\n            ['[foobar ~~~]', 'foobar', self::getIsolatedOptions(['expansion_factor' => 2.0, 'brackets' => true])], // The added brackets are taken into account in the expansion\n            ['<p data-foo=\"&quot;ççç&lt;å\">ƀåŕ</p>', '<p data-foo=\"&quot;ccc&lt;a\">bar</p>', self::getIsolatedOptions(['parse_html' => true, 'localizable_html_attributes' => ['data-foo'], 'accents' => true])],\n            ['<p data-foo=\"ççéç&quot;&quot;\">ƀåéŕ</p>', '<p data-foo=\"ccéc&quot;&quot;\">baér</p>', self::getIsolatedOptions(['parse_html' => true, 'localizable_html_attributes' => ['data-foo'], 'accents' => true])],\n            ['<p data-foo=\"ccc&quot;&quot;\">ƀåŕ</p>', '<p data-foo=\"ccc&quot;&quot;\">bar</p>', self::getIsolatedOptions(['parse_html' => true, 'accents' => true])],\n            ['<p>″≤″</p>', '<p>&quot;&lt;&quot;</p>', self::getIsolatedOptions(['parse_html' => true, 'accents' => true])],\n            ['Symfony is an Open Source, community-driven project with thousands of contributors. ~~~~~~~ ~~ ~~~~ ~~~~~~~ ~~~~~~~ ~~ ~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ ~~~~~~~ ~~ ~~~', 'Symfony is an Open Source, community-driven project with thousands of contributors.', self::getIsolatedOptions(['expansion_factor' => 2.0])],\n            ['<p>👇👇👇👇👇👇👇</p>', '<p>👇👇👇👇👇👇👇</p>', self::getIsolatedOptions(['parse_html' => true])],\n        ];\n    }\n\n    #[DataProvider('provideInvalidExpansionFactor')]\n    public function testInvalidExpansionFactor(float $expansionFactor)\n    {\n        $this->expectException(\\InvalidArgumentException::class);\n        $this->expectExceptionMessage('The expansion factor must be greater than or equal to 1.');\n\n        new PseudoLocalizationTranslator(new IdentityTranslator(), [\n            'expansion_factor' => $expansionFactor,\n        ]);\n    }\n\n    public static function provideInvalidExpansionFactor(): array\n    {\n        return [\n            [0],\n            [0.99],\n            [-1],\n        ];\n    }\n\n    private static function getIsolatedOptions(array $options): array\n    {\n        return array_replace([\n            'parse_html' => false,\n            'localizable_html_attributes' => [],\n            'accents' => false,\n            'expansion_factor' => 1.0,\n            'brackets' => false,\n        ], $options);\n    }\n}\n\n// @php-cs-fixer-ignore random_api_migration As logic is coupled with mt_rand() in src\n"
  },
  {
    "path": "Tests/StaticMessageTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\StaticMessage;\nuse Symfony\\Component\\Translation\\Translator;\n\nclass StaticMessageTest extends TestCase\n{\n    public function testTrans()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', [\n            'Symfony is great!' => 'Symfony est super !',\n        ], 'fr', '');\n\n        $translatable = new StaticMessage('Symfony is great!');\n\n        $this->assertSame('Symfony is great!', $translatable->trans($translator, 'fr'));\n    }\n}\n"
  },
  {
    "path": "Tests/TranslatableTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\TranslatableMessage;\nuse Symfony\\Component\\Translation\\Translator;\n\nclass TranslatableTest extends TestCase\n{\n    #[DataProvider('getTransTests')]\n    public function testTrans(string $expected, TranslatableMessage $translatable, array $translation, string $locale)\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', $translation, $locale, $translatable->getDomain());\n\n        $this->assertSame($expected, $translatable->trans($translator, $locale));\n    }\n\n    #[DataProvider('getFlattenedTransTests')]\n    public function testFlattenedTrans($expected, $messages, $translatable)\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', $messages, 'fr', '');\n\n        $this->assertSame($expected, $translatable->trans($translator, 'fr'));\n    }\n\n    public static function getTransTests()\n    {\n        return [\n            ['Symfony est super !', new TranslatableMessage('Symfony is great!', [], ''), [\n                'Symfony is great!' => 'Symfony est super !',\n            ], 'fr'],\n            ['Symfony est awesome !', new TranslatableMessage('Symfony is %what%!', ['%what%' => 'awesome'], ''), [\n                'Symfony is %what%!' => 'Symfony est %what% !',\n            ], 'fr'],\n            ['Symfony est superbe !', new TranslatableMessage('Symfony is %what%!', ['%what%' => new TranslatableMessage('awesome', [], '')], ''), [\n                'Symfony is %what%!' => 'Symfony est %what% !',\n                'awesome' => 'superbe',\n            ], 'fr'],\n        ];\n    }\n\n    public static function getFlattenedTransTests()\n    {\n        $messages = [\n            'symfony' => [\n                'is' => [\n                    'great' => 'Symfony est super!',\n                ],\n            ],\n            'foo' => [\n                'bar' => [\n                    'baz' => 'Foo Bar Baz',\n                ],\n                'baz' => 'Foo Baz',\n            ],\n        ];\n\n        return [\n            ['Symfony est super!', $messages, new TranslatableMessage('symfony.is.great', [], '')],\n            ['Foo Bar Baz', $messages, new TranslatableMessage('foo.bar.baz', [], '')],\n            ['Foo Baz', $messages, new TranslatableMessage('foo.baz', [], '')],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/TranslatorBagTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\TranslatorBag;\n\nclass TranslatorBagTest extends TestCase\n{\n    public function testAll()\n    {\n        $catalogue = new MessageCatalogue('en', $messages = ['domain1' => ['foo' => 'foo'], 'domain2' => ['bar' => 'bar']]);\n\n        $bag = new TranslatorBag();\n        $bag->addCatalogue($catalogue);\n\n        $this->assertEquals(['en' => $messages], $this->getAllMessagesFromTranslatorBag($bag));\n\n        $messages = ['domain1+intl-icu' => ['foo' => 'bar']] + $messages + [\n            'domain2+intl-icu' => ['bar' => 'foo'],\n            'domain3+intl-icu' => ['biz' => 'biz'],\n        ];\n        $catalogue = new MessageCatalogue('en', $messages);\n\n        $bag = new TranslatorBag();\n        $bag->addCatalogue($catalogue);\n\n        $this->assertEquals([\n            'en' => [\n                'domain1' => ['foo' => 'bar'],\n                'domain2' => ['bar' => 'foo'],\n                'domain3' => ['biz' => 'biz'],\n            ],\n        ], $this->getAllMessagesFromTranslatorBag($bag));\n    }\n\n    public function testDiff()\n    {\n        $catalogueA = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo', 'bar' => 'bar'], 'domain2' => ['baz' => 'baz', 'qux' => 'qux']]);\n\n        $bagA = new TranslatorBag();\n        $bagA->addCatalogue($catalogueA);\n\n        $catalogueB = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo'], 'domain2' => ['baz' => 'baz', 'corge' => 'corge']]);\n\n        $bagB = new TranslatorBag();\n        $bagB->addCatalogue($catalogueB);\n\n        $bagResult = $bagA->diff($bagB);\n\n        $this->assertEquals([\n            'en' => [\n                'domain1' => ['bar' => 'bar'],\n                'domain2' => ['qux' => 'qux'],\n            ],\n        ], $this->getAllMessagesFromTranslatorBag($bagResult));\n    }\n\n    public function testDiffWithIntlDomain()\n    {\n        $catalogueA = new MessageCatalogue('en', [\n            'domain1+intl-icu' => ['foo' => 'foo', 'bar' => 'bar'],\n            'domain2' => ['baz' => 'baz', 'qux' => 'qux'],\n        ]);\n\n        $bagA = new TranslatorBag();\n        $bagA->addCatalogue($catalogueA);\n\n        $catalogueB = new MessageCatalogue('en', [\n            'domain1' => ['foo' => 'foo'],\n            'domain2' => ['baz' => 'baz', 'corge' => 'corge'],\n        ]);\n\n        $bagB = new TranslatorBag();\n        $bagB->addCatalogue($catalogueB);\n\n        $bagResult = $bagA->diff($bagB);\n\n        $this->assertEquals([\n            'en' => [\n                'domain1' => ['bar' => 'bar'],\n                'domain2' => ['qux' => 'qux'],\n            ],\n        ], $this->getAllMessagesFromTranslatorBag($bagResult));\n    }\n\n    public function testIntersect()\n    {\n        $catalogueA = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo', 'bar' => 'bar'], 'domain2' => ['baz' => 'baz', 'qux' => 'qux']]);\n\n        $bagA = new TranslatorBag();\n        $bagA->addCatalogue($catalogueA);\n\n        $catalogueB = new MessageCatalogue('en', ['domain1' => ['foo' => 'foo', 'baz' => 'baz'], 'domain2' => ['baz' => 'baz', 'corge' => 'corge']]);\n\n        $bagB = new TranslatorBag();\n        $bagB->addCatalogue($catalogueB);\n\n        $bagResult = $bagA->intersect($bagB);\n\n        $this->assertEquals([\n            'en' => [\n                'domain1' => ['foo' => 'foo'],\n                'domain2' => ['baz' => 'baz'],\n            ],\n        ], $this->getAllMessagesFromTranslatorBag($bagResult));\n    }\n\n    private function getAllMessagesFromTranslatorBag(TranslatorBag $translatorBag): array\n    {\n        $allMessages = [];\n        foreach ($translatorBag->getCatalogues() as $catalogue) {\n            $allMessages[$catalogue->getLocale()] = $catalogue->all();\n        }\n\n        return $allMessages;\n    }\n}\n"
  },
  {
    "path": "Tests/TranslatorCacheTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Config\\Resource\\SelfCheckingResourceInterface;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\Loader\\LoaderInterface;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\Translator;\n\nclass TranslatorCacheTest extends TestCase\n{\n    protected string $tmpDir;\n\n    protected function setUp(): void\n    {\n        $this->tmpDir = sys_get_temp_dir().'/sf_translation';\n        $this->deleteTmpDir();\n    }\n\n    protected function tearDown(): void\n    {\n        $this->deleteTmpDir();\n    }\n\n    protected function deleteTmpDir()\n    {\n        if (!file_exists($dir = $this->tmpDir)) {\n            return;\n        }\n\n        $iterator = new \\RecursiveIteratorIterator(new \\RecursiveDirectoryIterator($this->tmpDir), \\RecursiveIteratorIterator::CHILD_FIRST);\n        foreach ($iterator as $path) {\n            if (preg_match('#[/\\\\\\\\]\\.\\.?$#', $path->__toString())) {\n                continue;\n            }\n            if ($path->isDir()) {\n                @rmdir($path->__toString());\n            } else {\n                @unlink($path->__toString());\n            }\n        }\n        rmdir($this->tmpDir);\n    }\n\n    #[DataProvider('runForDebugAndProduction')]\n    public function testThatACacheIsUsed($debug)\n    {\n        if (!class_exists(\\MessageFormatter::class)) {\n            $this->markTestSkipped(\\sprintf('Skipping test as the required \"%s\" class does not exist. Consider installing the \"intl\" PHP extension or the \"symfony/polyfill-intl-messageformatter\" package.', \\MessageFormatter::class));\n        }\n\n        $locale = 'any_locale';\n        $format = 'some_format';\n        $msgid = 'test';\n\n        // Prime the cache\n        $translator = new Translator($locale, null, $this->tmpDir, $debug);\n        $translator->addLoader($format, new ArrayLoader());\n        $translator->addResource($format, [$msgid => 'OK'], $locale);\n        $translator->addResource($format, [$msgid.'+intl' => 'OK'], $locale, 'messages+intl-icu');\n        $translator->trans($msgid);\n        $translator->trans($msgid.'+intl', [], 'messages+intl-icu');\n\n        // Try again and see we get a valid result whilst no loader can be used\n        $translator = new Translator($locale, null, $this->tmpDir, $debug);\n        $translator->addLoader($format, $this->createFailingLoader());\n        $translator->addResource($format, [$msgid => 'OK'], $locale);\n        $translator->addResource($format, [$msgid.'+intl' => 'OK'], $locale, 'messages+intl-icu');\n        $this->assertEquals('OK', $translator->trans($msgid), '-> caching does not work in '.($debug ? 'debug' : 'production'));\n        $this->assertEquals('OK', $translator->trans($msgid.'+intl', [], 'messages+intl-icu'));\n    }\n\n    public function testCatalogueIsReloadedWhenResourcesAreNoLongerFresh()\n    {\n        /*\n         * The testThatACacheIsUsed() test showed that we don't need the loader as long as the cache\n         * is fresh.\n         *\n         * Now we add a Resource that is never fresh and make sure that the\n         * cache is discarded (the loader is called twice).\n         *\n         * We need to run this for debug=true only because in production the cache\n         * will never be revalidated.\n         */\n\n        $locale = 'any_locale';\n        $format = 'some_format';\n        $msgid = 'test';\n\n        $catalogue = new MessageCatalogue($locale, []);\n        $catalogue->addResource(new StaleResource()); // better use a helper class than a mock, because it gets serialized in the cache and re-loaded\n\n        /** @var MockObject&LoaderInterface $loader */\n        $loader = $this->createMock(LoaderInterface::class);\n        $loader\n            ->expects($this->exactly(2))\n            ->method('load')\n            ->willReturn($catalogue)\n        ;\n\n        // 1st pass\n        $translator = new Translator($locale, null, $this->tmpDir, true);\n        $translator->addLoader($format, $loader);\n        $translator->addResource($format, null, $locale);\n        $translator->trans($msgid);\n\n        // 2nd pass\n        $translator = new Translator($locale, null, $this->tmpDir, true);\n        $translator->addLoader($format, $loader);\n        $translator->addResource($format, null, $locale);\n        $translator->trans($msgid);\n    }\n\n    #[DataProvider('runForDebugAndProduction')]\n    public function testDifferentTranslatorsForSameLocaleDoNotOverwriteEachOthersCache($debug)\n    {\n        /*\n         * Similar to the previous test. After we used the second translator, make\n         * sure there's still a usable cache for the first one.\n         */\n\n        $locale = 'any_locale';\n        $format = 'some_format';\n        $msgid = 'test';\n\n        // Create a Translator and prime its cache\n        $translator = new Translator($locale, null, $this->tmpDir, $debug);\n        $translator->addLoader($format, new ArrayLoader());\n        $translator->addResource($format, [$msgid => 'OK'], $locale);\n        $translator->trans($msgid);\n\n        // Create another Translator with a different catalogue for the same locale\n        $translator = new Translator($locale, null, $this->tmpDir, $debug);\n        $translator->addLoader($format, new ArrayLoader());\n        $translator->addResource($format, [$msgid => 'FAIL'], $locale);\n        $translator->trans($msgid);\n\n        // Now the first translator must still have a usable cache.\n        $translator = new Translator($locale, null, $this->tmpDir, $debug);\n        $translator->addLoader($format, $this->createFailingLoader());\n        $translator->addResource($format, [$msgid => 'OK'], $locale);\n        $this->assertEquals('OK', $translator->trans($msgid), '-> the cache was overwritten by another translator instance in '.($debug ? 'debug' : 'production'));\n    }\n\n    public function testGeneratedCacheFilesAreOnlyBelongRequestedLocales()\n    {\n        $translator = new Translator('a', null, $this->tmpDir);\n        $translator->setFallbackLocales(['b']);\n        $translator->trans('bar');\n\n        $cachedFiles = glob($this->tmpDir.'/*.php');\n\n        $this->assertCount(1, $cachedFiles);\n    }\n\n    public function testDifferentCacheFilesAreUsedForDifferentSetsOfFallbackLocales()\n    {\n        /*\n         * Because the cache file contains a catalogue including all of its fallback\n         * catalogues, we must take the set of fallback locales into consideration when\n         * loading a catalogue from the cache.\n         */\n        $translator = new Translator('a', null, $this->tmpDir);\n        $translator->setFallbackLocales(['b']);\n\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foo (a)'], 'a');\n        $translator->addResource('array', ['bar' => 'bar (b)'], 'b');\n\n        $this->assertEquals('bar (b)', $translator->trans('bar'));\n\n        // Remove fallback locale\n        $translator->setFallbackLocales([]);\n        $this->assertEquals('bar', $translator->trans('bar'));\n\n        // Use a fresh translator with no fallback locales, result should be the same\n        $translator = new Translator('a', null, $this->tmpDir);\n\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foo (a)'], 'a');\n        $translator->addResource('array', ['bar' => 'bar (b)'], 'b');\n\n        $this->assertEquals('bar', $translator->trans('bar'));\n    }\n\n    public function testPrimaryAndFallbackCataloguesContainTheSameMessagesRegardlessOfCaching()\n    {\n        /*\n         * As a safeguard against potential BC breaks, make sure that primary and fallback\n         * catalogues (reachable via getFallbackCatalogue()) always contain the full set of\n         * messages provided by the loader. This must also be the case when these catalogues\n         * are (internally) read from a cache.\n         *\n         * Optimizations inside the translator must not change this behavior.\n         */\n\n        /*\n         * Create a translator that loads two catalogues for two different locales.\n         * The catalogues contain distinct sets of messages.\n         */\n        $translator = new Translator('a', null, $this->tmpDir);\n        $translator->setFallbackLocales(['b']);\n\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foo (a)'], 'a');\n        $translator->addResource('array', ['foo' => 'foo (b)'], 'b');\n        $translator->addResource('array', ['bar' => 'bar (b)'], 'b');\n        $translator->addResource('array', ['baz' => 'baz (b)'], 'b', 'messages+intl-icu');\n\n        $catalogue = $translator->getCatalogue('a');\n        $this->assertFalse($catalogue->defines('bar')); // Sure, the \"a\" catalogue does not contain that message.\n\n        $fallback = $catalogue->getFallbackCatalogue();\n        $this->assertTrue($fallback->defines('foo')); // \"foo\" is present in \"a\" and \"b\"\n\n        /*\n         * Now, repeat the same test.\n         * Behind the scenes, the cache is used. But that should not matter, right?\n         */\n        $translator = new Translator('a', null, $this->tmpDir);\n        $translator->setFallbackLocales(['b']);\n\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foo (a)'], 'a');\n        $translator->addResource('array', ['foo' => 'foo (b)'], 'b');\n        $translator->addResource('array', ['bar' => 'bar (b)'], 'b');\n        $translator->addResource('array', ['baz' => 'baz (b)'], 'b', 'messages+intl-icu');\n\n        $catalogue = $translator->getCatalogue('a');\n        $this->assertFalse($catalogue->defines('bar'));\n\n        $fallback = $catalogue->getFallbackCatalogue();\n        $this->assertTrue($fallback->defines('foo'));\n        $this->assertTrue($fallback->defines('baz', 'messages+intl-icu'));\n    }\n\n    public function testRefreshCacheWhenResourcesAreNoLongerFresh()\n    {\n        $resource = $this->createStub(SelfCheckingResourceInterface::class);\n        $loader = $this->createMock(LoaderInterface::class);\n        $resource->method('isFresh')->willReturn(false);\n        $loader\n            ->expects($this->exactly(2))\n            ->method('load')\n            ->willReturn($this->getCatalogue('fr', [], [$resource]));\n\n        // prime the cache\n        $translator = new Translator('fr', null, $this->tmpDir, true);\n        $translator->addLoader('loader', $loader);\n        $translator->addResource('loader', 'foo', 'fr');\n        $translator->trans('foo');\n\n        // prime the cache second time\n        $translator = new Translator('fr', null, $this->tmpDir, true);\n        $translator->addLoader('loader', $loader);\n        $translator->addResource('loader', 'foo', 'fr');\n        $translator->trans('foo');\n    }\n\n    public function testCachedCatalogueIsReDumpedWhenCacheVaryChange()\n    {\n        $translator = new Translator('a', null, $this->tmpDir, false, []);\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'bar'], 'a', 'messages');\n\n        // Cached catalogue is dumped\n        $this->assertSame('bar', $translator->trans('foo', [], 'messages', 'a'));\n\n        $translator = new Translator('a', null, $this->tmpDir, false, ['vary']);\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'ccc'], 'a', 'messages');\n\n        $this->assertSame('ccc', $translator->trans('foo', [], 'messages', 'a'));\n    }\n\n    protected function getCatalogue($locale, $messages, $resources = [])\n    {\n        $catalogue = new MessageCatalogue($locale);\n        foreach ($messages as $key => $translation) {\n            $catalogue->set($key, $translation);\n        }\n        foreach ($resources as $resource) {\n            $catalogue->addResource($resource);\n        }\n\n        return $catalogue;\n    }\n\n    public static function runForDebugAndProduction()\n    {\n        return [[true], [false]];\n    }\n\n    private function createFailingLoader(): LoaderInterface\n    {\n        $loader = $this->createMock(LoaderInterface::class);\n        $loader\n            ->expects($this->never())\n            ->method('load');\n\n        return $loader;\n    }\n}\n\nclass StaleResource implements SelfCheckingResourceInterface\n{\n    public function isFresh(int $timestamp): bool\n    {\n        return false;\n    }\n\n    public function getResource()\n    {\n    }\n\n    public function __toString(): string\n    {\n        return '';\n    }\n}\n"
  },
  {
    "path": "Tests/TranslatorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\Attributes\\RequiresPhpExtension;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Exception\\RuntimeException;\nuse Symfony\\Component\\Translation\\Formatter\\IntlFormatterInterface;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatter;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\nuse Symfony\\Component\\Translation\\Loader\\YamlFileLoader;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\TranslatableMessage;\nuse Symfony\\Component\\Translation\\Translator;\n\nclass TranslatorTest extends TestCase\n{\n    private string $defaultLocale;\n\n    protected function setUp(): void\n    {\n        $this->defaultLocale = \\Locale::getDefault();\n        \\Locale::setDefault('en');\n    }\n\n    protected function tearDown(): void\n    {\n        \\Locale::setDefault($this->defaultLocale);\n    }\n\n    #[DataProvider('getInvalidLocalesTests')]\n    public function testConstructorInvalidLocale($locale)\n    {\n        $this->expectException(InvalidArgumentException::class);\n        new Translator($locale);\n    }\n\n    #[DataProvider('getValidLocalesTests')]\n    public function testConstructorValidLocale($locale)\n    {\n        $translator = new Translator($locale);\n\n        $this->assertSame($locale ?: (class_exists(\\Locale::class) ? \\Locale::getDefault() : 'en'), $translator->getLocale());\n    }\n\n    public function testSetGetLocale()\n    {\n        $translator = new Translator('en');\n\n        $this->assertEquals('en', $translator->getLocale());\n\n        $translator->setLocale('fr');\n        $this->assertEquals('fr', $translator->getLocale());\n    }\n\n    #[DataProvider('getInvalidLocalesTests')]\n    public function testSetInvalidLocale(string $locale)\n    {\n        $translator = new Translator('fr');\n\n        $this->expectException(InvalidArgumentException::class);\n\n        $translator->setLocale($locale);\n    }\n\n    #[DataProvider('getValidLocalesTests')]\n    public function testSetValidLocale(string $locale)\n    {\n        $translator = new Translator($locale);\n        $translator->setLocale($locale);\n\n        $this->assertEquals($locale ?: (class_exists(\\Locale::class) ? \\Locale::getDefault() : 'en'), $translator->getLocale());\n    }\n\n    public function testGetCatalogue()\n    {\n        $translator = new Translator('en');\n\n        $this->assertEquals(new MessageCatalogue('en'), $translator->getCatalogue());\n\n        $translator->setLocale('fr');\n        $this->assertEquals(new MessageCatalogue('fr'), $translator->getCatalogue('fr'));\n    }\n\n    public function testGetCatalogueReturnsConsolidatedCatalogue()\n    {\n        /*\n         * This will be useful once we refactor so that different domains will be loaded lazily (on-demand).\n         * In that case, getCatalogue() will probably have to load all missing domains in order to return\n         * one complete catalogue.\n         */\n\n        $locale = 'whatever';\n        $translator = new Translator($locale);\n        $translator->addLoader('loader-a', new ArrayLoader());\n        $translator->addLoader('loader-b', new ArrayLoader());\n        $translator->addResource('loader-a', ['foo' => 'foofoo'], $locale, 'domain-a');\n        $translator->addResource('loader-b', ['bar' => 'foobar'], $locale, 'domain-b');\n\n        /*\n         * Test that we get a single catalogue comprising messages\n         * from different loaders and different domains\n         */\n        $catalogue = $translator->getCatalogue($locale);\n        $this->assertTrue($catalogue->defines('foo', 'domain-a'));\n        $this->assertTrue($catalogue->defines('bar', 'domain-b'));\n    }\n\n    public function testSetFallbackLocales()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foofoo'], 'en');\n        $translator->addResource('array', ['bar' => 'foobar'], 'fr');\n\n        // force catalogue loading\n        $translator->trans('bar');\n\n        $translator->setFallbackLocales(['fr']);\n        $this->assertEquals('foobar', $translator->trans('bar'));\n    }\n\n    public function testSetFallbackLocalesMultiple()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foo (en)'], 'en');\n        $translator->addResource('array', ['bar' => 'bar (fr)'], 'fr');\n\n        // force catalogue loading\n        $translator->trans('bar');\n\n        $translator->setFallbackLocales(['fr_FR', 'fr']);\n        $this->assertEquals('bar (fr)', $translator->trans('bar'));\n    }\n\n    #[DataProvider('getInvalidLocalesTests')]\n    public function testSetFallbackInvalidLocales($locale)\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $translator = new Translator('fr');\n        $translator->setFallbackLocales(['fr', $locale]);\n    }\n\n    #[DataProvider('getValidLocalesTests')]\n    public function testSetFallbackValidLocales($locale)\n    {\n        $translator = new Translator($locale);\n        $translator->setFallbackLocales(['fr', $locale]);\n        // no assertion. this method just asserts that no exception is thrown\n        $this->addToAssertionCount(1);\n    }\n\n    public function testTransWithFallbackLocale()\n    {\n        $translator = new Translator('fr_FR');\n        $translator->setFallbackLocales(['en']);\n\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['bar' => 'foobar'], 'en');\n\n        $this->assertEquals('foobar', $translator->trans('bar'));\n    }\n\n    #[DataProvider('getInvalidLocalesTests')]\n    public function testAddResourceInvalidLocales($locale)\n    {\n        $translator = new Translator('fr');\n\n        $this->expectException(InvalidArgumentException::class);\n\n        $translator->addResource('array', ['foo' => 'foofoo'], $locale);\n    }\n\n    #[DataProvider('getValidLocalesTests')]\n    public function testAddResourceValidLocales(string $locale)\n    {\n        $translator = new Translator('fr');\n        $translator->addResource('array', ['foo' => 'foofoo'], $locale);\n        // no assertion. this method just asserts that no exception is thrown\n        $this->addToAssertionCount(1);\n    }\n\n    public function testAddResourceAfterTrans()\n    {\n        $translator = new Translator('fr');\n        $translator->addLoader('array', new ArrayLoader());\n\n        $translator->setFallbackLocales(['en']);\n\n        $translator->addResource('array', ['foo' => 'foofoo'], 'en');\n        $this->assertEquals('foofoo', $translator->trans('foo'));\n\n        $translator->addResource('array', ['bar' => 'foobar'], 'en');\n        $this->assertEquals('foobar', $translator->trans('bar'));\n    }\n\n    #[DataProvider('getTransFileTests')]\n    public function testTransWithoutFallbackLocaleFile(string $format, string $loader)\n    {\n        $loaderClass = 'Symfony\\\\Component\\\\Translation\\\\Loader\\\\'.$loader;\n        $translator = new Translator('en');\n        $translator->addLoader($format, new $loaderClass());\n        $translator->addResource($format, __DIR__.'/Fixtures/non-existing', 'en');\n        $translator->addResource($format, __DIR__.'/Fixtures/resources.'.$format, 'en');\n\n        $this->expectException(NotFoundResourceException::class);\n\n        // force catalogue loading\n        $translator->trans('foo');\n    }\n\n    #[DataProvider('getTransFileTests')]\n    public function testTransWithFallbackLocaleFile(string $format, string $loader)\n    {\n        $loaderClass = 'Symfony\\\\Component\\\\Translation\\\\Loader\\\\'.$loader;\n        $translator = new Translator('en_GB');\n        $translator->addLoader($format, new $loaderClass());\n        $translator->addResource($format, __DIR__.'/Fixtures/non-existing', 'en_GB');\n        $translator->addResource($format, __DIR__.'/Fixtures/resources.'.$format, 'en', 'resources');\n\n        $this->assertEquals('bar', $translator->trans('foo', [], 'resources'));\n    }\n\n    public function testTransWithIcuFallbackLocale()\n    {\n        $translator = new Translator('en_GB');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foofoo'], 'en_GB');\n        $translator->addResource('array', ['bar' => 'foobar'], 'en_001');\n        $translator->addResource('array', ['baz' => 'foobaz'], 'en');\n        $this->assertSame('foofoo', $translator->trans('foo'));\n        $this->assertSame('foobar', $translator->trans('bar'));\n        $this->assertSame('foobaz', $translator->trans('baz'));\n    }\n\n    public function testTransWithIcuVariantFallbackLocale()\n    {\n        $translator = new Translator('en_GB_scouse');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foofoo'], 'en_GB_scouse');\n        $translator->addResource('array', ['bar' => 'foobar'], 'en_GB');\n        $translator->addResource('array', ['baz' => 'foobaz'], 'en_001');\n        $translator->addResource('array', ['bar' => 'en', 'qux' => 'fooqux'], 'en');\n        $translator->addResource('array', ['bar' => 'nl_NL', 'fallback' => 'nl_NL'], 'nl_NL');\n        $translator->addResource('array', ['bar' => 'nl', 'fallback' => 'nl'], 'nl');\n\n        $translator->setFallbackLocales(['nl_NL', 'nl']);\n\n        $this->assertSame('foofoo', $translator->trans('foo'));\n        $this->assertSame('foobar', $translator->trans('bar'));\n        $this->assertSame('foobaz', $translator->trans('baz'));\n        $this->assertSame('fooqux', $translator->trans('qux'));\n        $this->assertSame('nl_NL', $translator->trans('fallback'));\n    }\n\n    public function testTransWithIcuRootFallbackLocale()\n    {\n        $translator = new Translator('az_Cyrl');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foofoo'], 'az_Cyrl');\n        $translator->addResource('array', ['bar' => 'foobar'], 'az');\n        $this->assertSame('foofoo', $translator->trans('foo'));\n        $this->assertSame('bar', $translator->trans('bar'));\n    }\n\n    #[DataProvider('getFallbackLocales')]\n    public function testTransWithFallbackLocaleBis($expectedLocale, $locale)\n    {\n        $translator = new Translator($locale);\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foofoo'], $locale);\n        $translator->addResource('array', ['bar' => 'foobar'], $expectedLocale);\n        $this->assertEquals('foobar', $translator->trans('bar'));\n    }\n\n    public static function getFallbackLocales()\n    {\n        $locales = [\n            ['en', 'en_US'],\n            ['en', 'en-US'],\n            ['sl_Latn_IT', 'sl_Latn_IT_nedis'],\n            ['sl_Latn', 'sl_Latn_IT'],\n        ];\n\n        if (\\function_exists('locale_parse')) {\n            $locales[] = ['sl_Latn_IT', 'sl-Latn-IT-nedis'];\n            $locales[] = ['sl_Latn', 'sl-Latn-IT'];\n        } else {\n            $locales[] = ['sl-Latn-IT', 'sl-Latn-IT-nedis'];\n            $locales[] = ['sl-Latn', 'sl-Latn-IT'];\n        }\n\n        return $locales;\n    }\n\n    public function testTransWithFallbackLocaleTer()\n    {\n        $translator = new Translator('fr_FR');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foo (en_US)'], 'en_US');\n        $translator->addResource('array', ['foo' => 'foo (en)', 'bar' => 'bar (en)'], 'en');\n\n        $translator->setFallbackLocales(['en_US', 'en']);\n\n        $this->assertEquals('foo (en_US)', $translator->trans('foo'));\n        $this->assertEquals('bar (en)', $translator->trans('bar'));\n    }\n\n    public function testTransNonExistentWithFallback()\n    {\n        $translator = new Translator('fr');\n        $translator->setFallbackLocales(['en']);\n        $translator->addLoader('array', new ArrayLoader());\n        $this->assertEquals('non-existent', $translator->trans('non-existent'));\n    }\n\n    public function testWhenAResourceHasNoRegisteredLoader()\n    {\n        $translator = new Translator('en');\n        $translator->addResource('array', ['foo' => 'foofoo'], 'en');\n\n        $this->expectException(RuntimeException::class);\n\n        $translator->trans('foo');\n    }\n\n    public function testNestedFallbackCatalogueWhenUsingMultipleLocales()\n    {\n        $translator = new Translator('fr');\n        $translator->setFallbackLocales(['ru', 'en']);\n\n        $translator->getCatalogue('fr');\n\n        $this->assertNotNull($translator->getCatalogue('ru')->getFallbackCatalogue());\n    }\n\n    public function testFallbackCatalogueResources()\n    {\n        $translator = new Translator('en_GB');\n        $translator->addLoader('yml', new YamlFileLoader());\n        $translator->addResource('yml', __DIR__.'/Fixtures/empty.yml', 'en_GB');\n        $translator->addResource('yml', __DIR__.'/Fixtures/resources.yml', 'en');\n\n        // force catalogue loading\n        $this->assertEquals('bar', $translator->trans('foo', []));\n\n        $resources = $translator->getCatalogue('en')->getResources();\n        $this->assertCount(1, $resources);\n        $this->assertContainsEquals(__DIR__.\\DIRECTORY_SEPARATOR.'Fixtures'.\\DIRECTORY_SEPARATOR.'resources.yml', $resources);\n\n        $resources = $translator->getCatalogue('en_GB')->getResources();\n        $this->assertCount(2, $resources);\n        $this->assertContainsEquals(__DIR__.\\DIRECTORY_SEPARATOR.'Fixtures'.\\DIRECTORY_SEPARATOR.'empty.yml', $resources);\n        $this->assertContainsEquals(__DIR__.\\DIRECTORY_SEPARATOR.'Fixtures'.\\DIRECTORY_SEPARATOR.'resources.yml', $resources);\n    }\n\n    #[DataProvider('getTransTests')]\n    public function testTrans($expected, $id, $translation, $parameters, $locale, $domain)\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', [(string) $id => $translation], $locale, $domain);\n\n        $this->assertEquals($expected, $translator->trans($id, $parameters, $domain, $locale));\n    }\n\n    #[DataProvider('getTransICUTests')]\n    public function testTransICU(...$args)\n    {\n        if (!class_exists(\\MessageFormatter::class)) {\n            $this->markTestSkipped(\\sprintf('Skipping test as the required \"%s\" class does not exist. Consider installing the \"intl\" PHP extension or the \"symfony/polyfill-intl-messageformatter\" package.', \\MessageFormatter::class));\n        }\n\n        $this->testTrans(...$args);\n    }\n\n    #[DataProvider('getInvalidLocalesTests')]\n    public function testTransInvalidLocale($locale)\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foofoo'], 'en');\n\n        $this->expectException(InvalidArgumentException::class);\n\n        $translator->trans('foo', [], '', $locale);\n    }\n\n    #[DataProvider('getValidLocalesTests')]\n    public function testTransValidLocale(string $locale)\n    {\n        $translator = new Translator($locale);\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['test' => 'OK'], $locale);\n\n        $this->assertEquals('OK', $translator->trans('test'));\n        $this->assertEquals('OK', $translator->trans('test', [], null, $locale));\n    }\n\n    #[DataProvider('getFlattenedTransTests')]\n    public function testFlattenedTrans(string $expected, $messages, $id)\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', $messages, 'fr', '');\n\n        $this->assertEquals($expected, $translator->trans($id, [], '', 'fr'));\n    }\n\n    public function testTransNullId()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['foo' => 'foofoo'], 'en');\n\n        $this->assertSame('', $translator->trans(null));\n\n        (\\Closure::bind(function () use ($translator) {\n            $this->assertSame([], $translator->catalogues);\n        }, $this, Translator::class))();\n    }\n\n    public static function getTransFileTests()\n    {\n        return [\n            ['csv', 'CsvFileLoader'],\n            ['ini', 'IniFileLoader'],\n            ['mo', 'MoFileLoader'],\n            ['po', 'PoFileLoader'],\n            ['php', 'PhpFileLoader'],\n            ['ts', 'QtFileLoader'],\n            ['xlf', 'XliffFileLoader'],\n            ['yml', 'YamlFileLoader'],\n            ['json', 'JsonFileLoader'],\n        ];\n    }\n\n    public static function getTransTests(): array\n    {\n        $param = new TranslatableMessage('Symfony is %what%!', ['%what%' => 'awesome'], '');\n\n        return [\n            ['Symfony est super !', 'Symfony is great!', 'Symfony est super !', [], 'fr', ''],\n            ['Symfony est awesome !', 'Symfony is %what%!', 'Symfony est %what% !', ['%what%' => 'awesome'], 'fr', ''],\n            ['Symfony est Symfony est awesome ! !', 'Symfony is %what%!', 'Symfony est %what% !', ['%what%' => $param], 'fr', ''],\n            ['Symfony est super !', new StringClass('Symfony is great!'), 'Symfony est super !', [], 'fr', ''],\n            ['', null, '', [], 'fr', ''],\n        ];\n    }\n\n    public static function getTransICUTests()\n    {\n        $id = '{apples, plural, =0 {There are no apples} one {There is one apple} other {There are # apples}}';\n\n        return [\n            ['There are no apples', $id, $id, ['{apples}' => 0], 'en', 'test'.MessageCatalogue::INTL_DOMAIN_SUFFIX],\n            ['There is one apple',  $id, $id, ['{apples}' => 1], 'en', 'test'.MessageCatalogue::INTL_DOMAIN_SUFFIX],\n            ['There are 3 apples',  $id, $id, ['{apples}' => 3], 'en', 'test'.MessageCatalogue::INTL_DOMAIN_SUFFIX],\n        ];\n    }\n\n    public static function getFlattenedTransTests()\n    {\n        $messages = [\n            'symfony' => [\n                'is' => [\n                    'great' => 'Symfony est super!',\n                ],\n            ],\n            'foo' => [\n                'bar' => [\n                    'baz' => 'Foo Bar Baz',\n                ],\n                'baz' => 'Foo Baz',\n            ],\n        ];\n\n        return [\n            ['Symfony est super!', $messages, 'symfony.is.great'],\n            ['Foo Bar Baz', $messages, 'foo.bar.baz'],\n            ['Foo Baz', $messages, 'foo.baz'],\n        ];\n    }\n\n    public static function getInvalidLocalesTests()\n    {\n        return [\n            ['fr FR'],\n            ['français'],\n            ['fr+en'],\n            ['utf#8'],\n            ['fr&en'],\n            ['fr~FR'],\n            [' fr'],\n            ['fr '],\n            ['fr*'],\n            ['fr/FR'],\n            ['fr\\\\FR'],\n        ];\n    }\n\n    public static function getValidLocalesTests()\n    {\n        return [\n            [''],\n            ['fr'],\n            ['francais'],\n            ['FR'],\n            ['frFR'],\n            ['fr-FR'],\n            ['fr_FR'],\n            ['fr.FR'],\n            ['fr-FR.UTF8'],\n            ['sr@latin'],\n        ];\n    }\n\n    #[RequiresPhpExtension('intl')]\n    public function testIntlFormattedDomain()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n\n        $translator->addResource('array', ['some_message' => 'Hello %name%'], 'en');\n        $this->assertSame('Hello Bob', $translator->trans('some_message', ['%name%' => 'Bob']));\n\n        $translator->addResource('array', ['some_message' => 'Hi {name}'], 'en', 'messages+intl-icu');\n        $this->assertSame('Hi Bob', $translator->trans('some_message', ['%name%' => 'Bob']));\n    }\n\n    public function testIntlDomainOverlapseWithIntlResourceBefore()\n    {\n        $intlFormatterMock = $this->createMock(IntlFormatterInterface::class);\n        $intlFormatterMock->expects($this->once())->method('formatIntl')->with('hello intl', 'en', [])->willReturn('hello intl');\n\n        $messageFormatter = new MessageFormatter(null, $intlFormatterMock);\n\n        $translator = new Translator('en', $messageFormatter);\n        $translator->addLoader('array', new ArrayLoader());\n\n        $translator->addResource('array', ['some_message' => 'hello intl'], 'en', 'messages+intl-icu');\n        $translator->addResource('array', ['some_message' => 'hello'], 'en', 'messages');\n\n        $this->assertSame('hello', $translator->trans('some_message', [], 'messages'));\n\n        $translator->addResource('array', ['some_message' => 'hello intl'], 'en', 'messages+intl-icu');\n\n        $this->assertSame('hello intl', $translator->trans('some_message', [], 'messages'));\n    }\n\n    public function testMissingLoaderForResourceError()\n    {\n        $translator = new Translator('en');\n        $translator->addResource('twig', 'messages.en.twig', 'en');\n\n        $this->expectException(RuntimeException::class);\n        $this->expectExceptionMessage('No loader is registered for the \"twig\" format when loading the \"messages.en.twig\" resource.');\n\n        $translator->getCatalogue('en');\n    }\n\n    public function testTransWithGlobalParameters()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['welcome' => 'Welcome {name}!'], 'en');\n        $translator->addResource('array', ['welcome' => 'Bienvenue {name}!'], 'fr');\n        $translator->addGlobalParameter('{name}', 'Global name');\n\n        $this->assertSame('Welcome Global name!', $translator->trans('welcome'));\n        $this->assertSame('Bienvenue Global name!', $translator->trans('welcome', [], null, 'fr'));\n        $this->assertSame('Welcome John!', $translator->trans('welcome', ['{name}' => 'John']));\n        $this->assertSame('Bienvenue Jean!', $translator->trans('welcome', ['{name}' => 'Jean'], null, 'fr'));\n    }\n\n    public function testTransWithGlobalTranslatableParameters()\n    {\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', ['welcome' => 'Welcome on {link}!'], 'en');\n        $translator->addResource('array', ['welcome' => 'Bienvenue sur {link}!'], 'fr');\n\n        $translator->addResource('array', ['url' => 'example.com/admin'], 'en', 'globals');\n        $translator->addResource('array', ['url' => 'example.fr/admin'], 'fr', 'globals');\n\n        $translator->addGlobalParameter('{link}', new TranslatableMessage('url', [], 'globals'));\n\n        $this->assertSame('Welcome on example.com/admin!', $translator->trans('welcome'));\n        $this->assertSame('Bienvenue sur example.fr/admin!', $translator->trans('welcome', [], null, 'fr'));\n        $this->assertSame('Welcome on other.com!', $translator->trans('welcome', ['{link}' => 'other.com']));\n        $this->assertSame('Bienvenue sur autre.fr!', $translator->trans('welcome', ['{link}' => 'autre.fr'], null, 'fr'));\n    }\n\n    #[RequiresPhpExtension('intl')]\n    public function testTransICUWithGlobalParameters()\n    {\n        $domain = 'test.'.MessageCatalogue::INTL_DOMAIN_SUFFIX;\n\n        $translator = new Translator('en');\n        $translator->addLoader('array', new ArrayLoader());\n        $translator->addResource('array', [\n            'apples' => '{apples, plural, =0 {There are no apples} one {There is one apple} other {There are # apples}}',\n        ], 'en', $domain);\n        $translator->addGlobalParameter('{apples}', 42);\n\n        $this->assertSame('There are 42 apples', $translator->trans('apples', [], $domain));\n        $this->assertSame('There is one apple', $translator->trans('apples', ['{apples}' => 1], $domain));\n    }\n}\n\nclass StringClass\n{\n    public function __construct(\n        protected string $str,\n    ) {\n    }\n\n    public function __toString(): string\n    {\n        return $this->str;\n    }\n}\n"
  },
  {
    "path": "Tests/Util/ArrayConverterTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Util;\n\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Util\\ArrayConverter;\n\nclass ArrayConverterTest extends TestCase\n{\n    #[DataProvider('messagesData')]\n    public function testDump($input, $expectedOutput)\n    {\n        $this->assertEquals($expectedOutput, ArrayConverter::expandToTree($input));\n    }\n\n    public static function messagesData()\n    {\n        return [\n            [\n                // input\n                [\n                    'foo1' => 'bar',\n                    'foo.bar' => 'value',\n                ],\n                // expected output\n                [\n                    'foo1' => 'bar',\n                    'foo' => ['bar' => 'value'],\n                ],\n            ],\n            [\n                // input\n                [\n                    'foo.bar' => 'value1',\n                    'foo.bar.test' => 'value2',\n                ],\n                // expected output\n                [\n                    'foo' => [\n                        'bar' => 'value1',\n                        'bar.test' => 'value2',\n                    ],\n                ],\n            ],\n            [\n                // input\n                [\n                    'foo.level2.level3.level4' => 'value1',\n                    'foo.level2' => 'value2',\n                    'foo.bar' => 'value3',\n                ],\n                // expected output\n                [\n                    'foo' => [\n                        'level2' => 'value2',\n                        'level2.level3.level4' => 'value1',\n                        'bar' => 'value3',\n                    ],\n                ],\n            ],\n            [\n                // input\n                [\n                    'foo.' => 'foo.',\n                    '.bar' => '.bar',\n                    'abc.abc' => 'value',\n                    'bcd.bcd.' => 'value',\n                    '.cde.cde.' => 'value',\n                    '.def.def' => 'value',\n                ],\n                // expected output\n                [\n                    'foo.' => 'foo.',\n                    '.bar' => '.bar',\n                    'abc' => [\n                        'abc' => 'value',\n                    ],\n                    'bcd' => [\n                        'bcd.' => 'value',\n                    ],\n                    '.cde' => [\n                        'cde.' => 'value',\n                    ],\n                    '.def' => [\n                        'def' => 'value',\n                    ],\n                ],\n            ],\n        ];\n    }\n}\n"
  },
  {
    "path": "Tests/Writer/TranslationWriterTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Tests\\Writer;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Component\\Translation\\Dumper\\DumperInterface;\nuse Symfony\\Component\\Translation\\Dumper\\XliffFileDumper;\nuse Symfony\\Component\\Translation\\Dumper\\YamlFileDumper;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\RuntimeException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\Writer\\TranslationWriter;\n\nclass TranslationWriterTest extends TestCase\n{\n    public function testWrite()\n    {\n        $dumper = $this->createMock(DumperInterface::class);\n        $dumper\n            ->expects($this->once())\n            ->method('dump');\n\n        $writer = new TranslationWriter();\n        $writer->addDumper('test', $dumper);\n        $writer->write(new MessageCatalogue('en'), 'test');\n    }\n\n    public function testGetFormats()\n    {\n        $writer = new TranslationWriter();\n        $writer->addDumper('foo', new YamlFileDumper());\n        $writer->addDumper('bar', new XliffFileDumper());\n\n        $this->assertEquals(['foo', 'bar'], $writer->getFormats());\n    }\n\n    public function testFormatIsNotSupported()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('There is no dumper associated with format \"foo\".');\n        $writer = new TranslationWriter();\n\n        $writer->write(new MessageCatalogue('en'), 'foo');\n    }\n\n    public function testUnwritableDirectory()\n    {\n        $writer = new TranslationWriter();\n        $writer->addDumper('foo', new YamlFileDumper());\n\n        $path = tempnam(sys_get_temp_dir(), '');\n        file_put_contents($path, '');\n\n        $this->expectException(RuntimeException::class);\n        $this->expectExceptionMessage(\\sprintf('Translation Writer was not able to create directory \"%s\".', $path));\n\n        $writer->write(new MessageCatalogue('en'), 'foo', ['path' => $path]);\n    }\n}\n"
  },
  {
    "path": "TranslatableMessage.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Contracts\\Translation\\TranslatableInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n/**\n * @author Nate Wiebe <nate@northern.co>\n */\nclass TranslatableMessage implements TranslatableInterface\n{\n    public function __construct(\n        private string $message,\n        private array $parameters = [],\n        private ?string $domain = null,\n    ) {\n    }\n\n    public function getMessage(): string\n    {\n        return $this->message;\n    }\n\n    public function getParameters(): array\n    {\n        return $this->parameters;\n    }\n\n    public function getDomain(): ?string\n    {\n        return $this->domain;\n    }\n\n    public function trans(TranslatorInterface $translator, ?string $locale = null): string\n    {\n        $parameters = $this->getParameters();\n        foreach ($parameters as $k => $v) {\n            if ($v instanceof TranslatableInterface) {\n                $parameters[$k] = $v->trans($translator, $locale);\n            }\n        }\n\n        return $translator->trans($this->getMessage(), $parameters, $this->getDomain(), $locale);\n    }\n}\n"
  },
  {
    "path": "Translator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\Config\\ConfigCacheFactory;\nuse Symfony\\Component\\Config\\ConfigCacheFactoryInterface;\nuse Symfony\\Component\\Config\\ConfigCacheInterface;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\NotFoundResourceException;\nuse Symfony\\Component\\Translation\\Exception\\RuntimeException;\nuse Symfony\\Component\\Translation\\Formatter\\IntlFormatterInterface;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatter;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface;\nuse Symfony\\Component\\Translation\\Loader\\LoaderInterface;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\nuse Symfony\\Contracts\\Translation\\TranslatableInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n// Help opcache.preload discover always-needed symbols\nclass_exists(MessageCatalogue::class);\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass Translator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface\n{\n    /**\n     * @var MessageCatalogueInterface[]\n     */\n    protected array $catalogues = [];\n\n    private string $locale;\n\n    /**\n     * @var string[]\n     */\n    private array $fallbackLocales = [];\n\n    /**\n     * @var LoaderInterface[]\n     */\n    private array $loaders = [];\n\n    private array $resources = [];\n\n    private MessageFormatterInterface $formatter;\n\n    private ?ConfigCacheFactoryInterface $configCacheFactory;\n\n    private bool $hasIntlFormatter;\n\n    private LocaleFallbackProvider $localeFallbackProvider;\n\n    /**\n     * @var array<string, string|int|float|TranslatableInterface>\n     */\n    private array $globalParameters = [];\n\n    /**\n     * @var array<string, string|int|float>\n     */\n    private array $globalTranslatedParameters = [];\n\n    /**\n     * @throws InvalidArgumentException If a locale contains invalid characters\n     */\n    public function __construct(\n        string $locale,\n        ?MessageFormatterInterface $formatter = null,\n        private ?string $cacheDir = null,\n        private bool $debug = false,\n        private array $cacheVary = [],\n    ) {\n        $this->setLocale($locale);\n\n        $this->formatter = $formatter ??= new MessageFormatter();\n        $this->hasIntlFormatter = $formatter instanceof IntlFormatterInterface;\n        $this->localeFallbackProvider = new LocaleFallbackProvider();\n    }\n\n    public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory): void\n    {\n        $this->configCacheFactory = $configCacheFactory;\n    }\n\n    /**\n     * Adds a Loader.\n     *\n     * @param string $format The name of the loader (@see addResource())\n     */\n    public function addLoader(string $format, LoaderInterface $loader): void\n    {\n        $this->loaders[$format] = $loader;\n    }\n\n    /**\n     * Adds a Resource.\n     *\n     * @param string $format   The name of the loader (@see addLoader())\n     * @param mixed  $resource The resource name\n     *\n     * @throws InvalidArgumentException If the locale contains invalid characters\n     */\n    public function addResource(string $format, mixed $resource, string $locale, ?string $domain = null): void\n    {\n        $domain ??= 'messages';\n\n        $this->assertValidLocale($locale);\n        $locale ?: $locale = class_exists(\\Locale::class) ? \\Locale::getDefault() : 'en';\n\n        $this->resources[$locale][] = [$format, $resource, $domain];\n\n        if (\\in_array($locale, $this->fallbackLocales, true)) {\n            $this->catalogues = [];\n        } else {\n            unset($this->catalogues[$locale]);\n        }\n    }\n\n    public function setLocale(string $locale): void\n    {\n        $this->assertValidLocale($locale);\n        $this->locale = $locale;\n    }\n\n    public function getLocale(): string\n    {\n        return $this->locale ?: (class_exists(\\Locale::class) ? \\Locale::getDefault() : 'en');\n    }\n\n    /**\n     * Sets the fallback locales.\n     *\n     * @param string[] $locales\n     *\n     * @throws InvalidArgumentException If a locale contains invalid characters\n     */\n    public function setFallbackLocales(array $locales): void\n    {\n        if ($this->fallbackLocales === $locales) {\n            return;\n        }\n\n        $this->localeFallbackProvider = new LocaleFallbackProvider($locales);\n        $this->fallbackLocales = $this->cacheVary['fallback_locales'] = $locales;\n        $this->catalogues = [];\n    }\n\n    /**\n     * @internal\n     */\n    public function getFallbackLocales(): array\n    {\n        return $this->fallbackLocales;\n    }\n\n    public function addGlobalParameter(string $id, string|int|float|TranslatableInterface $value): void\n    {\n        $this->globalParameters[$id] = $value;\n        $this->globalTranslatedParameters = [];\n    }\n\n    public function getGlobalParameters(): array\n    {\n        return $this->globalParameters;\n    }\n\n    public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string\n    {\n        if (null === $id || '' === $id) {\n            return '';\n        }\n\n        $domain ??= 'messages';\n\n        $catalogue = $this->getCatalogue($locale);\n        $locale = $catalogue->getLocale();\n        while (!$catalogue->defines($id, $domain)) {\n            if ($cat = $catalogue->getFallbackCatalogue()) {\n                $catalogue = $cat;\n                $locale = $catalogue->getLocale();\n            } else {\n                break;\n            }\n        }\n\n        foreach ($parameters as $key => $value) {\n            if ($value instanceof TranslatableInterface) {\n                $parameters[$key] = $value->trans($this, $locale);\n            }\n        }\n\n        if (null === $globalParameters = &$this->globalTranslatedParameters[$locale]) {\n            $globalParameters = $this->globalParameters;\n            foreach ($globalParameters as $key => $value) {\n                if ($value instanceof TranslatableInterface) {\n                    $globalParameters[$key] = $value->trans($this, $locale);\n                }\n            }\n        }\n\n        if ($globalParameters) {\n            $parameters += $globalParameters;\n        }\n\n        $len = \\strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX);\n        if ($this->hasIntlFormatter\n            && ($catalogue->defines($id, $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX)\n            || (\\strlen($domain) > $len && 0 === substr_compare($domain, MessageCatalogue::INTL_DOMAIN_SUFFIX, -$len, $len)))\n        ) {\n            return $this->formatter->formatIntl($catalogue->get($id, $domain), $locale, $parameters);\n        }\n\n        return $this->formatter->format($catalogue->get($id, $domain), $locale, $parameters);\n    }\n\n    public function getCatalogue(?string $locale = null): MessageCatalogueInterface\n    {\n        if (!$locale) {\n            $locale = $this->getLocale();\n        } else {\n            $this->assertValidLocale($locale);\n        }\n\n        if (!isset($this->catalogues[$locale])) {\n            $this->loadCatalogue($locale);\n        }\n\n        return $this->catalogues[$locale];\n    }\n\n    public function getCatalogues(): array\n    {\n        return array_values($this->catalogues);\n    }\n\n    /**\n     * Gets the loaders.\n     *\n     * @return LoaderInterface[]\n     */\n    protected function getLoaders(): array\n    {\n        return $this->loaders;\n    }\n\n    protected function loadCatalogue(string $locale): void\n    {\n        if (null === $this->cacheDir) {\n            $this->initializeCatalogue($locale);\n        } else {\n            $this->initializeCacheCatalogue($locale);\n        }\n    }\n\n    protected function initializeCatalogue(string $locale): void\n    {\n        $this->assertValidLocale($locale);\n\n        try {\n            $this->doLoadCatalogue($locale);\n        } catch (NotFoundResourceException $e) {\n            if (!$this->computeFallbackLocales($locale)) {\n                throw $e;\n            }\n        }\n        $this->loadFallbackCatalogues($locale);\n    }\n\n    private function initializeCacheCatalogue(string $locale): void\n    {\n        if (isset($this->catalogues[$locale])) {\n            /* Catalogue already initialized. */\n            return;\n        }\n\n        $this->assertValidLocale($locale);\n        $cache = $this->getConfigCacheFactory()->cache($this->getCatalogueCachePath($locale),\n            function (ConfigCacheInterface $cache) use ($locale) {\n                $this->dumpCatalogue($locale, $cache);\n            }\n        );\n\n        if (isset($this->catalogues[$locale])) {\n            /* Catalogue has been initialized as it was written out to cache. */\n            return;\n        }\n\n        /* Read catalogue from cache. */\n        $this->catalogues[$locale] = include $cache->getPath();\n    }\n\n    private function dumpCatalogue(string $locale, ConfigCacheInterface $cache): void\n    {\n        $this->initializeCatalogue($locale);\n        $fallbackContent = $this->getFallbackContent($this->catalogues[$locale]);\n\n        $content = \\sprintf(<<<EOF\n            <?php\n\n            use Symfony\\Component\\Translation\\MessageCatalogue;\n\n            \\$catalogue = new MessageCatalogue('%s', %s);\n\n            %s\n            return \\$catalogue;\n\n            EOF,\n            $locale,\n            var_export($this->getAllMessages($this->catalogues[$locale]), true),\n            $fallbackContent\n        );\n\n        $cache->write($content, $this->catalogues[$locale]->getResources());\n    }\n\n    private function getFallbackContent(MessageCatalogue $catalogue): string\n    {\n        $fallbackContent = '';\n        $current = '';\n        $replacementPattern = '/[^a-z0-9_]/i';\n        $fallbackCatalogue = $catalogue->getFallbackCatalogue();\n        while ($fallbackCatalogue) {\n            $fallback = $fallbackCatalogue->getLocale();\n            $fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback));\n            $currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current));\n\n            $fallbackContent .= \\sprintf(<<<'EOF'\n                $catalogue%s = new MessageCatalogue('%s', %s);\n                $catalogue%s->addFallbackCatalogue($catalogue%s);\n\n                EOF,\n                $fallbackSuffix,\n                $fallback,\n                var_export($this->getAllMessages($fallbackCatalogue), true),\n                $currentSuffix,\n                $fallbackSuffix\n            );\n            $current = $fallbackCatalogue->getLocale();\n            $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();\n        }\n\n        return $fallbackContent;\n    }\n\n    private function getCatalogueCachePath(string $locale): string\n    {\n        return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('xxh128', serialize($this->cacheVary), true)), 0, 7), '/', '_').'.php';\n    }\n\n    /**\n     * @internal\n     */\n    protected function doLoadCatalogue(string $locale): void\n    {\n        $this->catalogues[$locale] = new MessageCatalogue($locale);\n\n        if (isset($this->resources[$locale])) {\n            foreach ($this->resources[$locale] as $resource) {\n                if (!isset($this->loaders[$resource[0]])) {\n                    if (\\is_string($resource[1])) {\n                        throw new RuntimeException(\\sprintf('No loader is registered for the \"%s\" format when loading the \"%s\" resource.', $resource[0], $resource[1]));\n                    }\n\n                    throw new RuntimeException(\\sprintf('No loader is registered for the \"%s\" format.', $resource[0]));\n                }\n                $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2]));\n            }\n        }\n    }\n\n    private function loadFallbackCatalogues(string $locale): void\n    {\n        $current = $this->catalogues[$locale];\n\n        foreach ($this->computeFallbackLocales($locale) as $fallback) {\n            if (!isset($this->catalogues[$fallback])) {\n                $this->initializeCatalogue($fallback);\n            }\n\n            $fallbackCatalogue = new MessageCatalogue($fallback, $this->getAllMessages($this->catalogues[$fallback]));\n            foreach ($this->catalogues[$fallback]->getResources() as $resource) {\n                $fallbackCatalogue->addResource($resource);\n            }\n            $current->addFallbackCatalogue($fallbackCatalogue);\n            $current = $fallbackCatalogue;\n        }\n    }\n\n    protected function computeFallbackLocales(string $locale): array\n    {\n        return $this->localeFallbackProvider->computeFallbackLocales($locale);\n    }\n\n    /**\n     * Asserts that the locale is valid, throws an Exception if not.\n     *\n     * @throws InvalidArgumentException If the locale contains invalid characters\n     */\n    protected function assertValidLocale(string $locale): void\n    {\n        LocaleFallbackProvider::validateLocale($locale);\n    }\n\n    /**\n     * Provides the ConfigCache factory implementation, falling back to a\n     * default implementation if necessary.\n     */\n    private function getConfigCacheFactory(): ConfigCacheFactoryInterface\n    {\n        $this->configCacheFactory ??= new ConfigCacheFactory($this->debug);\n\n        return $this->configCacheFactory;\n    }\n\n    private function getAllMessages(MessageCatalogueInterface $catalogue): array\n    {\n        $allMessages = [];\n\n        foreach ($catalogue->all() as $domain => $messages) {\n            if ($intlMessages = $catalogue->all($domain.MessageCatalogue::INTL_DOMAIN_SUFFIX)) {\n                $allMessages[$domain.MessageCatalogue::INTL_DOMAIN_SUFFIX] = $intlMessages;\n                $messages = array_diff_key($messages, $intlMessages);\n            }\n            if ($messages) {\n                $allMessages[$domain] = $messages;\n            }\n        }\n\n        return $allMessages;\n    }\n}\n"
  },
  {
    "path": "TranslatorBag.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\Translation\\Catalogue\\AbstractOperation;\nuse Symfony\\Component\\Translation\\Catalogue\\TargetOperation;\n\nfinal class TranslatorBag implements TranslatorBagInterface\n{\n    /** @var MessageCatalogue[] */\n    private array $catalogues = [];\n\n    public function addCatalogue(MessageCatalogue $catalogue): void\n    {\n        if (null !== $existingCatalogue = $this->getCatalogue($catalogue->getLocale())) {\n            $catalogue->addCatalogue($existingCatalogue);\n        }\n\n        $this->catalogues[$catalogue->getLocale()] = $catalogue;\n    }\n\n    public function addBag(TranslatorBagInterface $bag): void\n    {\n        foreach ($bag->getCatalogues() as $catalogue) {\n            $this->addCatalogue($catalogue);\n        }\n    }\n\n    public function getCatalogue(?string $locale = null): MessageCatalogueInterface\n    {\n        if (null === $locale || !isset($this->catalogues[$locale])) {\n            $this->catalogues[$locale] = new MessageCatalogue($locale);\n        }\n\n        return $this->catalogues[$locale];\n    }\n\n    public function getCatalogues(): array\n    {\n        return array_values($this->catalogues);\n    }\n\n    public function diff(TranslatorBagInterface $diffBag): self\n    {\n        $diff = new self();\n\n        foreach ($this->catalogues as $locale => $catalogue) {\n            if (null === $diffCatalogue = $diffBag->getCatalogue($locale)) {\n                $diff->addCatalogue($catalogue);\n\n                continue;\n            }\n\n            $operation = new TargetOperation($diffCatalogue, $catalogue);\n            $operation->moveMessagesToIntlDomainsIfPossible(AbstractOperation::NEW_BATCH);\n            $newCatalogue = new MessageCatalogue($locale);\n\n            foreach ($catalogue->getDomains() as $domain) {\n                $newCatalogue->add($operation->getNewMessages($domain), $domain);\n            }\n\n            $diff->addCatalogue($newCatalogue);\n        }\n\n        return $diff;\n    }\n\n    public function intersect(TranslatorBagInterface $intersectBag): self\n    {\n        $diff = new self();\n\n        foreach ($this->catalogues as $locale => $catalogue) {\n            if (null === $intersectCatalogue = $intersectBag->getCatalogue($locale)) {\n                continue;\n            }\n\n            $operation = new TargetOperation($catalogue, $intersectCatalogue);\n            $operation->moveMessagesToIntlDomainsIfPossible(AbstractOperation::OBSOLETE_BATCH);\n            $obsoleteCatalogue = new MessageCatalogue($locale);\n\n            foreach ($operation->getDomains() as $domain) {\n                $obsoleteCatalogue->add(\n                    array_diff($operation->getMessages($domain), $operation->getNewMessages($domain)),\n                    $domain\n                );\n            }\n\n            $diff->addCatalogue($obsoleteCatalogue);\n        }\n\n        return $diff;\n    }\n}\n"
  },
  {
    "path": "TranslatorBagInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\ninterface TranslatorBagInterface\n{\n    /**\n     * Gets the catalogue by locale.\n     *\n     * @param string|null $locale The locale or null to use the default\n     *\n     * @throws InvalidArgumentException If the locale contains invalid characters\n     */\n    public function getCatalogue(?string $locale = null): MessageCatalogueInterface;\n\n    /**\n     * Returns all catalogues of the instance.\n     *\n     * @return MessageCatalogueInterface[]\n     */\n    public function getCatalogues(): array;\n}\n"
  },
  {
    "path": "Util/ArrayConverter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Util;\n\n/**\n * ArrayConverter generates tree like structure from a message catalogue.\n * e.g. this\n *   'foo.bar1' => 'test1',\n *   'foo.bar2' => 'test2'\n * converts to follows:\n *   foo:\n *     bar1: test1\n *     bar2: test2.\n *\n * @author Gennady Telegin <gtelegin@gmail.com>\n */\nclass ArrayConverter\n{\n    /**\n     * Converts linear messages array to tree-like array.\n     * For example: ['foo.bar' => 'value'] will be converted to ['foo' => ['bar' => 'value']].\n     *\n     * @param array $messages Linear messages array\n     */\n    public static function expandToTree(array $messages): array\n    {\n        $tree = [];\n\n        foreach ($messages as $id => $value) {\n            $referenceToElement = &self::getElementByPath($tree, self::getKeyParts($id));\n\n            $referenceToElement = $value;\n\n            unset($referenceToElement);\n        }\n\n        return $tree;\n    }\n\n    private static function &getElementByPath(array &$tree, array $parts): mixed\n    {\n        $elem = &$tree;\n        $parentOfElem = null;\n\n        foreach ($parts as $i => $part) {\n            if (isset($elem[$part]) && \\is_string($elem[$part])) {\n                /* Process next case:\n                 *    'foo': 'test1',\n                 *    'foo.bar': 'test2'\n                 *\n                 * $tree['foo'] was string before we found array {bar: test2}.\n                 *  Treat new element as string too, e.g. add $tree['foo.bar'] = 'test2';\n                 */\n                $elem = &$elem[implode('.', \\array_slice($parts, $i))];\n                break;\n            }\n\n            $parentOfElem = &$elem;\n            $elem = &$elem[$part];\n        }\n\n        if ($elem && \\is_array($elem) && $parentOfElem) {\n            /* Process next case:\n             *    'foo.bar': 'test1'\n             *    'foo': 'test2'\n             *\n             * $tree['foo'] was array = {bar: 'test1'} before we found string constant `foo`.\n             * Cancel treating $tree['foo'] as array and cancel back it expansion,\n             *  e.g. make it $tree['foo.bar'] = 'test1' again.\n             */\n            self::cancelExpand($parentOfElem, $part, $elem);\n        }\n\n        return $elem;\n    }\n\n    private static function cancelExpand(array &$tree, string $prefix, array $node): void\n    {\n        $prefix .= '.';\n\n        foreach ($node as $id => $value) {\n            if (\\is_string($value)) {\n                $tree[$prefix.$id] = $value;\n            } else {\n                self::cancelExpand($tree, $prefix.$id, $value);\n            }\n        }\n    }\n\n    /**\n     * @return string[]\n     */\n    private static function getKeyParts(string $key): array\n    {\n        $parts = explode('.', $key);\n        $partsCount = \\count($parts);\n\n        $result = [];\n        $buffer = '';\n\n        foreach ($parts as $index => $part) {\n            if (0 === $index && '' === $part) {\n                $buffer = '.';\n\n                continue;\n            }\n\n            if ($index === $partsCount - 1 && '' === $part) {\n                $buffer .= '.';\n                $result[] = $buffer;\n\n                continue;\n            }\n\n            if (isset($parts[$index + 1]) && '' === $parts[$index + 1]) {\n                $buffer .= $part;\n\n                continue;\n            }\n\n            if ($buffer) {\n                $result[] = $buffer.$part;\n                $buffer = '';\n\n                continue;\n            }\n\n            $result[] = $part;\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "Util/XliffUtils.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Util;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\InvalidResourceException;\n\n/**\n * Provides some utility methods for XLIFF translation files, such as validating\n * their contents according to the XSD schema.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass XliffUtils\n{\n    /**\n     * Gets xliff file version based on the root \"version\" attribute.\n     *\n     * Defaults to 1.2 for backwards compatibility.\n     *\n     * @throws InvalidArgumentException\n     */\n    public static function getVersionNumber(\\DOMDocument $dom): string\n    {\n        foreach ($dom->getElementsByTagName('xliff') as $xliff) {\n            $version = $xliff->attributes->getNamedItem('version');\n            if ($version) {\n                return $version->nodeValue;\n            }\n\n            $namespace = $xliff->attributes->getNamedItem('xmlns');\n            if ($namespace) {\n                if (0 !== substr_compare('urn:oasis:names:tc:xliff:document:', $namespace->nodeValue, 0, 34)) {\n                    throw new InvalidArgumentException(\\sprintf('Not a valid XLIFF namespace \"%s\".', $namespace));\n                }\n\n                return substr($namespace, 34);\n            }\n        }\n\n        // Falls back to v1.2\n        return '1.2';\n    }\n\n    /**\n     * Validates and parses the given file into a DOMDocument.\n     *\n     * @throws InvalidResourceException\n     */\n    public static function validateSchema(\\DOMDocument $dom): array\n    {\n        $xliffVersion = static::getVersionNumber($dom);\n        $internalErrors = libxml_use_internal_errors(true);\n        if ($shouldEnable = self::shouldEnableEntityLoader()) {\n            $disableEntities = libxml_disable_entity_loader(false);\n        }\n        try {\n            $isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion));\n            if (!$isValid) {\n                return self::getXmlErrors($internalErrors);\n            }\n        } finally {\n            if ($shouldEnable) {\n                libxml_disable_entity_loader($disableEntities);\n            }\n        }\n\n        $dom->normalizeDocument();\n\n        libxml_clear_errors();\n        libxml_use_internal_errors($internalErrors);\n\n        return [];\n    }\n\n    private static function shouldEnableEntityLoader(): bool\n    {\n        static $dom, $schema;\n        if (null === $dom) {\n            $dom = new \\DOMDocument();\n            $dom->loadXML('<?xml version=\"1.0\"?><test/>');\n\n            $tmpfile = tempnam(sys_get_temp_dir(), 'symfony');\n            register_shutdown_function(static function () use ($tmpfile) {\n                @unlink($tmpfile);\n            });\n            $schema = '<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n  <xsd:include schemaLocation=\"file:///'.str_replace('\\\\', '/', $tmpfile).'\" />\n</xsd:schema>';\n            file_put_contents($tmpfile, '<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n  <xsd:element name=\"test\" type=\"testType\" />\n  <xsd:complexType name=\"testType\"/>\n</xsd:schema>');\n        }\n\n        return !@$dom->schemaValidateSource($schema);\n    }\n\n    public static function getErrorsAsString(array $xmlErrors): string\n    {\n        $errorsAsString = '';\n\n        foreach ($xmlErrors as $error) {\n            $errorsAsString .= \\sprintf(\"[%s %s] %s (in %s - line %d, column %d)\\n\",\n                \\LIBXML_ERR_WARNING === $error['level'] ? 'WARNING' : 'ERROR',\n                $error['code'],\n                $error['message'],\n                $error['file'],\n                $error['line'],\n                $error['column']\n            );\n        }\n\n        return $errorsAsString;\n    }\n\n    private static function getSchema(string $xliffVersion): string\n    {\n        if ('1.2' === $xliffVersion) {\n            $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-1.2-transitional.xsd');\n            $xmlUri = 'http://www.w3.org/2001/xml.xsd';\n        } elseif (\\in_array($xliffVersion, ['2.0', '2.1'], true)) {\n            $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-2.0.xsd');\n            $xmlUri = 'informativeCopiesOf3rdPartySchemas/w3c/xml.xsd';\n        } elseif ('2.2' === $xliffVersion) {\n            $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-2.2.xsd');\n            $xmlUri = 'informativeCopiesOf3rdPartySchemas/w3c/xml.xsd';\n        } else {\n            throw new InvalidArgumentException(\\sprintf('No support implemented for loading XLIFF version \"%s\".', $xliffVersion));\n        }\n\n        return self::fixXmlLocation($schemaSource, $xmlUri);\n    }\n\n    /**\n     * Internally changes the URI of a dependent xsd to be loaded locally.\n     */\n    private static function fixXmlLocation(string $schemaSource, string $xmlUri): string\n    {\n        $newPath = str_replace('\\\\', '/', __DIR__).'/../Resources/schemas/xml.xsd';\n        $parts = explode('/', $newPath);\n        $locationstart = 'file:///';\n        if (0 === stripos($newPath, 'phar://')) {\n            $tmpfile = tempnam(sys_get_temp_dir(), 'symfony');\n            if ($tmpfile) {\n                copy($newPath, $tmpfile);\n                $parts = explode('/', str_replace('\\\\', '/', $tmpfile));\n            } else {\n                array_shift($parts);\n                $locationstart = 'phar:///';\n            }\n        }\n\n        $drive = '\\\\' === \\DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';\n        $newPath = $locationstart.$drive.implode('/', array_map('rawurlencode', $parts));\n\n        return str_replace($xmlUri, $newPath, $schemaSource);\n    }\n\n    /**\n     * Returns the XML errors of the internal XML parser.\n     */\n    private static function getXmlErrors(bool $internalErrors): array\n    {\n        $errors = [];\n        foreach (libxml_get_errors() as $error) {\n            $errors[] = [\n                'level' => \\LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',\n                'code' => $error->code,\n                'message' => trim($error->message),\n                'file' => $error->file ?: 'n/a',\n                'line' => $error->line,\n                'column' => $error->column,\n            ];\n        }\n\n        libxml_clear_errors();\n        libxml_use_internal_errors($internalErrors);\n\n        return $errors;\n    }\n}\n"
  },
  {
    "path": "Writer/TranslationWriter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Writer;\n\nuse Symfony\\Component\\Translation\\Dumper\\DumperInterface;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\RuntimeException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * TranslationWriter writes translation messages.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\nclass TranslationWriter implements TranslationWriterInterface\n{\n    /**\n     * @var array<string, DumperInterface>\n     */\n    private array $dumpers = [];\n\n    /**\n     * Adds a dumper to the writer.\n     */\n    public function addDumper(string $format, DumperInterface $dumper): void\n    {\n        $this->dumpers[$format] = $dumper;\n    }\n\n    /**\n     * Obtains the list of supported formats.\n     */\n    public function getFormats(): array\n    {\n        return array_keys($this->dumpers);\n    }\n\n    /**\n     * Writes translation from the catalogue according to the selected format.\n     *\n     * @param string $format  The format to use to dump the messages\n     * @param array  $options Options that are passed to the dumper\n     *\n     * @throws InvalidArgumentException\n     */\n    public function write(MessageCatalogue $catalogue, string $format, array $options = []): void\n    {\n        if (!isset($this->dumpers[$format])) {\n            throw new InvalidArgumentException(\\sprintf('There is no dumper associated with format \"%s\".', $format));\n        }\n\n        // get the right dumper\n        $dumper = $this->dumpers[$format];\n\n        if (isset($options['path']) && !is_dir($options['path']) && !@mkdir($options['path'], 0o777, true) && !is_dir($options['path'])) {\n            throw new RuntimeException(\\sprintf('Translation Writer was not able to create directory \"%s\".', $options['path']));\n        }\n\n        // save\n        $dumper->dump($catalogue, $options);\n    }\n}\n"
  },
  {
    "path": "Writer/TranslationWriterInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Writer;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * TranslationWriter writes translation messages.\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\ninterface TranslationWriterInterface\n{\n    /**\n     * Writes translation from the catalogue according to the selected format.\n     *\n     * @param string $format  The format to use to dump the messages\n     * @param array  $options Options that are passed to the dumper\n     *\n     * @throws InvalidArgumentException\n     */\n    public function write(MessageCatalogue $catalogue, string $format, array $options = []): void;\n}\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"symfony/translation\",\n    \"type\": \"library\",\n    \"description\": \"Provides tools to internationalize your application\",\n    \"keywords\": [],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Fabien Potencier\",\n            \"email\": \"fabien@symfony.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.4\",\n        \"symfony/polyfill-mbstring\": \"^1.0\",\n        \"symfony/translation-contracts\": \"^3.6.1\"\n    },\n    \"require-dev\": {\n        \"nikic/php-parser\": \"^5.0\",\n        \"psr/log\": \"^1|^2|^3\",\n        \"symfony/config\": \"^7.4|^8.0\",\n        \"symfony/console\": \"^7.4|^8.0\",\n        \"symfony/dependency-injection\": \"^7.4|^8.0\",\n        \"symfony/finder\": \"^7.4|^8.0\",\n        \"symfony/http-client-contracts\": \"^2.5|^3.0\",\n        \"symfony/http-kernel\": \"^7.4|^8.0\",\n        \"symfony/intl\": \"^7.4|^8.0\",\n        \"symfony/polyfill-intl-icu\": \"^1.21\",\n        \"symfony/routing\": \"^7.4|^8.0\",\n        \"symfony/service-contracts\": \"^2.5|^3\",\n        \"symfony/yaml\": \"^7.4|^8.0\"\n    },\n    \"conflict\": {\n        \"nikic/php-parser\": \"<5.0\",\n        \"symfony/http-client-contracts\": \"<2.5\",\n        \"symfony/service-contracts\": \"<2.5\"\n    },\n    \"provide\": {\n        \"symfony/translation-implementation\": \"2.3|3.0\"\n    },\n    \"autoload\": {\n        \"files\": [ \"Resources/functions.php\" ],\n        \"psr-4\": { \"Symfony\\\\Component\\\\Translation\\\\\": \"\" },\n        \"exclude-from-classmap\": [\n            \"/Tests/\"\n        ]\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/11.3/phpunit.xsd\"\n         backupGlobals=\"false\"\n         colors=\"true\"\n         bootstrap=\"vendor/autoload.php\"\n         failOnDeprecation=\"true\"\n         failOnRisky=\"true\"\n         failOnWarning=\"true\"\n>\n    <php>\n        <ini name=\"error_reporting\" value=\"-1\" />\n    </php>\n\n    <testsuites>\n        <testsuite name=\"Symfony Translation Component Test Suite\">\n            <directory>./Tests/</directory>\n        </testsuite>\n    </testsuites>\n\n    <source ignoreSuppressionOfDeprecations=\"true\">\n        <include>\n            <directory>./</directory>\n        </include>\n        <exclude>\n            <directory>./Tests</directory>\n            <directory>./vendor</directory>\n        </exclude>\n    </source>\n\n    <extensions>\n        <bootstrap class=\"Symfony\\Bridge\\PhpUnit\\SymfonyExtension\" />\n    </extensions>\n</phpunit>\n"
  }
]