Showing preview only (823K chars total). Download the full file or copy to clipboard to get everything.
Repository: symfony/translation
Branch: 8.1
Commit: ba0bc436a49e
Files: 259
Total size: 759.8 KB
Directory structure:
gitextract_etp_7s_u/
├── .gitattributes
├── .github/
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── workflows/
│ └── close-pull-request.yml
├── .gitignore
├── CHANGELOG.md
├── Catalogue/
│ ├── AbstractOperation.php
│ ├── MergeOperation.php
│ ├── OperationInterface.php
│ └── TargetOperation.php
├── CatalogueMetadataAwareInterface.php
├── Command/
│ ├── TranslationLintCommand.php
│ ├── TranslationPullCommand.php
│ ├── TranslationPushCommand.php
│ ├── TranslationTrait.php
│ └── XliffLintCommand.php
├── DataCollector/
│ └── TranslationDataCollector.php
├── DataCollectorTranslator.php
├── DependencyInjection/
│ ├── DataCollectorTranslatorPass.php
│ ├── LoggingTranslatorPass.php
│ ├── TranslationDumperPass.php
│ ├── TranslationExtractorPass.php
│ ├── TranslatorPass.php
│ └── TranslatorPathsPass.php
├── Dumper/
│ ├── CsvFileDumper.php
│ ├── DumperInterface.php
│ ├── FileDumper.php
│ ├── IcuResFileDumper.php
│ ├── IniFileDumper.php
│ ├── JsonFileDumper.php
│ ├── MoFileDumper.php
│ ├── PhpFileDumper.php
│ ├── PoFileDumper.php
│ ├── QtFileDumper.php
│ ├── XliffFileDumper.php
│ └── YamlFileDumper.php
├── Exception/
│ ├── ExceptionInterface.php
│ ├── IncompleteDsnException.php
│ ├── InvalidArgumentException.php
│ ├── InvalidResourceException.php
│ ├── LogicException.php
│ ├── MissingRequiredOptionException.php
│ ├── NotFoundResourceException.php
│ ├── ProviderException.php
│ ├── ProviderExceptionInterface.php
│ ├── RuntimeException.php
│ └── UnsupportedSchemeException.php
├── Extractor/
│ ├── AbstractFileExtractor.php
│ ├── ChainExtractor.php
│ ├── ExtractorInterface.php
│ ├── PhpAstExtractor.php
│ └── Visitor/
│ ├── AbstractVisitor.php
│ ├── ConstraintVisitor.php
│ ├── TransMethodVisitor.php
│ └── TranslatableMessageVisitor.php
├── Formatter/
│ ├── IntlFormatter.php
│ ├── IntlFormatterInterface.php
│ ├── MessageFormatter.php
│ └── MessageFormatterInterface.php
├── IdentityTranslator.php
├── LICENSE
├── Loader/
│ ├── ArrayLoader.php
│ ├── CsvFileLoader.php
│ ├── FileLoader.php
│ ├── IcuDatFileLoader.php
│ ├── IcuResFileLoader.php
│ ├── IniFileLoader.php
│ ├── JsonFileLoader.php
│ ├── LoaderInterface.php
│ ├── MoFileLoader.php
│ ├── PhpFileLoader.php
│ ├── PoFileLoader.php
│ ├── QtFileLoader.php
│ ├── XliffFileLoader.php
│ └── YamlFileLoader.php
├── LocaleFallbackProvider.php
├── LocaleSwitcher.php
├── LoggingTranslator.php
├── MessageCatalogue.php
├── MessageCatalogueInterface.php
├── MetadataAwareInterface.php
├── Provider/
│ ├── AbstractProviderFactory.php
│ ├── Dsn.php
│ ├── FilteringProvider.php
│ ├── NullProvider.php
│ ├── NullProviderFactory.php
│ ├── ProviderFactoryInterface.php
│ ├── ProviderInterface.php
│ ├── TranslationProviderCollection.php
│ └── TranslationProviderCollectionFactory.php
├── PseudoLocalizationTranslator.php
├── README.md
├── Reader/
│ ├── TranslationReader.php
│ └── TranslationReaderInterface.php
├── Resources/
│ ├── bin/
│ │ └── translation-status.php
│ ├── data/
│ │ ├── parents.json
│ │ └── parents.php
│ ├── functions.php
│ └── schemas/
│ ├── xliff-core-1.2-transitional.xsd
│ ├── xliff-core-2.0.xsd
│ ├── xliff-core-2.2.xsd
│ └── xml.xsd
├── StaticMessage.php
├── Test/
│ ├── AbstractProviderFactoryTestCase.php
│ ├── IncompleteDsnTestTrait.php
│ └── ProviderTestCase.php
├── Tests/
│ ├── Catalogue/
│ │ ├── AbstractOperationTestCase.php
│ │ ├── MergeOperationTest.php
│ │ ├── MessageCatalogueTest.php
│ │ └── TargetOperationTest.php
│ ├── Command/
│ │ ├── TranslationLintCommandTest.php
│ │ ├── TranslationProviderTestCase.php
│ │ ├── TranslationPullCommandTest.php
│ │ ├── TranslationPushCommandTest.php
│ │ └── XliffLintCommandTest.php
│ ├── DataCollector/
│ │ └── TranslationDataCollectorTest.php
│ ├── DataCollectorTranslatorTest.php
│ ├── DependencyInjection/
│ │ ├── DataCollectorTranslatorPassTest.php
│ │ ├── Fixtures/
│ │ │ ├── ControllerArguments.php
│ │ │ ├── ServiceArguments.php
│ │ │ ├── ServiceMethodCalls.php
│ │ │ ├── ServiceProperties.php
│ │ │ └── ServiceSubscriber.php
│ │ ├── LoggingTranslatorPassTest.php
│ │ ├── TranslationDumperPassTest.php
│ │ ├── TranslationExtractorPassTest.php
│ │ ├── TranslationPathsPassTest.php
│ │ └── TranslatorPassTest.php
│ ├── Dumper/
│ │ ├── CsvFileDumperTest.php
│ │ ├── FileDumperTest.php
│ │ ├── IcuResFileDumperTest.php
│ │ ├── IniFileDumperTest.php
│ │ ├── JsonFileDumperTest.php
│ │ ├── MoFileDumperTest.php
│ │ ├── PhpFileDumperTest.php
│ │ ├── PoFileDumperTest.php
│ │ ├── QtFileDumperTest.php
│ │ ├── XliffFileDumperTest.php
│ │ └── YamlFileDumperTest.php
│ ├── Exception/
│ │ ├── ProviderExceptionTest.php
│ │ └── UnsupportedSchemeExceptionTest.php
│ ├── Extractor/
│ │ └── PhpAstExtractorTest.php
│ ├── Fixtures/
│ │ ├── empty-translation.mo
│ │ ├── empty-translation.po
│ │ ├── empty.csv
│ │ ├── empty.ini
│ │ ├── empty.json
│ │ ├── empty.mo
│ │ ├── empty.po
│ │ ├── empty.xlf
│ │ ├── empty.yml
│ │ ├── encoding.xlf
│ │ ├── escaped-id-plurals.po
│ │ ├── escaped-id.po
│ │ ├── extractor/
│ │ │ ├── resource.format.engine
│ │ │ ├── this.is.a.template.format.engine
│ │ │ ├── translatable-fqn.html.php
│ │ │ ├── translatable-short.html.php
│ │ │ ├── translatable.html.php
│ │ │ └── translation.html.php
│ │ ├── extractor-7.3/
│ │ │ └── translation.html.php
│ │ ├── extractor-ast/
│ │ │ ├── resource.format.engine
│ │ │ ├── this.is.a.template.format.engine
│ │ │ ├── translatable-fqn.html.php
│ │ │ ├── translatable-short-fqn.html.php
│ │ │ ├── translatable-short.html.php
│ │ │ ├── translatable.html.php
│ │ │ ├── translation.html.php
│ │ │ └── validator-constraints.php
│ │ ├── fuzzy-translations.po
│ │ ├── invalid-xml-resources.xlf
│ │ ├── malformed.json
│ │ ├── messages.yml
│ │ ├── messages_linear.yml
│ │ ├── missing-plurals.po
│ │ ├── non-string.yml
│ │ ├── non-valid.xlf
│ │ ├── non-valid.yml
│ │ ├── plurals.mo
│ │ ├── plurals.po
│ │ ├── resname.xlf
│ │ ├── resourcebundle/
│ │ │ ├── dat/
│ │ │ │ ├── en.res
│ │ │ │ ├── en.txt
│ │ │ │ ├── fr.res
│ │ │ │ ├── fr.txt
│ │ │ │ └── packagelist.txt
│ │ │ └── res/
│ │ │ └── en.res
│ │ ├── resources-2.0+intl-icu.xlf
│ │ ├── resources-2.0-clean.xlf
│ │ ├── resources-2.0-empty-notes.xlf
│ │ ├── resources-2.0-multi-segment-unit.xlf
│ │ ├── resources-2.0-name.xlf
│ │ ├── resources-2.0-segment-attributes.xlf
│ │ ├── resources-2.0.xlf
│ │ ├── resources-2.1.xlf
│ │ ├── resources-2.2-pgs-combined.xlf
│ │ ├── resources-2.2-pgs-gender.xlf
│ │ ├── resources-2.2-pgs-plural.xlf
│ │ ├── resources-2.2.xlf
│ │ ├── resources-clean.xlf
│ │ ├── resources-clean.xliff
│ │ ├── resources-multi-files.xlf
│ │ ├── resources-notes-meta.xlf
│ │ ├── resources-target-attributes.xlf
│ │ ├── resources-tool-info.xlf
│ │ ├── resources.csv
│ │ ├── resources.dump.json
│ │ ├── resources.ini
│ │ ├── resources.json
│ │ ├── resources.mo
│ │ ├── resources.php
│ │ ├── resources.po
│ │ ├── resources.ts
│ │ ├── resources.xlf
│ │ ├── resources.yml
│ │ ├── valid.csv
│ │ ├── with-attributes.xlf
│ │ ├── withdoctype.xlf
│ │ └── withnote.xlf
│ ├── Formatter/
│ │ ├── IntlFormatterTest.php
│ │ └── MessageFormatterTest.php
│ ├── IdentityTranslatorTest.php
│ ├── Loader/
│ │ ├── CsvFileLoaderTest.php
│ │ ├── IcuDatFileLoaderTest.php
│ │ ├── IcuResFileLoaderTest.php
│ │ ├── IniFileLoaderTest.php
│ │ ├── JsonFileLoaderTest.php
│ │ ├── LocalizedTestCase.php
│ │ ├── MoFileLoaderTest.php
│ │ ├── PhpFileLoaderTest.php
│ │ ├── PoFileLoaderTest.php
│ │ ├── QtFileLoaderTest.php
│ │ ├── XliffFileLoaderTest.php
│ │ └── YamlFileLoaderTest.php
│ ├── LocaleFallbackProviderTest.php
│ ├── LocaleSwitcherTest.php
│ ├── LoggingTranslatorTest.php
│ ├── MessageCatalogueTest.php
│ ├── Provider/
│ │ ├── DsnTest.php
│ │ ├── FilteringProviderTest.php
│ │ ├── NullProviderFactoryTest.php
│ │ └── TranslationProviderCollectionTest.php
│ ├── PseudoLocalizationTranslatorTest.php
│ ├── StaticMessageTest.php
│ ├── TranslatableTest.php
│ ├── TranslatorBagTest.php
│ ├── TranslatorCacheTest.php
│ ├── TranslatorTest.php
│ ├── Util/
│ │ └── ArrayConverterTest.php
│ └── Writer/
│ └── TranslationWriterTest.php
├── TranslatableMessage.php
├── Translator.php
├── TranslatorBag.php
├── TranslatorBagInterface.php
├── Util/
│ ├── ArrayConverter.php
│ └── XliffUtils.php
├── Writer/
│ ├── TranslationWriter.php
│ └── TranslationWriterInterface.php
├── composer.json
└── phpunit.xml.dist
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
/Tests export-ignore
/phpunit.xml.dist export-ignore
/.git* export-ignore
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
Please do not submit any Pull Requests here. They will be closed.
---
Please submit your PR here instead:
https://github.com/symfony/symfony
This repository is what we call a "subtree split": a read-only subset of that main repository.
We're looking forward to your PR there!
================================================
FILE: .github/workflows/close-pull-request.yml
================================================
name: Close Pull Request
on:
pull_request_target:
types: [opened]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: superbrothers/close-pull-request@v3
with:
comment: |
Thanks for your Pull Request! We love contributions.
However, you should instead open your PR on the main repository:
https://github.com/symfony/symfony
This repository is what we call a "subtree split": a read-only subset of that main repository.
We're looking forward to your PR there!
================================================
FILE: .gitignore
================================================
vendor/
composer.lock
phpunit.xml
================================================
FILE: CHANGELOG.md
================================================
CHANGELOG
=========
8.1
---
* Add support for XLIFF 2.1 and 2.2
* Add support for XLIFF 2.2 PGS (Plural, Gender, and Select Module)
* Add `LocaleFallbackProvider`
8.0
---
* Remove the `$escape` parameter from `CsvFileLoader::setCsvControl()`
* Make `DataCollectorTranslator` class `final`
* Remove `ProviderFactoryTestCase`, extend `AbstractProviderFactoryTestCase` instead
* Remove `TranslatableMessage::__toString()` method, use `trans()` or `getMessage()` instead
7.4
---
* Make the extractor alias optional
* Deprecate `TranslatableMessage::__toString`
* Add `Symfony\Component\Translation\StaticMessage`
7.3
---
* Add `Translator::addGlobalParameter()` to allow defining global translation parameters
7.2
---
* Deprecate `ProviderFactoryTestCase`, extend `AbstractProviderFactoryTestCase` instead
The `testIncompleteDsnException()` test is no longer provided by default. If you make use of it by implementing the `incompleteDsnProvider()` data providers,
you now need to use the `IncompleteDsnTestTrait`.
* Make `ProviderFactoryTestCase` and `ProviderTestCase` compatible with PHPUnit 10+
* Add `lint:translations` command
* Deprecate passing an escape character to `CsvFileLoader::setCsvControl()`
* Make Xliff 2.0 attributes in segment element available as `segment-attributes`
metadata returned by `XliffFileLoader` and make `XliffFileDumper` write them to the file
7.1
---
* Mark class `DataCollectorTranslator` as `final`
7.0
---
* Remove `PhpStringTokenParser`
* Remove `PhpExtractor` in favor of `PhpAstExtractor`
6.4
---
* Give current locale to `LocaleSwitcher::runWithLocale()`'s callback
* Add `--as-tree` option to `translation:pull` command to write YAML messages as a tree-like structure
* [BC BREAK] Add argument `$buildDir` to `DataCollectorTranslator::warmUp()`
* Add `DataCollectorTranslatorPass` and `LoggingTranslatorPass` (moved from `FrameworkBundle`)
* Add `PhraseTranslationProvider`
6.2.7
-----
* [BC BREAK] The following data providers for `ProviderFactoryTestCase` are now static:
`supportsProvider()`, `createProvider()`, `unsupportedSchemeProvider()`and `incompleteDsnProvider()`
* [BC BREAK] `ProviderTestCase::toStringProvider()` is now static
6.2
---
* Deprecate `PhpStringTokenParser`
* Deprecate `PhpExtractor` in favor of `PhpAstExtractor`
* Add `PhpAstExtractor` (requires [nikic/php-parser](https://github.com/nikic/php-parser) to be installed)
6.1
---
* Parameters implementing `TranslatableInterface` are processed
* Add the file extension to the `XliffFileDumper` constructor
5.4
---
* Add `github` format & autodetection to render errors as annotations when
running the XLIFF linter command in a Github Actions environment.
* Translation providers are not experimental anymore
5.3
---
* Add `translation:pull` and `translation:push` commands to manage translations with third-party providers
* Add `TranslatorBagInterface::getCatalogues` method
* Add support to load XLIFF string in `XliffFileLoader`
5.2.0
-----
* added support for calling `trans` with ICU formatted messages
* added `PseudoLocalizationTranslator`
* added `TranslatableMessage` objects that represent a message that can be translated
* added the `t()` function to easily create `TranslatableMessage` objects
* Added support for extracting messages from `TranslatableMessage` objects
5.1.0
-----
* added support for `name` attribute on `unit` element from xliff2 to be used as a translation key instead of always the `source` element
5.0.0
-----
* removed support for using `null` as the locale in `Translator`
* removed `TranslatorInterface`
* removed `MessageSelector`
* removed `ChoiceMessageFormatterInterface`
* removed `PluralizationRule`
* removed `Interval`
* removed `transChoice()` methods, use the trans() method instead with a %count% parameter
* removed `FileDumper::setBackup()` and `TranslationWriter::disableBackup()`
* removed `MessageFormatter::choiceFormat()`
* added argument `$filename` to `PhpExtractor::parseTokens()`
* removed support for implicit STDIN usage in the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit.
4.4.0
-----
* deprecated support for using `null` as the locale in `Translator`
* deprecated accepting STDIN implicitly when using the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit.
* Marked the `TranslationDataCollector` class as `@final`.
4.3.0
-----
* Improved Xliff 1.2 loader to load the original file's metadata
* Added `TranslatorPathsPass`
4.2.0
-----
* Started using ICU parent locales as fallback locales.
* allow using the ICU message format using domains with the "+intl-icu" suffix
* deprecated `Translator::transChoice()` in favor of using `Translator::trans()` with a `%count%` parameter
* deprecated `TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`
* deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead
* Added `IntlFormatter` and `IntlFormatterInterface`
* added support for multiple files and directories in `XliffLintCommand`
* Marked `Translator::getFallbackLocales()` and `TranslationDataCollector::getFallbackLocales()` as internal
4.1.0
-----
* The `FileDumper::setBackup()` method is deprecated.
* The `TranslationWriter::disableBackup()` method is deprecated.
* The `XliffFileDumper` will write "name" on the "unit" node when dumping XLIFF 2.0.
4.0.0
-----
* removed the backup feature of the `FileDumper` class
* removed `TranslationWriter::writeTranslations()` method
* removed support for passing `MessageSelector` instances to the constructor of the `Translator` class
3.4.0
-----
* Added `TranslationDumperPass`
* Added `TranslationExtractorPass`
* Added `TranslatorPass`
* Added `TranslationReader` and `TranslationReaderInterface`
* Added `<notes>` section to the Xliff 2.0 dumper.
* Improved Xliff 2.0 loader to load `<notes>` section.
* Added `TranslationWriterInterface`
* Deprecated `TranslationWriter::writeTranslations` in favor of `TranslationWriter::write`
* added support for adding custom message formatter and decoupling the default one.
* Added `PhpExtractor`
* Added `PhpStringTokenParser`
3.2.0
-----
* Added support for escaping `|` in plural translations with double pipe.
3.1.0
-----
* Deprecated the backup feature of the file dumper classes.
3.0.0
-----
* removed `FileDumper::format()` method.
* Changed the visibility of the locale property in `Translator` from protected to private.
2.8.0
-----
* deprecated FileDumper::format(), overwrite FileDumper::formatCatalogue() instead.
* deprecated Translator::getMessages(), rely on TranslatorBagInterface::getCatalogue() instead.
* added `FileDumper::formatCatalogue` which allows format the catalogue without dumping it into file.
* added option `json_encoding` to JsonFileDumper
* added options `as_tree`, `inline` to YamlFileDumper
* added support for XLIFF 2.0.
* added support for XLIFF target and tool attributes.
* added message parameters to DataCollectorTranslator.
* [DEPRECATION] The `DiffOperation` class has been deprecated and
will be removed in Symfony 3.0, since its operation has nothing to do with 'diff',
so the class name is misleading. The `TargetOperation` class should be used for
this use-case instead.
2.7.0
-----
* added DataCollectorTranslator for collecting the translated messages.
2.6.0
-----
* added possibility to cache catalogues
* added TranslatorBagInterface
* added LoggingTranslator
* added Translator::getMessages() for retrieving the message catalogue as an array
2.5.0
-----
* added relative file path template to the file dumpers
* added optional backup to the file dumpers
* changed IcuResFileDumper to extend FileDumper
2.3.0
-----
* added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues)
* added Translator::getFallbackLocales()
* deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method
2.2.0
-----
* QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3.
* [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now
throws Symfony\Component\Translation\Exception\NotFoundResourceException when a resource cannot be found
and Symfony\Component\Translation\Exception\InvalidResourceException when a resource is invalid.
* changed the exception class thrown by some load() methods from \RuntimeException to \InvalidArgumentException
(IcuDatFileLoader, IcuResFileLoader and QtFileLoader)
2.1.0
-----
* added support for more than one fallback locale
* added support for extracting translation messages from templates (Twig and PHP)
* added dumpers for translation catalogs
* added support for QT, gettext, and ResourceBundles
================================================
FILE: Catalogue/AbstractOperation.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Catalogue;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\Exception\LogicException;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
/**
* Base catalogues binary operation class.
*
* A catalogue binary operation performs operation on
* source (the left argument) and target (the right argument) catalogues.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
abstract class AbstractOperation implements OperationInterface
{
public const OBSOLETE_BATCH = 'obsolete';
public const NEW_BATCH = 'new';
public const ALL_BATCH = 'all';
protected MessageCatalogue $result;
/**
* This array stores 'all', 'new' and 'obsolete' messages for all valid domains.
*
* The data structure of this array is as follows:
*
* [
* 'domain 1' => [
* 'all' => [...],
* 'new' => [...],
* 'obsolete' => [...]
* ],
* 'domain 2' => [
* 'all' => [...],
* 'new' => [...],
* 'obsolete' => [...]
* ],
* ...
* ]
*
* @var array The array that stores 'all', 'new' and 'obsolete' messages
*/
protected array $messages;
private array $domains;
/**
* @throws LogicException
*/
public function __construct(
protected MessageCatalogueInterface $source,
protected MessageCatalogueInterface $target,
) {
if ($source->getLocale() !== $target->getLocale()) {
throw new LogicException('Operated catalogues must belong to the same locale.');
}
$this->result = new MessageCatalogue($source->getLocale());
$this->messages = [];
}
public function getDomains(): array
{
if (!isset($this->domains)) {
$domains = [];
foreach ([$this->source, $this->target] as $catalogue) {
foreach ($catalogue->getDomains() as $domain) {
$domains[$domain] = $domain;
if ($catalogue->all($domainIcu = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX)) {
$domains[$domainIcu] = $domainIcu;
}
}
}
$this->domains = array_values($domains);
}
return $this->domains;
}
public function getMessages(string $domain): array
{
if (!\in_array($domain, $this->getDomains(), true)) {
throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain));
}
if (!isset($this->messages[$domain][self::ALL_BATCH])) {
$this->processDomain($domain);
}
return $this->messages[$domain][self::ALL_BATCH];
}
public function getNewMessages(string $domain): array
{
if (!\in_array($domain, $this->getDomains(), true)) {
throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain));
}
if (!isset($this->messages[$domain][self::NEW_BATCH])) {
$this->processDomain($domain);
}
return $this->messages[$domain][self::NEW_BATCH];
}
public function getObsoleteMessages(string $domain): array
{
if (!\in_array($domain, $this->getDomains(), true)) {
throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain));
}
if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) {
$this->processDomain($domain);
}
return $this->messages[$domain][self::OBSOLETE_BATCH];
}
public function getResult(): MessageCatalogueInterface
{
foreach ($this->getDomains() as $domain) {
if (!isset($this->messages[$domain])) {
$this->processDomain($domain);
}
}
return $this->result;
}
/**
* @param self::*_BATCH $batch
*/
public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BATCH): void
{
// If MessageFormatter class does not exists, intl domains are not supported.
if (!class_exists(\MessageFormatter::class)) {
return;
}
foreach ($this->getDomains() as $domain) {
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
$messages = match ($batch) {
self::OBSOLETE_BATCH => $this->getObsoleteMessages($domain),
self::NEW_BATCH => $this->getNewMessages($domain),
self::ALL_BATCH => $this->getMessages($domain),
default => throw new \InvalidArgumentException(\sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)),
};
if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) {
continue;
}
$result = $this->getResult();
$allIntlMessages = $result->all($intlDomain);
$currentMessages = array_diff_key($messages, $result->all($domain));
$result->replace($currentMessages, $domain);
$result->replace($allIntlMessages + $messages, $intlDomain);
}
}
/**
* Performs operation on source and target catalogues for the given domain and
* stores the results.
*
* @param string $domain The domain which the operation will be performed for
*/
abstract protected function processDomain(string $domain): void;
}
================================================
FILE: Catalogue/MergeOperation.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Catalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
/**
* Merge operation between two catalogues as follows:
* all = source ∪ target = {x: x ∈ source ∨ x ∈ target}
* new = all ∖ source = {x: x ∈ target ∧ x ∉ source}
* obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ source ∧ x ∉ target} = ∅
* Basically, the result contains messages from both catalogues.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class MergeOperation extends AbstractOperation
{
protected function processDomain(string $domain): void
{
$this->messages[$domain] = [
'all' => [],
'new' => [],
'obsolete' => [],
];
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {
if (null === $this->result->getCatalogueMetadata($key, $domain)) {
$this->result->setCatalogueMetadata($key, $value, $domain);
}
}
foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {
if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {
$this->result->setCatalogueMetadata($key, $value, $intlDomain);
}
}
foreach ($this->source->all($domain) as $id => $message) {
$this->messages[$domain]['all'][$id] = $message;
$d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;
$this->result->add([$id => $message], $d);
if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) {
$this->result->setMetadata($id, $keyMetadata, $d);
}
}
foreach ($this->target->all($domain) as $id => $message) {
if (!$this->source->has($id, $domain)) {
$this->messages[$domain]['all'][$id] = $message;
$this->messages[$domain]['new'][$id] = $message;
$d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;
$this->result->add([$id => $message], $d);
if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) {
$this->result->setMetadata($id, $keyMetadata, $d);
}
}
}
}
}
================================================
FILE: Catalogue/OperationInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Catalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
/**
* Represents an operation on catalogue(s).
*
* An instance of this interface performs an operation on one or more catalogues and
* stores intermediate and final results of the operation.
*
* The first catalogue in its argument(s) is called the 'source catalogue' or 'source' and
* the following results are stored:
*
* Messages: also called 'all', are valid messages for the given domain after the operation is performed.
*
* New Messages: also called 'new' (new = all ∖ source = {x: x ∈ all ∧ x ∉ source}).
*
* Obsolete Messages: also called 'obsolete' (obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ all}).
*
* Result: also called 'result', is the resulting catalogue for the given domain that holds the same messages as 'all'.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*/
interface OperationInterface
{
/**
* Returns domains affected by operation.
*/
public function getDomains(): array;
/**
* Returns all valid messages ('all') after operation.
*/
public function getMessages(string $domain): array;
/**
* Returns new messages ('new') after operation.
*/
public function getNewMessages(string $domain): array;
/**
* Returns obsolete messages ('obsolete') after operation.
*/
public function getObsoleteMessages(string $domain): array;
/**
* Returns resulting catalogue ('result').
*/
public function getResult(): MessageCatalogueInterface;
}
================================================
FILE: Catalogue/TargetOperation.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Catalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
/**
* Target operation between two catalogues:
* intersection = source ∩ target = {x: x ∈ source ∧ x ∈ target}
* all = intersection ∪ (target ∖ intersection) = target
* new = all ∖ source = {x: x ∈ target ∧ x ∉ source}
* obsolete = source ∖ all = source ∖ target = {x: x ∈ source ∧ x ∉ target}
* Basically, the result contains messages from the target catalogue.
*
* @author Michael Lee <michael.lee@zerustech.com>
*/
class TargetOperation extends AbstractOperation
{
protected function processDomain(string $domain): void
{
$this->messages[$domain] = [
'all' => [],
'new' => [],
'obsolete' => [],
];
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {
if (null === $this->result->getCatalogueMetadata($key, $domain)) {
$this->result->setCatalogueMetadata($key, $value, $domain);
}
}
foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {
if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {
$this->result->setCatalogueMetadata($key, $value, $intlDomain);
}
}
// For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``,
// because doing so will drop messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}
//
// For 'new' messages, the code can't be simplified as ``array_diff_assoc($this->target->all($domain), $this->source->all($domain));``
// because doing so will not exclude messages like {x: x ∈ target ∧ x ∉ source.all ∧ x ∈ source.fallback}
//
// For 'obsolete' messages, the code can't be simplified as ``array_diff_assoc($this->source->all($domain), $this->target->all($domain))``
// because doing so will not exclude messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}
foreach ($this->source->all($domain) as $id => $message) {
if ($this->target->has($id, $domain)) {
$this->messages[$domain]['all'][$id] = $message;
$d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;
$this->result->add([$id => $message], $d);
if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) {
$this->result->setMetadata($id, $keyMetadata, $d);
}
} else {
$this->messages[$domain]['obsolete'][$id] = $message;
}
}
foreach ($this->target->all($domain) as $id => $message) {
if (!$this->source->has($id, $domain)) {
$this->messages[$domain]['all'][$id] = $message;
$this->messages[$domain]['new'][$id] = $message;
$d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;
$this->result->add([$id => $message], $d);
if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) {
$this->result->setMetadata($id, $keyMetadata, $d);
}
}
}
}
}
================================================
FILE: CatalogueMetadataAwareInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
/**
* This interface is used to get, set, and delete metadata about the Catalogue.
*
* @author Hugo Alliaume <hugo@alliau.me>
*/
interface CatalogueMetadataAwareInterface
{
/**
* Gets catalogue metadata for the given domain and key.
*
* Passing an empty domain will return an array with all catalogue metadata indexed by
* domain and then by key. Passing an empty key will return an array with all
* catalogue metadata for the given domain.
*
* @return mixed The value that was set or an array with the domains/keys or null
*/
public function getCatalogueMetadata(string $key = '', string $domain = 'messages'): mixed;
/**
* Adds catalogue metadata to a message domain.
*/
public function setCatalogueMetadata(string $key, mixed $value, string $domain = 'messages'): void;
/**
* Deletes catalogue metadata for the given key and domain.
*
* Passing an empty domain will delete all catalogue metadata. Passing an empty key will
* delete all metadata for the given domain.
*/
public function deleteCatalogueMetadata(string $key = '', string $domain = 'messages'): void;
}
================================================
FILE: Command/TranslationLintCommand.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Translation\Exception\ExceptionInterface;
use Symfony\Component\Translation\TranslatorBagInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Lint translations files syntax and outputs encountered errors.
*
* @author Hugo Alliaume <hugo@alliau.me>
*/
#[AsCommand(name: 'lint:translations', description: 'Lint translations files syntax and outputs encountered errors')]
class TranslationLintCommand extends Command
{
private SymfonyStyle $io;
public function __construct(
private TranslatorInterface&TranslatorBagInterface $translator,
private array $enabledLocales = [],
) {
$this->enabledLocales = array_filter($enabledLocales);
parent::__construct();
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestOptionValuesFor('locale')) {
$suggestions->suggestValues($this->enabledLocales);
}
}
protected function configure(): void
{
$this
->setDefinition([
new InputOption('locale', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to lint.', $this->enabledLocales),
])
->setHelp(<<<'EOF'
The <info>%command.name%</> command lint translations.
<info>php %command.full_name%</>
EOF
);
}
protected function initialize(InputInterface $input, OutputInterface $output): void
{
$this->io = new SymfonyStyle($input, $output);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$locales = $input->getOption('locale');
/** @var array<string, array<string, array<string, \Throwable>>> $errors */
$errors = [];
$domainsByLocales = [];
foreach ($locales as $locale) {
$messageCatalogue = $this->translator->getCatalogue($locale);
foreach ($domainsByLocales[$locale] = $messageCatalogue->getDomains() as $domain) {
foreach ($messageCatalogue->all($domain) as $id => $translation) {
try {
$this->translator->trans($id, [], $domain, $messageCatalogue->getLocale());
} catch (ExceptionInterface $e) {
$errors[$locale][$domain][$id] = $e;
}
}
}
}
if (!$domainsByLocales) {
$this->io->error('No translation files were found.');
return Command::SUCCESS;
}
$this->io->table(
['Locale', 'Domains', 'Valid?'],
array_map(
static fn (string $locale, array $domains) => [
$locale,
implode(', ', $domains),
!\array_key_exists($locale, $errors) ? '<info>Yes</>' : '<error>No</>',
],
array_keys($domainsByLocales),
$domainsByLocales
),
);
if ($errors) {
foreach ($errors as $locale => $domains) {
foreach ($domains as $domain => $domainsErrors) {
$this->io->section(\sprintf('Errors for locale "%s" and domain "%s"', $locale, $domain));
foreach ($domainsErrors as $id => $error) {
$this->io->text(\sprintf('Translation key "%s" is invalid:', $id));
$this->io->error($error->getMessage());
}
}
}
return Command::FAILURE;
}
$this->io->success('All translations are valid.');
return Command::SUCCESS;
}
}
================================================
FILE: Command/TranslationPullCommand.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Translation\Catalogue\TargetOperation;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Provider\TranslationProviderCollection;
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
use Symfony\Component\Translation\Writer\TranslationWriterInterface;
/**
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*/
#[AsCommand(name: 'translation:pull', description: 'Pull translations from a given provider.')]
final class TranslationPullCommand extends Command
{
use TranslationTrait;
public function __construct(
private TranslationProviderCollection $providerCollection,
private TranslationWriterInterface $writer,
private TranslationReaderInterface $reader,
private string $defaultLocale,
private array $transPaths = [],
private array $enabledLocales = [],
) {
$this->enabledLocales = array_filter($enabledLocales);
parent::__construct();
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('provider')) {
$suggestions->suggestValues($this->providerCollection->keys());
return;
}
if ($input->mustSuggestOptionValuesFor('domains')) {
$provider = $this->providerCollection->get($input->getArgument('provider'));
if (method_exists($provider, 'getDomains')) {
$suggestions->suggestValues($provider->getDomains());
}
return;
}
if ($input->mustSuggestOptionValuesFor('locales')) {
$suggestions->suggestValues($this->enabledLocales);
return;
}
if ($input->mustSuggestOptionValuesFor('format')) {
$suggestions->suggestValues(['php', 'xlf', 'xlf12', 'xlf20', 'po', 'mo', 'yml', 'yaml', 'ts', 'csv', 'json', 'ini', 'res']);
}
}
protected function configure(): void
{
$keys = $this->providerCollection->keys();
$defaultProvider = 1 === \count($keys) ? $keys[0] : null;
$this
->setDefinition([
new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to pull translations from.', $defaultProvider),
new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with provider ones (it will delete not synchronized messages).'),
new InputOption('intl-icu', null, InputOption::VALUE_NONE, 'Associated to --force option, it will write messages in "%domain%+intl-icu.%locale%.xlf" files.'),
new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'),
new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'Override the default output format.', 'xlf12'),
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'),
])
->setHelp(<<<'EOF'
The <info>%command.name%</> command pulls translations from the given provider. Only
new translations are pulled, existing ones are not overwritten.
You can overwrite existing translations (and remove the missing ones on local side) by using the <info>--force</> flag:
<info>php %command.full_name% --force provider</>
Full example:
<info>php %command.full_name% provider --force --domains=messages --domains=validators --locales=en</>
This command pulls all translations associated with the <info>messages</> and <info>validators</> domains for the <info>en</> locale.
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.
Local translations for others domains and locales are ignored.
EOF
)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$provider = $this->providerCollection->get($input->getArgument('provider'));
$force = $input->getOption('force');
$intlIcu = $input->getOption('intl-icu');
$locales = $input->getOption('locales') ?: $this->enabledLocales;
$domains = $input->getOption('domains');
$format = $input->getOption('format');
$asTree = (int) $input->getOption('as-tree');
$xliffVersion = '1.2';
if ($intlIcu && !$force) {
$io->note('--intl-icu option only has an effect when used with --force. Here, it will be ignored.');
}
switch ($format) {
case 'xlf20': $xliffVersion = '2.0';
// no break
case 'xlf12': $format = 'xlf';
}
$writeOptions = [
'path' => end($this->transPaths),
'xliff_version' => $xliffVersion,
'default_locale' => $this->defaultLocale,
'as_tree' => (bool) $asTree,
'inline' => $asTree,
];
if (!$domains) {
$domains = $provider->getDomains();
}
$providerTranslations = $provider->read($domains, $locales);
if ($force) {
foreach ($providerTranslations->getCatalogues() as $catalogue) {
$operation = new TargetOperation(new MessageCatalogue($catalogue->getLocale()), $catalogue);
if ($intlIcu) {
$operation->moveMessagesToIntlDomainsIfPossible();
}
$this->writer->write($operation->getResult(), $format, $writeOptions);
}
$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)));
return 0;
}
$localTranslations = $this->readLocalTranslations($locales, $domains, $this->transPaths);
// Append pulled translations to local ones.
$localTranslations->addBag($providerTranslations->diff($localTranslations));
foreach ($localTranslations->getCatalogues() as $catalogue) {
$this->writer->write($catalogue, $format, $writeOptions);
}
$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)));
return 0;
}
}
================================================
FILE: Command/TranslationPushCommand.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Translation\Provider\FilteringProvider;
use Symfony\Component\Translation\Provider\TranslationProviderCollection;
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
use Symfony\Component\Translation\TranslatorBag;
/**
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*/
#[AsCommand(name: 'translation:push', description: 'Push translations to a given provider.')]
final class TranslationPushCommand extends Command
{
use TranslationTrait;
public function __construct(
private TranslationProviderCollection $providers,
private TranslationReaderInterface $reader,
private array $transPaths = [],
private array $enabledLocales = [],
) {
$this->enabledLocales = array_filter($enabledLocales);
parent::__construct();
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('provider')) {
$suggestions->suggestValues($this->providers->keys());
return;
}
if ($input->mustSuggestOptionValuesFor('domains')) {
$provider = $this->providers->get($input->getArgument('provider'));
if (method_exists($provider, 'getDomains')) {
$domains = $provider->getDomains();
$suggestions->suggestValues($domains);
}
return;
}
if ($input->mustSuggestOptionValuesFor('locales')) {
$suggestions->suggestValues($this->enabledLocales);
}
}
protected function configure(): void
{
$keys = $this->providers->keys();
$defaultProvider = 1 === \count($keys) ? $keys[0] : null;
$this
->setDefinition([
new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to push translations to.', $defaultProvider),
new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with local ones (it will delete not synchronized messages).'),
new InputOption('delete-missing', null, InputOption::VALUE_NONE, 'Delete translations available on provider but not locally.'),
new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to push.'),
new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to push.', $this->enabledLocales),
])
->setHelp(<<<'EOF'
The <info>%command.name%</> command pushes translations to the given provider. Only new
translations are pushed, existing ones are not overwritten.
You can overwrite existing translations by using the <info>--force</> flag:
<info>php %command.full_name% --force provider</>
You can delete provider translations which are not present locally by using the <info>--delete-missing</> flag:
<info>php %command.full_name% --delete-missing provider</>
Full example:
<info>php %command.full_name% provider --force --delete-missing --domains=messages --domains=validators --locales=en</>
This command pushes all translations associated with the <info>messages</> and <info>validators</> domains for the <info>en</> locale.
Provider translations for the specified domains and locale are deleted if they're not present locally and overwritten if it's the case.
Provider translations for others domains and locales are ignored.
EOF
)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$provider = $this->providers->get($input->getArgument('provider'));
if (!$this->enabledLocales) {
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)));
}
$io = new SymfonyStyle($input, $output);
$domains = $input->getOption('domains');
$locales = $input->getOption('locales');
$force = $input->getOption('force');
$deleteMissing = $input->getOption('delete-missing');
if (!$domains && $provider instanceof FilteringProvider) {
$domains = $provider->getDomains();
}
// Reading local translations must be done after retrieving the domains from the provider
// in order to manage only translations from configured domains
$localTranslations = $this->readLocalTranslations($locales, $domains, $this->transPaths);
if (!$domains) {
$domains = $this->getDomainsFromTranslatorBag($localTranslations);
}
if (!$deleteMissing && $force) {
$provider->write($localTranslations);
$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)));
return 0;
}
$providerTranslations = $provider->read($domains, $locales);
if ($deleteMissing) {
$provider->delete($providerTranslations->diff($localTranslations));
$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)));
// Read provider translations again, after missing translations deletion,
// to avoid push freshly deleted translations.
$providerTranslations = $provider->read($domains, $locales);
}
$translationsToWrite = $localTranslations->diff($providerTranslations);
if ($force) {
$translationsToWrite->addBag($localTranslations->intersect($providerTranslations));
}
$provider->write($translationsToWrite);
$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)));
return 0;
}
private function getDomainsFromTranslatorBag(TranslatorBag $translatorBag): array
{
$domains = [];
foreach ($translatorBag->getCatalogues() as $catalogue) {
$domains += $catalogue->getDomains();
}
return array_unique($domains);
}
}
================================================
FILE: Command/TranslationTrait.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Command;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
use Symfony\Component\Translation\TranslatorBag;
/**
* @internal
*/
trait TranslationTrait
{
private function readLocalTranslations(array $locales, array $domains, array $transPaths): TranslatorBag
{
$bag = new TranslatorBag();
foreach ($locales as $locale) {
$catalogue = new MessageCatalogue($locale);
foreach ($transPaths as $path) {
$this->reader->read($path, $catalogue);
}
if ($domains) {
foreach ($domains as $domain) {
$bag->addCatalogue($this->filterCatalogue($catalogue, $domain));
}
} else {
$bag->addCatalogue($catalogue);
}
}
return $bag;
}
private function filterCatalogue(MessageCatalogue $catalogue, string $domain): MessageCatalogue
{
$filteredCatalogue = new MessageCatalogue($catalogue->getLocale());
// extract intl-icu messages only
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
if ($intlMessages = $catalogue->all($intlDomain)) {
$filteredCatalogue->add($intlMessages, $intlDomain);
}
// extract all messages and subtract intl-icu messages
if ($messages = array_diff($catalogue->all($domain), $intlMessages)) {
$filteredCatalogue->add($messages, $domain);
}
foreach ($catalogue->getResources() as $resource) {
$filteredCatalogue->addResource($resource);
}
if ($metadata = $catalogue->getMetadata('', $intlDomain)) {
foreach ($metadata as $k => $v) {
$filteredCatalogue->setMetadata($k, $v, $intlDomain);
}
}
if ($metadata = $catalogue->getMetadata('', $domain)) {
foreach ($metadata as $k => $v) {
$filteredCatalogue->setMetadata($k, $v, $domain);
}
}
return $filteredCatalogue;
}
}
================================================
FILE: Command/XliffLintCommand.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\CI\GithubActionReporter;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\Util\XliffUtils;
/**
* Validates XLIFF files syntax and outputs encountered errors.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
* @author Robin Chalas <robin.chalas@gmail.com>
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
*/
#[AsCommand(name: 'lint:xliff', description: 'Lint an XLIFF file and outputs encountered errors')]
class XliffLintCommand extends Command
{
private string $format;
private bool $displayCorrectFiles;
private ?\Closure $directoryIteratorProvider;
private ?\Closure $isReadableProvider;
public function __construct(
?string $name = null,
?callable $directoryIteratorProvider = null,
?callable $isReadableProvider = null,
private bool $requireStrictFileNames = true,
) {
parent::__construct($name);
$this->directoryIteratorProvider = null === $directoryIteratorProvider ? null : $directoryIteratorProvider(...);
$this->isReadableProvider = null === $isReadableProvider ? null : $isReadableProvider(...);
}
protected function configure(): void
{
$this
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
->addOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())))
->setHelp(<<<EOF
The <info>%command.name%</info> command lints an XLIFF file and outputs to STDOUT
the first encountered syntax error.
You can validates XLIFF contents passed from STDIN:
<info>cat filename | php %command.full_name% -</info>
You can also validate the syntax of a file:
<info>php %command.full_name% filename</info>
Or of a whole directory:
<info>php %command.full_name% dirname</info>
The <info>--format</info> option specifies the format of the command output:
<info>php %command.full_name% dirname --format=json</info>
EOF
)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$filenames = (array) $input->getArgument('filename');
$this->format = $input->getOption('format') ?? (GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt');
$this->displayCorrectFiles = $output->isVerbose();
if (['-'] === $filenames) {
return $this->display($io, [$this->validate(file_get_contents('php://stdin'))]);
}
if (!$filenames) {
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
$filesInfo = [];
foreach ($filenames as $filename) {
if (!$this->isReadable($filename)) {
throw new RuntimeException(\sprintf('File or directory "%s" is not readable.', $filename));
}
foreach ($this->getFiles($filename) as $file) {
$filesInfo[] = $this->validate(file_get_contents($file), $file);
}
}
return $this->display($io, $filesInfo);
}
private function validate(string $content, ?string $file = null): array
{
$errors = [];
// Avoid: Warning DOMDocument::loadXML(): Empty string supplied as input
if ('' === trim($content)) {
return ['file' => $file, 'valid' => true];
}
$internal = libxml_use_internal_errors(true);
$document = new \DOMDocument();
$document->loadXML($content);
if (null !== $targetLanguage = $this->getTargetLanguageFromFile($document)) {
$normalizedLocalePattern = \sprintf('(%s|%s)', preg_quote($targetLanguage, '/'), preg_quote(str_replace('-', '_', $targetLanguage), '/'));
// strict file names require translation files to be named '____.locale.xlf'
// otherwise, both '____.locale.xlf' and 'locale.____.xlf' are allowed
// also, the regexp matching must be case-insensitive, as defined for 'target-language' values
// http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#target-language
$expectedFilenamePattern = $this->requireStrictFileNames ? \sprintf('/^.*\.(?i:%s)\.(?:xlf|xliff)/', $normalizedLocalePattern) : \sprintf('/^(?:.*\.(?i:%s)|(?i:%s)\..*)\.(?:xlf|xliff)/', $normalizedLocalePattern, $normalizedLocalePattern);
if (0 === preg_match($expectedFilenamePattern, basename($file))) {
$errors[] = [
'line' => -1,
'column' => -1,
'message' => \sprintf('There is a mismatch between the language included in the file name ("%s") and the "%s" value used in the "target-language" attribute of the file.', basename($file), $targetLanguage),
];
}
}
foreach (XliffUtils::validateSchema($document) as $xmlError) {
$errors[] = [
'line' => $xmlError['line'],
'column' => $xmlError['column'],
'message' => $xmlError['message'],
];
}
libxml_clear_errors();
libxml_use_internal_errors($internal);
return ['file' => $file, 'valid' => 0 === \count($errors), 'messages' => $errors];
}
private function display(SymfonyStyle $io, array $files): int
{
return match ($this->format) {
'txt' => $this->displayTxt($io, $files),
'json' => $this->displayJson($io, $files),
'github' => $this->displayTxt($io, $files, true),
default => throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
};
}
private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false): int
{
$countFiles = \count($filesInfo);
$erroredFiles = 0;
$githubReporter = $errorAsGithubAnnotations ? new GithubActionReporter($io) : null;
foreach ($filesInfo as $info) {
if ($info['valid'] && $this->displayCorrectFiles) {
$io->comment('<info>OK</info>'.($info['file'] ? \sprintf(' in %s', $info['file']) : ''));
} elseif (!$info['valid']) {
++$erroredFiles;
$io->text('<error> ERROR </error>'.($info['file'] ? \sprintf(' in %s', $info['file']) : ''));
$io->listing(array_map(static function ($error) use ($info, $githubReporter) {
// general document errors have a '-1' line number
$line = -1 === $error['line'] ? null : $error['line'];
$githubReporter?->error($error['message'], $info['file'], $line, null !== $line ? $error['column'] : null);
return null === $line ? $error['message'] : \sprintf('Line %d, Column %d: %s', $line, $error['column'], $error['message']);
}, $info['messages']));
}
}
if (0 === $erroredFiles) {
$io->success(\sprintf('All %d XLIFF files contain valid syntax.', $countFiles));
} else {
$io->warning(\sprintf('%d XLIFF files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles));
}
return min($erroredFiles, 1);
}
private function displayJson(SymfonyStyle $io, array $filesInfo): int
{
$errors = 0;
array_walk($filesInfo, static function (&$v) use (&$errors) {
$v['file'] = (string) $v['file'];
if (!$v['valid']) {
++$errors;
}
});
$io->writeln(json_encode($filesInfo, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
return min($errors, 1);
}
/**
* @return iterable<\SplFileInfo>
*/
private function getFiles(string $fileOrDirectory): iterable
{
if (is_file($fileOrDirectory)) {
yield new \SplFileInfo($fileOrDirectory);
return;
}
foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {
if (!\in_array($file->getExtension(), ['xlf', 'xliff'], true)) {
continue;
}
yield $file;
}
}
/**
* @return iterable<\SplFileInfo>
*/
private function getDirectoryIterator(string $directory): iterable
{
$default = static fn ($directory) => new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
\RecursiveIteratorIterator::LEAVES_ONLY
);
if (null !== $this->directoryIteratorProvider) {
return ($this->directoryIteratorProvider)($directory, $default);
}
return $default($directory);
}
private function isReadable(string $fileOrDirectory): bool
{
$default = static fn ($fileOrDirectory) => is_readable($fileOrDirectory);
if (null !== $this->isReadableProvider) {
return ($this->isReadableProvider)($fileOrDirectory, $default);
}
return $default($fileOrDirectory);
}
private function getTargetLanguageFromFile(\DOMDocument $xliffContents): ?string
{
foreach ($xliffContents->getElementsByTagName('file')[0]->attributes ?? [] as $attribute) {
if ('target-language' === $attribute->nodeName) {
return $attribute->nodeValue;
}
}
return null;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestOptionValuesFor('format')) {
$suggestions->suggestValues($this->getAvailableFormatOptions());
}
}
/** @return string[] */
private function getAvailableFormatOptions(): array
{
return ['txt', 'json', 'github'];
}
}
================================================
FILE: DataCollector/TranslationDataCollector.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\DataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
use Symfony\Component\Translation\DataCollectorTranslator;
use Symfony\Component\VarDumper\Cloner\Data;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*
* @final
*/
class TranslationDataCollector extends DataCollector implements LateDataCollectorInterface
{
public function __construct(
private DataCollectorTranslator $translator,
) {
}
public function lateCollect(): void
{
$messages = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages());
$this->data += $this->computeCount($messages);
$this->data['messages'] = $messages;
$this->data = $this->cloneVar($this->data);
}
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$this->data['locale'] = $this->translator->getLocale();
$this->data['fallback_locales'] = $this->translator->getFallbackLocales();
$this->data['global_parameters'] = $this->translator->getGlobalParameters();
}
public function reset(): void
{
$this->data = [];
}
public function getMessages(): array|Data
{
return $this->data['messages'] ?? [];
}
public function getCountMissings(): int
{
return $this->data[DataCollectorTranslator::MESSAGE_MISSING] ?? 0;
}
public function getCountFallbacks(): int
{
return $this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK] ?? 0;
}
public function getCountDefines(): int
{
return $this->data[DataCollectorTranslator::MESSAGE_DEFINED] ?? 0;
}
public function getLocale(): ?string
{
return !empty($this->data['locale']) ? $this->data['locale'] : null;
}
/**
* @internal
*/
public function getFallbackLocales(): Data|array
{
return (isset($this->data['fallback_locales']) && \count($this->data['fallback_locales']) > 0) ? $this->data['fallback_locales'] : [];
}
/**
* @internal
*/
public function getGlobalParameters(): Data|array
{
return $this->data['global_parameters'] ?? [];
}
public function getName(): string
{
return 'translation';
}
private function sanitizeCollectedMessages(array $messages): array
{
$result = [];
foreach ($messages as $key => $message) {
$messageId = $message['locale'].$message['domain'].$message['id'];
if (!isset($result[$messageId])) {
$message['count'] = 1;
$message['parameters'] = !empty($message['parameters']) ? [$message['parameters']] : [];
$messages[$key]['translation'] = $this->sanitizeString($message['translation']);
$result[$messageId] = $message;
} else {
if (!empty($message['parameters'])) {
$result[$messageId]['parameters'][] = $message['parameters'];
}
++$result[$messageId]['count'];
}
unset($messages[$key]);
}
return $result;
}
private function computeCount(array $messages): array
{
$count = [
DataCollectorTranslator::MESSAGE_DEFINED => 0,
DataCollectorTranslator::MESSAGE_MISSING => 0,
DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK => 0,
];
foreach ($messages as $message) {
++$count[$message['state']];
}
return $count;
}
private function sanitizeString(string $string, int $length = 80): string
{
$string = trim(preg_replace('/\s+/', ' ', $string));
if (false !== $encoding = mb_detect_encoding($string, null, true)) {
if (mb_strlen($string, $encoding) > $length) {
return mb_substr($string, 0, $length - 3, $encoding).'...';
}
} elseif (\strlen($string) > $length) {
return substr($string, 0, $length - 3).'...';
}
return $string;
}
}
================================================
FILE: DataCollectorTranslator.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
use Symfony\Contracts\Service\ResetInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
final class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface, WarmableInterface, ResetInterface
{
public const MESSAGE_DEFINED = 0;
public const MESSAGE_MISSING = 1;
public const MESSAGE_EQUALS_FALLBACK = 2;
private array $messages = [];
public function __construct(
private TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator,
) {
}
public function reset(): void
{
$this->messages = [];
}
public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
{
$trans = $this->translator->trans($id = (string) $id, $parameters, $domain, $locale);
$this->collectMessage($locale, $domain, $id, $trans, $parameters);
return $trans;
}
public function setLocale(string $locale): void
{
$this->translator->setLocale($locale);
}
public function getLocale(): string
{
return $this->translator->getLocale();
}
public function getCatalogue(?string $locale = null): MessageCatalogueInterface
{
return $this->translator->getCatalogue($locale);
}
public function getCatalogues(): array
{
return $this->translator->getCatalogues();
}
public function warmUp(string $cacheDir, ?string $buildDir = null): array
{
if ($this->translator instanceof WarmableInterface) {
return $this->translator->warmUp($cacheDir, $buildDir);
}
return [];
}
public function getFallbackLocales(): array
{
if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) {
return $this->translator->getFallbackLocales();
}
return [];
}
public function getGlobalParameters(): array
{
if ($this->translator instanceof Translator || method_exists($this->translator, 'getGlobalParameters')) {
return $this->translator->getGlobalParameters();
}
return [];
}
public function __call(string $method, array $args): mixed
{
return $this->translator->{$method}(...$args);
}
public function getCollectedMessages(): array
{
return $this->messages;
}
private function collectMessage(?string $locale, ?string $domain, string $id, string $translation, ?array $parameters = []): void
{
$domain ??= 'messages';
$catalogue = $this->translator->getCatalogue($locale);
$locale = $catalogue->getLocale();
$fallbackLocale = null;
if ($catalogue->defines($id, $domain)) {
$state = self::MESSAGE_DEFINED;
} elseif ($catalogue->has($id, $domain)) {
$state = self::MESSAGE_EQUALS_FALLBACK;
$fallbackCatalogue = $catalogue->getFallbackCatalogue();
while ($fallbackCatalogue) {
if ($fallbackCatalogue->defines($id, $domain)) {
$fallbackLocale = $fallbackCatalogue->getLocale();
break;
}
$fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();
}
} else {
$state = self::MESSAGE_MISSING;
}
$this->messages[] = [
'locale' => $locale,
'fallbackLocale' => $fallbackLocale,
'domain' => $domain,
'id' => $id,
'translation' => $translation,
'parameters' => $parameters,
'state' => $state,
'transChoiceNumber' => isset($parameters['%count%']) && is_numeric($parameters['%count%']) ? $parameters['%count%'] : null,
];
}
}
================================================
FILE: DependencyInjection/DataCollectorTranslatorPass.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Translation\TranslatorBagInterface;
/**
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
*/
class DataCollectorTranslatorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (!$container->has('translator')) {
return;
}
$translatorClass = $container->getParameterBag()->resolveValue($container->findDefinition('translator')->getClass());
if (!is_subclass_of($translatorClass, TranslatorBagInterface::class)) {
$container->removeDefinition('translator.data_collector');
$container->removeDefinition('data_collector.translation');
}
}
}
================================================
FILE: DependencyInjection/LoggingTranslatorPass.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\Translation\TranslatorBagInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class LoggingTranslatorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (!$container->hasAlias('logger') || !$container->hasAlias('translator')) {
return;
}
if (!$container->hasParameter('translator.logging') || !$container->getParameter('translator.logging')) {
return;
}
$translatorAlias = $container->getAlias('translator');
$definition = $container->getDefinition((string) $translatorAlias);
$class = $container->getParameterBag()->resolveValue($definition->getClass());
if (!$r = $container->getReflectionClass($class)) {
throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $translatorAlias));
}
if (!$r->isSubclassOf(TranslatorInterface::class) || !$r->isSubclassOf(TranslatorBagInterface::class)) {
return;
}
$container->getDefinition('translator.logging')->setDecoratedService('translator');
$warmer = $container->getDefinition('translation.warmer');
$subscriberAttributes = $warmer->getTag('container.service_subscriber');
$warmer->clearTag('container.service_subscriber');
foreach ($subscriberAttributes as $k => $v) {
if ((!isset($v['id']) || 'translator' !== $v['id']) && (!isset($v['key']) || 'translator' !== $v['key'])) {
$warmer->addTag('container.service_subscriber', $v);
}
}
$warmer->addTag('container.service_subscriber', ['key' => 'translator', 'id' => 'translator.logging.inner']);
}
}
================================================
FILE: DependencyInjection/TranslationDumperPass.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Adds tagged translation.formatter services to translation writer.
*/
class TranslationDumperPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition('translation.writer')) {
return;
}
$definition = $container->getDefinition('translation.writer');
foreach ($container->findTaggedServiceIds('translation.dumper', true) as $id => $attributes) {
$definition->addMethodCall('addDumper', [$attributes[0]['alias'], new Reference($id)]);
}
}
}
================================================
FILE: DependencyInjection/TranslationExtractorPass.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Adds tagged translation.extractor services to translation extractor.
*/
class TranslationExtractorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition('translation.extractor')) {
return;
}
$definition = $container->getDefinition('translation.extractor');
foreach ($container->findTaggedServiceIds('translation.extractor', true) as $id => $attributes) {
$definition->addMethodCall('addExtractor', [$attributes[0]['alias'] ?? $id, new Reference($id)]);
}
}
}
================================================
FILE: DependencyInjection/TranslatorPass.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class TranslatorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition('translator.default')) {
return;
}
$loaders = [];
$loaderRefs = [];
foreach ($container->findTaggedServiceIds('translation.loader', true) as $id => $attributes) {
$loaderRefs[$id] = new Reference($id);
$loaders[$id][] = $attributes[0]['alias'];
if (isset($attributes[0]['legacy-alias'])) {
$loaders[$id][] = $attributes[0]['legacy-alias'];
}
}
if ($container->hasDefinition('translation.reader')) {
$definition = $container->getDefinition('translation.reader');
foreach ($loaders as $id => $formats) {
foreach ($formats as $format) {
$definition->addMethodCall('addLoader', [$format, $loaderRefs[$id]]);
}
}
}
$container
->findDefinition('translator.default')
->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs))
->replaceArgument(3, $loaders)
;
if ($container->hasDefinition('validator') && $container->hasDefinition('translation.extractor.visitor.constraint')) {
$constraintVisitorDefinition = $container->getDefinition('translation.extractor.visitor.constraint');
$constraintClassNames = [];
foreach ($container->getDefinitions() as $definition) {
if (!$definition->hasTag('validator.constraint_validator')) {
continue;
}
// Resolve constraint validator FQCN even if defined as %foo.validator.class% parameter
$className = $container->getParameterBag()->resolveValue($definition->getClass());
// Extraction of the constraint class name from the Constraint Validator FQCN
$constraintClassNames[] = str_replace('Validator', '', substr(strrchr($className, '\\'), 1));
}
$constraintVisitorDefinition->setArgument(0, $constraintClassNames);
}
if (!$container->hasParameter('twig.default_path')) {
return;
}
$paths = array_keys($container->getDefinition('twig.template_iterator')->getArgument(1));
if ($container->hasDefinition('console.command.translation_debug')) {
$definition = $container->getDefinition('console.command.translation_debug');
$definition->replaceArgument(4, $container->getParameter('twig.default_path'));
if (\count($definition->getArguments()) > 6) {
$definition->replaceArgument(6, $paths);
}
}
if ($container->hasDefinition('console.command.translation_extract')) {
$definition = $container->getDefinition('console.command.translation_extract');
$definition->replaceArgument(5, $container->getParameter('twig.default_path'));
if (\count($definition->getArguments()) > 7) {
$definition->replaceArgument(7, $paths);
}
}
}
}
================================================
FILE: DependencyInjection/TranslatorPathsPass.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver;
/**
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class TranslatorPathsPass extends AbstractRecursivePass
{
protected bool $skipScalars = true;
private int $level = 0;
/**
* @var array<string, bool>
*/
private array $paths = [];
/**
* @var array<int, Definition>
*/
private array $definitions = [];
/**
* @var array<string, array<string, bool>>
*/
private array $controllers = [];
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition('translator')) {
return;
}
foreach ($this->findControllerArguments($container) as $controller => $argument) {
$id = substr($controller, 0, strpos($controller, ':') ?: \strlen($controller));
if ($container->hasDefinition($id)) {
[$locatorRef] = $argument->getValues();
$this->controllers[(string) $locatorRef][$container->getDefinition($id)->getClass()] = true;
}
}
try {
parent::process($container);
$paths = [];
foreach ($this->paths as $class => $_) {
if (($r = $container->getReflectionClass($class)) && !$r->isInterface()) {
$paths[] = $r->getFileName();
foreach ($r->getTraits() as $trait) {
$paths[] = $trait->getFileName();
}
}
}
if ($paths) {
if ($container->hasDefinition('console.command.translation_debug')) {
$definition = $container->getDefinition('console.command.translation_debug');
$definition->replaceArgument(6, array_merge($definition->getArgument(6), $paths));
}
if ($container->hasDefinition('console.command.translation_extract')) {
$definition = $container->getDefinition('console.command.translation_extract');
$definition->replaceArgument(7, array_merge($definition->getArgument(7), $paths));
}
}
} finally {
$this->level = 0;
$this->paths = [];
$this->definitions = [];
}
}
protected function processValue(mixed $value, bool $isRoot = false): mixed
{
if ($value instanceof Reference) {
if ('translator' === (string) $value) {
for ($i = $this->level - 1; $i >= 0; --$i) {
$class = $this->definitions[$i]->getClass();
if (ServiceLocator::class === $class) {
if (!isset($this->controllers[$this->currentId ?? ''])) {
continue;
}
foreach ($this->controllers[$this->currentId ?? ''] as $class => $_) {
$this->paths[$class] = true;
}
} else {
$this->paths[$class] = true;
}
break;
}
}
return $value;
}
if ($value instanceof Definition) {
$this->definitions[$this->level++] = $value;
$value = parent::processValue($value, $isRoot);
unset($this->definitions[--$this->level]);
return $value;
}
return parent::processValue($value, $isRoot);
}
private function findControllerArguments(ContainerBuilder $container): array
{
if (!$container->has('argument_resolver.service')) {
return [];
}
$resolverDef = $container->findDefinition('argument_resolver.service');
if (TraceableValueResolver::class === $resolverDef->getClass()) {
$resolverDef = $container->getDefinition($resolverDef->getArgument(0));
}
$argument = $resolverDef->getArgument(0);
if ($argument instanceof Reference) {
$argument = $container->getDefinition($argument);
}
return $argument->getArgument(0);
}
}
================================================
FILE: Dumper/CsvFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\MessageCatalogue;
/**
* CsvFileDumper generates a csv formatted string representation of a message catalogue.
*
* @author Stealth35
*/
class CsvFileDumper extends FileDumper
{
private string $delimiter = ';';
private string $enclosure = '"';
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
$handle = fopen('php://memory', 'r+');
foreach ($messages->all($domain) as $source => $target) {
fputcsv($handle, [$source, $target], $this->delimiter, $this->enclosure, '\\');
}
rewind($handle);
$output = stream_get_contents($handle);
fclose($handle);
return $output;
}
/**
* Sets the delimiter and escape character for CSV.
*/
public function setCsvControl(string $delimiter = ';', string $enclosure = '"'): void
{
$this->delimiter = $delimiter;
$this->enclosure = $enclosure;
}
protected function getExtension(): string
{
return 'csv';
}
}
================================================
FILE: Dumper/DumperInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\MessageCatalogue;
/**
* DumperInterface is the interface implemented by all translation dumpers.
* There is no common option.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
interface DumperInterface
{
/**
* Dumps the message catalogue.
*
* @param array $options Options that are used by the dumper
*/
public function dump(MessageCatalogue $messages, array $options = []): void;
}
================================================
FILE: Dumper/FileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\Exception\RuntimeException;
use Symfony\Component\Translation\MessageCatalogue;
/**
* FileDumper is an implementation of DumperInterface that dump a message catalogue to file(s).
*
* Options:
* - path (mandatory): the directory where the files should be saved
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
abstract class FileDumper implements DumperInterface
{
/**
* A template for the relative paths to files.
*/
protected string $relativePathTemplate = '%domain%.%locale%.%extension%';
/**
* Sets the template for the relative paths to files.
*/
public function setRelativePathTemplate(string $relativePathTemplate): void
{
$this->relativePathTemplate = $relativePathTemplate;
}
public function dump(MessageCatalogue $messages, array $options = []): void
{
if (!\array_key_exists('path', $options)) {
throw new InvalidArgumentException('The file dumper needs a path option.');
}
// save a file for each domain
foreach ($messages->getDomains() as $domain) {
$fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale());
if (!file_exists($fullpath)) {
$directory = \dirname($fullpath);
if (!file_exists($directory) && !@mkdir($directory, 0o777, true)) {
throw new RuntimeException(\sprintf('Unable to create directory "%s".', $directory));
}
}
$intlDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX;
$intlMessages = $messages->all($intlDomain);
if ($intlMessages) {
$intlPath = $options['path'].'/'.$this->getRelativePath($intlDomain, $messages->getLocale());
file_put_contents($intlPath, $this->formatCatalogue($messages, $intlDomain, $options));
$messages->replace([], $intlDomain);
try {
if ($messages->all($domain)) {
file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options));
}
continue;
} finally {
$messages->replace($intlMessages, $intlDomain);
}
}
file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options));
}
}
/**
* Transforms a domain of a message catalogue to its string representation.
*/
abstract public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string;
/**
* Gets the file extension of the dumper.
*/
abstract protected function getExtension(): string;
/**
* Gets the relative file path using the template.
*/
private function getRelativePath(string $domain, string $locale): string
{
return strtr($this->relativePathTemplate, [
'%domain%' => $domain,
'%locale%' => $locale,
'%extension%' => $this->getExtension(),
]);
}
}
================================================
FILE: Dumper/IcuResFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\MessageCatalogue;
/**
* IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue.
*
* @author Stealth35
*/
class IcuResFileDumper extends FileDumper
{
protected string $relativePathTemplate = '%domain%/%locale%.%extension%';
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
$data = $indexes = $resources = '';
foreach ($messages->all($domain) as $source => $target) {
$indexes .= pack('v', \strlen($data) + 28);
$data .= $source."\0";
}
$data .= $this->writePadding($data);
$keyTop = $this->getPosition($data);
foreach ($messages->all($domain) as $source => $target) {
$resources .= pack('V', $this->getPosition($data));
$data .= pack('V', \strlen($target))
.mb_convert_encoding($target."\0", 'UTF-16LE', 'UTF-8')
.$this->writePadding($data)
;
}
$resOffset = $this->getPosition($data);
$data .= pack('v', \count($messages->all($domain)))
.$indexes
.$this->writePadding($data)
.$resources
;
$bundleTop = $this->getPosition($data);
$root = pack('V7',
$resOffset + (2 << 28), // Resource Offset + Resource Type
6, // Index length
$keyTop, // Index keys top
$bundleTop, // Index resources top
$bundleTop, // Index bundle top
\count($messages->all($domain)), // Index max table length
0 // Index attributes
);
$header = pack('vC2v4C12@32',
32, // Header size
0xDA, 0x27, // Magic number 1 and 2
20, 0, 0, 2, // Rest of the header, ..., Size of a char
0x52, 0x65, 0x73, 0x42, // Data format identifier
1, 2, 0, 0, // Data version
1, 4, 0, 0 // Unicode version
);
return $header.$root.$data;
}
private function writePadding(string $data): ?string
{
$padding = \strlen($data) % 4;
return $padding ? str_repeat("\xAA", 4 - $padding) : null;
}
private function getPosition(string $data): float|int
{
return (\strlen($data) + 28) / 4;
}
protected function getExtension(): string
{
return 'res';
}
}
================================================
FILE: Dumper/IniFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\MessageCatalogue;
/**
* IniFileDumper generates an ini formatted string representation of a message catalogue.
*
* @author Stealth35
*/
class IniFileDumper extends FileDumper
{
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
$output = '';
foreach ($messages->all($domain) as $source => $target) {
$escapeTarget = str_replace('"', '\"', $target);
$output .= $source.'="'.$escapeTarget."\"\n";
}
return $output;
}
protected function getExtension(): string
{
return 'ini';
}
}
================================================
FILE: Dumper/JsonFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\MessageCatalogue;
/**
* JsonFileDumper generates an json formatted string representation of a message catalogue.
*
* @author singles
*/
class JsonFileDumper extends FileDumper
{
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
$flags = $options['json_encoding'] ?? \JSON_PRETTY_PRINT;
return json_encode($messages->all($domain), $flags);
}
protected function getExtension(): string
{
return 'json';
}
}
================================================
FILE: Dumper/MoFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\Loader\MoFileLoader;
use Symfony\Component\Translation\MessageCatalogue;
/**
* MoFileDumper generates a gettext formatted string representation of a message catalogue.
*
* @author Stealth35
*/
class MoFileDumper extends FileDumper
{
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
$sources = $targets = $sourceOffsets = $targetOffsets = '';
$offsets = [];
$size = 0;
foreach ($messages->all($domain) as $source => $target) {
$offsets[] = array_map('strlen', [$sources, $source, $targets, $target]);
$sources .= "\0".$source;
$targets .= "\0".$target;
++$size;
}
$header = [
'magicNumber' => MoFileLoader::MO_LITTLE_ENDIAN_MAGIC,
'formatRevision' => 0,
'count' => $size,
'offsetId' => MoFileLoader::MO_HEADER_SIZE,
'offsetTranslated' => MoFileLoader::MO_HEADER_SIZE + (8 * $size),
'sizeHashes' => 0,
'offsetHashes' => MoFileLoader::MO_HEADER_SIZE + (16 * $size),
];
$sourcesSize = \strlen($sources);
$sourcesStart = $header['offsetHashes'] + 1;
foreach ($offsets as $offset) {
$sourceOffsets .= $this->writeLong($offset[1])
.$this->writeLong($offset[0] + $sourcesStart);
$targetOffsets .= $this->writeLong($offset[3])
.$this->writeLong($offset[2] + $sourcesStart + $sourcesSize);
}
return implode('', array_map($this->writeLong(...), $header))
.$sourceOffsets
.$targetOffsets
.$sources
.$targets;
}
protected function getExtension(): string
{
return 'mo';
}
private function writeLong(mixed $str): string
{
return pack('V*', $str);
}
}
================================================
FILE: Dumper/PhpFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\MessageCatalogue;
/**
* PhpFileDumper generates PHP files from a message catalogue.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
class PhpFileDumper extends FileDumper
{
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
return "<?php\n\nreturn ".var_export($messages->all($domain), true).";\n";
}
protected function getExtension(): string
{
return 'php';
}
}
================================================
FILE: Dumper/PoFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\MessageCatalogue;
/**
* PoFileDumper generates a gettext formatted string representation of a message catalogue.
*
* @author Stealth35
*/
class PoFileDumper extends FileDumper
{
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
$output = 'msgid ""'."\n";
$output .= 'msgstr ""'."\n";
$output .= '"Content-Type: text/plain; charset=UTF-8\n"'."\n";
$output .= '"Content-Transfer-Encoding: 8bit\n"'."\n";
$output .= '"Language: '.$messages->getLocale().'\n"'."\n";
$output .= "\n";
$newLine = false;
foreach ($messages->all($domain) as $source => $target) {
if ($newLine) {
$output .= "\n";
} else {
$newLine = true;
}
$metadata = $messages->getMetadata($source, $domain);
if (isset($metadata['comments'])) {
$output .= $this->formatComments($metadata['comments']);
}
if (isset($metadata['flags'])) {
$output .= $this->formatComments(implode(',', (array) $metadata['flags']), ',');
}
if (isset($metadata['sources'])) {
$output .= $this->formatComments(implode(' ', (array) $metadata['sources']), ':');
}
$sourceRules = $this->getStandardRules($source);
$targetRules = $this->getStandardRules($target);
if (2 == \count($sourceRules) && [] !== $targetRules) {
$output .= \sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0]));
$output .= \sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1]));
foreach ($targetRules as $i => $targetRule) {
$output .= \sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule));
}
} else {
$output .= \sprintf('msgid "%s"'."\n", $this->escape($source));
$output .= \sprintf('msgstr "%s"'."\n", $this->escape($target));
}
}
return $output;
}
private function getStandardRules(string $id): array
{
// Partly copied from TranslatorTrait::trans.
$parts = [];
if (preg_match('/^\|++$/', $id)) {
$parts = explode('|', $id);
} elseif (preg_match_all('/(?:\|\||[^\|])++/', $id, $matches)) {
$parts = $matches[0];
}
$intervalRegexp = <<<'EOF'
/^(?P<interval>
({\s*
(\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
\s*})
|
(?P<left_delimiter>[\[\]])
\s*
(?P<left>-Inf|\-?\d+(\.\d+)?)
\s*,\s*
(?P<right>\+?Inf|\-?\d+(\.\d+)?)
\s*
(?P<right_delimiter>[\[\]])
)\s*(?P<message>.*?)$/xs
EOF;
$standardRules = [];
foreach ($parts as $part) {
$part = trim(str_replace('||', '|', $part));
if (preg_match($intervalRegexp, $part)) {
// Explicit rule is not a standard rule.
return [];
}
$standardRules[] = $part;
}
return $standardRules;
}
protected function getExtension(): string
{
return 'po';
}
private function escape(string $str): string
{
return addcslashes($str, "\0..\37\42\134");
}
private function formatComments(string|array $comments, string $prefix = ''): ?string
{
$output = null;
foreach ((array) $comments as $comment) {
$output .= \sprintf('#%s %s'."\n", $prefix, $comment);
}
return $output;
}
}
================================================
FILE: Dumper/QtFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\MessageCatalogue;
/**
* QtFileDumper generates ts files from a message catalogue.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class QtFileDumper extends FileDumper
{
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->formatOutput = true;
$ts = $dom->appendChild($dom->createElement('TS'));
$context = $ts->appendChild($dom->createElement('context'));
$context->appendChild($dom->createElement('name', $domain));
foreach ($messages->all($domain) as $source => $target) {
$message = $context->appendChild($dom->createElement('message'));
$metadata = $messages->getMetadata($source, $domain);
if (isset($metadata['sources'])) {
foreach ((array) $metadata['sources'] as $location) {
$loc = explode(':', $location, 2);
$location = $message->appendChild($dom->createElement('location'));
$location->setAttribute('filename', $loc[0]);
if (isset($loc[1])) {
$location->setAttribute('line', $loc[1]);
}
}
}
$message->appendChild($dom->createElement('source', $source));
$message->appendChild($dom->createElement('translation', $target));
}
return $dom->saveXML();
}
protected function getExtension(): string
{
return 'ts';
}
}
================================================
FILE: Dumper/XliffFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\MessageCatalogue;
/**
* XliffFileDumper generates xliff files from a message catalogue.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
class XliffFileDumper extends FileDumper
{
public function __construct(
private string $extension = 'xlf',
) {
}
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
$xliffVersion = '1.2';
if (\array_key_exists('xliff_version', $options)) {
$xliffVersion = $options['xliff_version'];
}
if (\array_key_exists('default_locale', $options)) {
$defaultLocale = $options['default_locale'];
} else {
$defaultLocale = \Locale::getDefault();
}
if ('1.2' === $xliffVersion) {
return $this->dumpXliff1($defaultLocale, $messages, $domain, $options);
}
if ('2.0' === $xliffVersion) {
return $this->dumpXliff2($defaultLocale, $messages, $domain);
}
throw new InvalidArgumentException(\sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion));
}
protected function getExtension(): string
{
return $this->extension;
}
private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = []): string
{
$toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony'];
if (\array_key_exists('tool_info', $options)) {
$toolInfo = array_merge($toolInfo, $options['tool_info']);
}
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->formatOutput = true;
$xliff = $dom->appendChild($dom->createElement('xliff'));
$xliff->setAttribute('version', '1.2');
$xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2');
$xliffFile = $xliff->appendChild($dom->createElement('file'));
$xliffFile->setAttribute('source-language', str_replace('_', '-', $defaultLocale));
$xliffFile->setAttribute('target-language', str_replace('_', '-', $messages->getLocale()));
$xliffFile->setAttribute('datatype', 'plaintext');
$xliffFile->setAttribute('original', 'file.ext');
$xliffHead = $xliffFile->appendChild($dom->createElement('header'));
$xliffTool = $xliffHead->appendChild($dom->createElement('tool'));
foreach ($toolInfo as $id => $value) {
$xliffTool->setAttribute($id, $value);
}
if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) {
$xliffPropGroup = $xliffHead->appendChild($dom->createElement('prop-group'));
foreach ($catalogueMetadata as $key => $value) {
$xliffProp = $xliffPropGroup->appendChild($dom->createElement('prop'));
$xliffProp->setAttribute('prop-type', $key);
$xliffProp->appendChild($dom->createTextNode($value));
}
}
$xliffBody = $xliffFile->appendChild($dom->createElement('body'));
foreach ($messages->all($domain) as $source => $target) {
$translation = $dom->createElement('trans-unit');
$translation->setAttribute('id', strtr(substr(base64_encode(hash('xxh128', $source, true)), 0, 7), '/+', '._'));
$translation->setAttribute('resname', $source);
$s = $translation->appendChild($dom->createElement('source'));
$s->appendChild($dom->createTextNode($source));
// Does the target contain characters requiring a CDATA section?
$text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target);
$targetElement = $dom->createElement('target');
$metadata = $messages->getMetadata($source, $domain);
if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) {
foreach ($metadata['target-attributes'] as $name => $value) {
$targetElement->setAttribute($name, $value);
}
}
$t = $translation->appendChild($targetElement);
$t->appendChild($text);
if ($this->hasMetadataArrayInfo('notes', $metadata)) {
foreach ($metadata['notes'] as $note) {
if (!isset($note['content'])) {
continue;
}
$n = $translation->appendChild($dom->createElement('note'));
$n->appendChild($dom->createTextNode($note['content']));
if (isset($note['priority'])) {
$n->setAttribute('priority', $note['priority']);
}
if (isset($note['from'])) {
$n->setAttribute('from', $note['from']);
}
}
}
$xliffBody->appendChild($translation);
}
return $dom->saveXML();
}
private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain): string
{
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->formatOutput = true;
$xliff = $dom->appendChild($dom->createElement('xliff'));
$xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:2.0');
$xliff->setAttribute('version', '2.0');
$xliff->setAttribute('srcLang', str_replace('_', '-', $defaultLocale));
$xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale()));
$xliffFile = $xliff->appendChild($dom->createElement('file'));
if (str_ends_with($domain, MessageCatalogue::INTL_DOMAIN_SUFFIX)) {
$xliffFile->setAttribute('id', substr($domain, 0, -\strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX)).'.'.$messages->getLocale());
} else {
$xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale());
}
if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) {
$xliff->setAttribute('xmlns:m', 'urn:oasis:names:tc:xliff:metadata:2.0');
$xliffMetadata = $xliffFile->appendChild($dom->createElement('m:metadata'));
foreach ($catalogueMetadata as $key => $value) {
$xliffMeta = $xliffMetadata->appendChild($dom->createElement('prop'));
$xliffMeta->setAttribute('type', $key);
$xliffMeta->appendChild($dom->createTextNode($value));
}
}
foreach ($messages->all($domain) as $source => $target) {
$translation = $dom->createElement('unit');
$translation->setAttribute('id', strtr(substr(base64_encode(hash('xxh128', $source, true)), 0, 7), '/+', '._'));
if (\strlen($source) <= 80) {
$translation->setAttribute('name', $source);
}
$metadata = $messages->getMetadata($source, $domain);
// Add notes section
if ($this->hasMetadataArrayInfo('notes', $metadata) && $metadata['notes']) {
$notesElement = $dom->createElement('notes');
foreach ($metadata['notes'] as $note) {
$n = $dom->createElement('note');
$n->appendChild($dom->createTextNode($note['content'] ?? ''));
unset($note['content']);
foreach ($note as $name => $value) {
$n->setAttribute($name, $value);
}
$notesElement->appendChild($n);
}
$translation->appendChild($notesElement);
}
$segment = $translation->appendChild($dom->createElement('segment'));
if ($this->hasMetadataArrayInfo('segment-attributes', $metadata)) {
foreach ($metadata['segment-attributes'] as $name => $value) {
$segment->setAttribute($name, $value);
}
}
$s = $segment->appendChild($dom->createElement('source'));
$s->appendChild($dom->createTextNode($source));
// Does the target contain characters requiring a CDATA section?
$text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target);
$targetElement = $dom->createElement('target');
if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) {
foreach ($metadata['target-attributes'] as $name => $value) {
$targetElement->setAttribute($name, $value);
}
}
$t = $segment->appendChild($targetElement);
$t->appendChild($text);
$xliffFile->appendChild($translation);
}
return $dom->saveXML();
}
private function hasMetadataArrayInfo(string $key, ?array $metadata = null): bool
{
return is_iterable($metadata[$key] ?? null);
}
}
================================================
FILE: Dumper/YamlFileDumper.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Dumper;
use Symfony\Component\Translation\Exception\LogicException;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Util\ArrayConverter;
use Symfony\Component\Yaml\Yaml;
/**
* YamlFileDumper generates yaml files from a message catalogue.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
class YamlFileDumper extends FileDumper
{
public function __construct(
private string $extension = 'yml',
) {
}
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
{
if (!class_exists(Yaml::class)) {
throw new LogicException('Dumping translations in the YAML format requires the Symfony Yaml component.');
}
$data = $messages->all($domain);
if (isset($options['as_tree']) && $options['as_tree']) {
$data = ArrayConverter::expandToTree($data);
}
if (isset($options['inline']) && ($inline = (int) $options['inline']) > 0) {
return Yaml::dump($data, $inline);
}
return Yaml::dump($data);
}
protected function getExtension(): string
{
return $this->extension;
}
}
================================================
FILE: Exception/ExceptionInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
/**
* Exception interface for all exceptions thrown by the component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ExceptionInterface extends \Throwable
{
}
================================================
FILE: Exception/IncompleteDsnException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
class IncompleteDsnException extends InvalidArgumentException
{
public function __construct(string $message, ?string $dsn = null, ?\Throwable $previous = null)
{
if ($dsn) {
$message = \sprintf('Invalid "%s" provider DSN: ', $dsn).$message;
}
parent::__construct($message, 0, $previous);
}
}
================================================
FILE: Exception/InvalidArgumentException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
/**
* Base InvalidArgumentException for the Translation component.
*
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
================================================
FILE: Exception/InvalidResourceException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
/**
* Thrown when a resource cannot be loaded.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class InvalidResourceException extends \InvalidArgumentException implements ExceptionInterface
{
}
================================================
FILE: Exception/LogicException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
/**
* Base LogicException for Translation component.
*
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class LogicException extends \LogicException implements ExceptionInterface
{
}
================================================
FILE: Exception/MissingRequiredOptionException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
/**
* @author Oskar Stark <oskarstark@googlemail.com>
*/
class MissingRequiredOptionException extends IncompleteDsnException
{
public function __construct(string $option, ?string $dsn = null, ?\Throwable $previous = null)
{
$message = \sprintf('The option "%s" is required but missing.', $option);
parent::__construct($message, $dsn, $previous);
}
}
================================================
FILE: Exception/NotFoundResourceException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
/**
* Thrown when a resource does not exist.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class NotFoundResourceException extends \InvalidArgumentException implements ExceptionInterface
{
}
================================================
FILE: Exception/ProviderException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class ProviderException extends RuntimeException implements ProviderExceptionInterface
{
private string $debug;
public function __construct(
string $message,
private ResponseInterface $response,
int $code = 0,
?\Exception $previous = null,
) {
$this->debug = $response->getInfo('debug') ?? '';
parent::__construct($message, $code, $previous);
}
public function getResponse(): ResponseInterface
{
return $this->response;
}
public function getDebug(): string
{
return $this->debug;
}
}
================================================
FILE: Exception/ProviderExceptionInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ProviderExceptionInterface extends ExceptionInterface
{
/*
* Returns debug info coming from the Symfony\Contracts\HttpClient\ResponseInterface
*/
public function getDebug(): string;
}
================================================
FILE: Exception/RuntimeException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
/**
* Base RuntimeException for the Translation component.
*
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
================================================
FILE: Exception/UnsupportedSchemeException.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Exception;
use Symfony\Component\Translation\Bridge;
use Symfony\Component\Translation\Provider\Dsn;
class UnsupportedSchemeException extends LogicException
{
private const SCHEME_TO_PACKAGE_MAP = [
'crowdin' => [
'class' => Bridge\Crowdin\CrowdinProviderFactory::class,
'package' => 'symfony/crowdin-translation-provider',
],
'loco' => [
'class' => Bridge\Loco\LocoProviderFactory::class,
'package' => 'symfony/loco-translation-provider',
],
'lokalise' => [
'class' => Bridge\Lokalise\LokaliseProviderFactory::class,
'package' => 'symfony/lokalise-translation-provider',
],
'phrase' => [
'class' => Bridge\Phrase\PhraseProviderFactory::class,
'package' => 'symfony/phrase-translation-provider',
],
];
public function __construct(Dsn $dsn, ?string $name = null, array $supported = [])
{
$provider = $dsn->getScheme();
if (false !== $pos = strpos($provider, '+')) {
$provider = substr($provider, 0, $pos);
}
$package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null;
if ($package && !class_exists($package['class'])) {
parent::__construct(\sprintf('Unable to synchronize translations via "%s" as the provider is not installed. Try running "composer require %s".', $provider, $package['package']));
return;
}
$message = \sprintf('The "%s" scheme is not supported', $dsn->getScheme());
if ($name && $supported) {
$message .= \sprintf('; supported schemes for translation provider "%s" are: "%s"', $name, implode('", "', $supported));
}
parent::__construct($message.'.');
}
}
================================================
FILE: Extractor/AbstractFileExtractor.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Extractor;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
/**
* Base class used by classes that extract translation messages from files.
*
* @author Marcos D. Sánchez <marcosdsanchez@gmail.com>
*/
abstract class AbstractFileExtractor
{
protected function extractFiles(string|iterable $resource): iterable
{
if (is_iterable($resource)) {
$files = [];
foreach ($resource as $file) {
if ($this->canBeExtracted($file)) {
$files[] = $this->toSplFileInfo($file);
}
}
} elseif (is_file($resource)) {
$files = $this->canBeExtracted($resource) ? [$this->toSplFileInfo($resource)] : [];
} else {
$files = $this->extractFromDirectory($resource);
}
return $files;
}
private function toSplFileInfo(string $file): \SplFileInfo
{
return new \SplFileInfo($file);
}
/**
* @throws InvalidArgumentException
*/
protected function isFile(string $file): bool
{
if (!is_file($file)) {
throw new InvalidArgumentException(\sprintf('The "%s" file does not exist.', $file));
}
return true;
}
abstract protected function canBeExtracted(string $file): bool;
abstract protected function extractFromDirectory(string|array $resource): iterable;
}
================================================
FILE: Extractor/ChainExtractor.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Extractor;
use Symfony\Component\Translation\MessageCatalogue;
/**
* ChainExtractor extracts translation messages from template files.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
class ChainExtractor implements ExtractorInterface
{
/**
* The extractors.
*
* @var ExtractorInterface[]
*/
private array $extractors = [];
/**
* Adds a loader to the translation extractor.
*/
public function addExtractor(string $format, ExtractorInterface $extractor): void
{
$this->extractors[$format] = $extractor;
}
public function setPrefix(string $prefix): void
{
foreach ($this->extractors as $extractor) {
$extractor->setPrefix($prefix);
}
}
public function extract(string|iterable $directory, MessageCatalogue $catalogue): void
{
foreach ($this->extractors as $extractor) {
$extractor->extract($directory, $catalogue);
}
}
}
================================================
FILE: Extractor/ExtractorInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Extractor;
use Symfony\Component\Translation\MessageCatalogue;
/**
* Extracts translation messages from a directory or files to the catalogue.
* New found messages are injected to the catalogue using the prefix.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
interface ExtractorInterface
{
/**
* Extracts translation messages from files, a file or a directory to the catalogue.
*
* @param string|iterable<string> $resource Files, a file or a directory
*/
public function extract(string|iterable $resource, MessageCatalogue $catalogue): void;
/**
* Sets the prefix that should be used for new found messages.
*/
public function setPrefix(string $prefix): void;
}
================================================
FILE: Extractor/PhpAstExtractor.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Extractor;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor;
use PhpParser\Parser;
use PhpParser\ParserFactory;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Translation\Extractor\Visitor\AbstractVisitor;
use Symfony\Component\Translation\MessageCatalogue;
/**
* PhpAstExtractor extracts translation messages from a PHP AST.
*
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*/
final class PhpAstExtractor extends AbstractFileExtractor implements ExtractorInterface
{
private Parser $parser;
public function __construct(
/**
* @param iterable<AbstractVisitor&NodeVisitor> $visitors
*/
private readonly iterable $visitors,
private string $prefix = '',
) {
if (!class_exists(ParserFactory::class)) {
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));
}
$this->parser = (new ParserFactory())->createForHostVersion();
}
public function extract(iterable|string $resource, MessageCatalogue $catalogue): void
{
foreach ($this->extractFiles($resource) as $file) {
$traverser = new NodeTraverser();
// This is needed to resolve namespaces in class methods/constants.
$nameResolver = new NodeVisitor\NameResolver();
$traverser->addVisitor($nameResolver);
foreach ($this->visitors as $visitor) {
$visitor->initialize($catalogue, $file, $this->prefix);
$traverser->addVisitor($visitor);
}
$nodes = $this->parser->parse(file_get_contents($file));
$traverser->traverse($nodes);
}
}
public function setPrefix(string $prefix): void
{
$this->prefix = $prefix;
}
protected function canBeExtracted(string $file): bool
{
return 'php' === pathinfo($file, \PATHINFO_EXTENSION)
&& $this->isFile($file)
&& preg_match('/\bt\(|->trans\(|TranslatableMessage|Symfony\\\\Component\\\\Validator\\\\Constraints/i', file_get_contents($file));
}
protected function extractFromDirectory(array|string $resource): iterable|Finder
{
if (!class_exists(Finder::class)) {
throw new \LogicException(\sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class));
}
return (new Finder())->files()->name('*.php')->in($resource);
}
}
================================================
FILE: Extractor/Visitor/AbstractVisitor.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Extractor\Visitor;
use PhpParser\Node;
use Symfony\Component\Translation\MessageCatalogue;
/**
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*/
abstract class AbstractVisitor
{
private MessageCatalogue $catalogue;
private \SplFileInfo $file;
private string $messagePrefix;
public function initialize(MessageCatalogue $catalogue, \SplFileInfo $file, string $messagePrefix): void
{
$this->catalogue = $catalogue;
$this->file = $file;
$this->messagePrefix = $messagePrefix;
}
protected function addMessageToCatalogue(string $message, ?string $domain, int $line): void
{
$domain ??= 'messages';
$this->catalogue->set($message, $this->messagePrefix.$message, $domain);
$metadata = $this->catalogue->getMetadata($message, $domain) ?? [];
$normalizedFilename = preg_replace('{[\\\\/]+}', '/', $this->file);
$metadata['sources'][] = $normalizedFilename.':'.$line;
$this->catalogue->setMetadata($message, $metadata, $domain);
}
protected function getStringArguments(Node\Expr\CallLike|Node\Attribute|Node\Expr\New_ $node, int|string $index, bool $indexIsRegex = false): array
{
if (\is_string($index)) {
return $this->getStringNamedArguments($node, $index, $indexIsRegex);
}
$args = $node instanceof Node\Expr\CallLike ? $node->getRawArgs() : $node->args;
if (!($arg = $args[$index] ?? null) instanceof Node\Arg) {
return [];
}
return (array) $this->getStringValue($arg->value);
}
protected function hasNodeNamedArguments(Node\Expr\CallLike|Node\Attribute|Node\Expr\New_ $node): bool
{
$args = $node instanceof Node\Expr\CallLike ? $node->getRawArgs() : $node->args;
foreach ($args as $arg) {
if ($arg instanceof Node\Arg && null !== $arg->name) {
return true;
}
}
return false;
}
protected function nodeFirstNamedArgumentIndex(Node\Expr\CallLike|Node\Attribute|Node\Expr\New_ $node): int
{
$args = $node instanceof Node\Expr\CallLike ? $node->getRawArgs() : $node->args;
foreach ($args as $i => $arg) {
if ($arg instanceof Node\Arg && null !== $arg->name) {
return $i;
}
}
return \PHP_INT_MAX;
}
private function getStringNamedArguments(Node\Expr\CallLike|Node\Attribute $node, ?string $argumentName = null, bool $isArgumentNamePattern = false): array
{
$args = $node instanceof Node\Expr\CallLike ? $node->getArgs() : $node->args;
$argumentValues = [];
foreach ($args as $arg) {
if (!$isArgumentNamePattern && $arg->name?->toString() === $argumentName) {
$argumentValues[] = $this->getStringValue($arg->value);
} elseif ($isArgumentNamePattern && preg_match($argumentName, $arg->name?->toString() ?? '') > 0) {
$argumentValues[] = $this->getStringValue($arg->value);
}
}
return array_filter($argumentValues);
}
private function getStringValue(Node $node): ?string
{
if ($node instanceof Node\Scalar\String_) {
return $node->value;
}
if ($node instanceof Node\Expr\BinaryOp\Concat) {
if (null === $left = $this->getStringValue($node->left)) {
return null;
}
if (null === $right = $this->getStringValue($node->right)) {
return null;
}
return $left.$right;
}
if ($node instanceof Node\Expr\Assign && $node->expr instanceof Node\Scalar\String_) {
return $node->expr->value;
}
if ($node instanceof Node\Expr\ClassConstFetch) {
try {
$reflection = new \ReflectionClass($node->class->toString());
$constant = $reflection->getReflectionConstant($node->name->toString());
if (false !== $constant && \is_string($constant->getValue())) {
return $constant->getValue();
}
} catch (\ReflectionException) {
}
}
return null;
}
}
================================================
FILE: Extractor/Visitor/ConstraintVisitor.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Extractor\Visitor;
use PhpParser\Node;
use PhpParser\NodeVisitor;
/**
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*
* Code mostly comes from https://github.com/php-translation/extractor/blob/master/src/Visitor/Php/Symfony/Constraint.php
*/
final class ConstraintVisitor extends AbstractVisitor implements NodeVisitor
{
public function __construct(
private readonly array $constraintClassNames = [],
) {
}
public function beforeTraverse(array $nodes): ?Node
{
return null;
}
public function enterNode(Node $node): ?Node
{
return null;
}
public function leaveNode(Node $node): ?Node
{
if (!$node instanceof Node\Expr\New_ && !$node instanceof Node\Attribute) {
return null;
}
$className = $node instanceof Node\Attribute ? $node->name : $node->class;
if (!$className instanceof Node\Name) {
return null;
}
$parts = $className->getParts();
$isConstraintClass = false;
foreach ($parts as $part) {
if (\in_array($part, $this->constraintClassNames, true)) {
$isConstraintClass = true;
break;
}
}
if (!$isConstraintClass) {
return null;
}
$arg = $node->args[0] ?? null;
if (!$arg instanceof Node\Arg) {
return null;
}
if ($this->hasNodeNamedArguments($node)) {
$messages = $this->getStringArguments($node, '/message/i', true);
} else {
if (!$arg->value instanceof Node\Expr\Array_) {
// There is no way to guess which argument is a message to be translated.
return null;
}
$messages = [];
$options = $arg->value;
foreach ($options->items as $item) {
if (!$item->key instanceof Node\Scalar\String_) {
continue;
}
if (false === stripos($item->key->value ?? '', 'message')) {
continue;
}
if (!$item->value instanceof Node\Scalar\String_) {
continue;
}
$messages[] = $item->value->value;
break;
}
}
foreach ($messages as $message) {
$this->addMessageToCatalogue($message, 'validators', $node->getStartLine());
}
return null;
}
public function afterTraverse(array $nodes): ?Node
{
return null;
}
}
================================================
FILE: Extractor/Visitor/TransMethodVisitor.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Extractor\Visitor;
use PhpParser\Node;
use PhpParser\NodeVisitor;
/**
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*/
final class TransMethodVisitor extends AbstractVisitor implements NodeVisitor
{
public function beforeTraverse(array $nodes): ?Node
{
return null;
}
public function enterNode(Node $node): ?Node
{
return null;
}
public function leaveNode(Node $node): ?Node
{
if (!$node instanceof Node\Expr\MethodCall && !$node instanceof Node\Expr\FuncCall) {
return null;
}
if (!\is_string($node->name) && !$node->name instanceof Node\Identifier && !$node->name instanceof Node\Name) {
return null;
}
$name = $node->name instanceof Node\Name ? $node->name->getLast() : (string) $node->name;
if ('trans' === $name || 't' === $name) {
$firstNamedArgumentIndex = $this->nodeFirstNamedArgumentIndex($node);
if (!$messages = $this->getStringArguments($node, 0 < $firstNamedArgumentIndex ? 0 : 'id')) {
return null;
}
$domain = $this->getStringArguments($node, 2 < $firstNamedArgumentIndex ? 2 : 'domain')[0] ?? null;
foreach ($messages as $message) {
$this->addMessageToCatalogue($message, $domain, $node->getStartLine());
}
}
return null;
}
public function afterTraverse(array $nodes): ?Node
{
return null;
}
}
================================================
FILE: Extractor/Visitor/TranslatableMessageVisitor.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Extractor\Visitor;
use PhpParser\Node;
use PhpParser\NodeVisitor;
/**
* @author Mathieu Santostefano <msantostefano@protonmail.com>
*/
final class TranslatableMessageVisitor extends AbstractVisitor implements NodeVisitor
{
public function beforeTraverse(array $nodes): ?Node
{
return null;
}
public function enterNode(Node $node): ?Node
{
return null;
}
public function leaveNode(Node $node): ?Node
{
if (!$node instanceof Node\Expr\New_) {
return null;
}
if (!($className = $node->class) instanceof Node\Name) {
return null;
}
if (!\in_array('TranslatableMessage', $className->getParts(), true)) {
return null;
}
$firstNamedArgumentIndex = $this->nodeFirstNamedArgumentIndex($node);
if (!$messages = $this->getStringArguments($node, 0 < $firstNamedArgumentIndex ? 0 : 'message')) {
return null;
}
$domain = $this->getStringArguments($node, 2 < $firstNamedArgumentIndex ? 2 : 'domain')[0] ?? null;
foreach ($messages as $message) {
$this->addMessageToCatalogue($message, $domain, $node->getStartLine());
}
return null;
}
public function afterTraverse(array $nodes): ?Node
{
return null;
}
}
================================================
FILE: Formatter/IntlFormatter.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Formatter;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\Exception\LogicException;
/**
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class IntlFormatter implements IntlFormatterInterface
{
private bool $hasMessageFormatter;
private array $cache = [];
public function formatIntl(string $message, string $locale, array $parameters = []): string
{
// MessageFormatter constructor throws an exception if the message is empty
if ('' === $message) {
return '';
}
if (!$formatter = $this->cache[$locale][$message] ?? null) {
if (!$this->hasMessageFormatter ??= class_exists(\MessageFormatter::class)) {
throw new LogicException('Cannot parse message translation: please install the "intl" PHP extension or the "symfony/polyfill-intl-messageformatter" package.');
}
try {
$this->cache[$locale][$message] = $formatter = new \MessageFormatter($locale, $message);
} catch (\IntlException $e) {
throw new InvalidArgumentException(\sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e);
}
}
foreach ($parameters as $key => $value) {
if (\in_array($key[0] ?? null, ['%', '{'], true)) {
unset($parameters[$key]);
$parameters[trim($key, '%{ }')] = $value;
}
}
if (false === $message = $formatter->format($parameters)) {
throw new InvalidArgumentException(\sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage());
}
return $message;
}
}
================================================
FILE: Formatter/IntlFormatterInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Formatter;
/**
* Formats ICU message patterns.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
interface IntlFormatterInterface
{
/**
* Formats a localized message using rules defined by ICU MessageFormat.
*
* @see http://icu-project.org/apiref/icu4c/classMessageFormat.html#details
*/
public function formatIntl(string $message, string $locale, array $parameters = []): string;
}
================================================
FILE: Formatter/MessageFormatter.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Formatter;
use Symfony\Component\Translation\IdentityTranslator;
use Symfony\Contracts\Translation\TranslatorInterface;
// Help opcache.preload discover always-needed symbols
class_exists(IntlFormatter::class);
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class MessageFormatter implements MessageFormatterInterface, IntlFormatterInterface
{
private TranslatorInterface $translator;
private IntlFormatterInterface $intlFormatter;
/**
* @param TranslatorInterface|null $translator An identity translator to use as selector for pluralization
*/
public function __construct(?TranslatorInterface $translator = null, ?IntlFormatterInterface $intlFormatter = null)
{
$this->translator = $translator ?? new IdentityTranslator();
$this->intlFormatter = $intlFormatter ?? new IntlFormatter();
}
public function format(string $message, string $locale, array $parameters = []): string
{
return $this->translator->trans($message, $parameters, null, $locale);
}
public function formatIntl(string $message, string $locale, array $parameters = []): string
{
return $this->intlFormatter->formatIntl($message, $locale, $parameters);
}
}
================================================
FILE: Formatter/MessageFormatterInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Formatter;
/**
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
interface MessageFormatterInterface
{
/**
* Formats a localized message pattern with given arguments.
*
* @param string $message The message (may also be an object that can be cast to string)
* @param string $locale The message locale
* @param array $parameters An array of parameters for the message
*/
public function format(string $message, string $locale, array $parameters = []): string;
}
================================================
FILE: IdentityTranslator.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorTrait;
/**
* IdentityTranslator does not translate anything.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class IdentityTranslator implements TranslatorInterface, LocaleAwareInterface
{
use TranslatorTrait;
public function setLocale(string $locale): void
{
$this->locale = $locale;
}
}
================================================
FILE: LICENSE
================================================
Copyright (c) 2004-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: Loader/ArrayLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\MessageCatalogue;
/**
* ArrayLoader loads translations from a PHP array.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ArrayLoader implements LoaderInterface
{
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
{
$resource = $this->flatten($resource);
$catalogue = new MessageCatalogue($locale);
$catalogue->add($resource, $domain);
return $catalogue;
}
/**
* Flattens an nested array of translations.
*
* The scheme used is:
* 'key' => ['key2' => ['key3' => 'value']]
* Becomes:
* 'key.key2.key3' => 'value'
*/
private function flatten(array $messages): array
{
$result = [];
foreach ($messages as $key => $value) {
if (\is_array($value)) {
foreach ($this->flatten($value) as $k => $v) {
if (null !== $v) {
$result[$key.'.'.$k] = $v;
}
}
} elseif (null !== $value) {
$result[$key] = $value;
}
}
return $result;
}
}
================================================
FILE: Loader/CsvFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
/**
* CsvFileLoader loads translations from CSV files.
*
* @author Saša Stamenković <umpirsky@gmail.com>
*/
class CsvFileLoader extends FileLoader
{
private string $delimiter = ';';
private string $enclosure = '"';
protected function loadResource(string $resource): array
{
$messages = [];
try {
$file = new \SplFileObject($resource, 'rb');
} catch (\RuntimeException $e) {
throw new NotFoundResourceException(\sprintf('Error opening file "%s".', $resource), 0, $e);
}
$file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY | \SplFileObject::DROP_NEW_LINE);
$file->setCsvControl($this->delimiter, $this->enclosure, '');
foreach ($file as $data) {
if (false === $data) {
continue;
}
if (!str_starts_with($data[0], '#') && isset($data[1]) && 2 === \count($data)) {
$messages[$data[0]] = $data[1];
}
}
return $messages;
}
/**
* Sets the delimiter and enclosure character for CSV.
*/
public function setCsvControl(string $delimiter = ';', string $enclosure = '"'): void
{
$this->delimiter = $delimiter;
$this->enclosure = $enclosure;
}
}
================================================
FILE: Loader/FileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\MessageCatalogue;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
abstract class FileLoader extends ArrayLoader
{
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
{
if (!stream_is_local($resource)) {
throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource));
}
if (!file_exists($resource)) {
throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource));
}
$messages = $this->loadResource($resource);
// empty resource
$messages ??= [];
// not an array
if (!\is_array($messages)) {
throw new InvalidResourceException(\sprintf('Unable to load file "%s".', $resource));
}
$catalogue = parent::load($messages, $locale, $domain);
if (class_exists(FileResource::class)) {
$catalogue->addResource(new FileResource($resource));
}
return $catalogue;
}
/**
* @throws InvalidResourceException if stream content has an invalid format
*/
abstract protected function loadResource(string $resource): array;
}
================================================
FILE: Loader/IcuDatFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\MessageCatalogue;
/**
* IcuResFileLoader loads translations from a resource bundle.
*
* @author stealth35
*/
class IcuDatFileLoader extends IcuResFileLoader
{
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
{
if (!stream_is_local($resource.'.dat')) {
throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource));
}
if (!file_exists($resource.'.dat')) {
throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource));
}
try {
$rb = new \ResourceBundle($locale, $resource);
} catch (\Exception) {
$rb = null;
}
if (!$rb) {
throw new InvalidResourceException(\sprintf('Cannot load resource "%s".', $resource));
} elseif (intl_is_failure($rb->getErrorCode())) {
throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
}
$messages = $this->flatten($rb);
$catalogue = new MessageCatalogue($locale);
$catalogue->add($messages, $domain);
if (class_exists(FileResource::class)) {
$catalogue->addResource(new FileResource($resource.'.dat'));
}
return $catalogue;
}
}
================================================
FILE: Loader/IcuResFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Config\Resource\DirectoryResource;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\MessageCatalogue;
/**
* IcuResFileLoader loads translations from a resource bundle.
*
* @author stealth35
*/
class IcuResFileLoader implements LoaderInterface
{
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
{
if (!stream_is_local($resource)) {
throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource));
}
if (!is_dir($resource)) {
throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource));
}
try {
$rb = new \ResourceBundle($locale, $resource);
} catch (\Exception) {
$rb = null;
}
if (!$rb) {
throw new InvalidResourceException(\sprintf('Cannot load resource "%s".', $resource));
} elseif (intl_is_failure($rb->getErrorCode())) {
throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
}
$messages = $this->flatten($rb);
$catalogue = new MessageCatalogue($locale);
$catalogue->add($messages, $domain);
if (class_exists(DirectoryResource::class)) {
$catalogue->addResource(new DirectoryResource($resource));
}
return $catalogue;
}
/**
* Flattens an ResourceBundle.
*
* The scheme used is:
* key { key2 { key3 { "value" } } }
* Becomes:
* 'key.key2.key3' => 'value'
*
* This function takes an array by reference and will modify it
*
* @param \ResourceBundle $rb The ResourceBundle that will be flattened
* @param array $messages Used internally for recursive calls
* @param string|null $path Current path being parsed, used internally for recursive calls
*/
protected function flatten(\ResourceBundle $rb, array &$messages = [], ?string $path = null): array
{
foreach ($rb as $key => $value) {
$nodePath = $path ? $path.'.'.$key : $key;
if ($value instanceof \ResourceBundle) {
$this->flatten($value, $messages, $nodePath);
} else {
$messages[$nodePath] = $value;
}
}
return $messages;
}
}
================================================
FILE: Loader/IniFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
/**
* IniFileLoader loads translations from an ini file.
*
* @author stealth35
*/
class IniFileLoader extends FileLoader
{
protected function loadResource(string $resource): array
{
return parse_ini_file($resource, true);
}
}
================================================
FILE: Loader/JsonFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\Exception\InvalidResourceException;
/**
* JsonFileLoader loads translations from an json file.
*
* @author singles
*/
class JsonFileLoader extends FileLoader
{
protected function loadResource(string $resource): array
{
$messages = [];
if ($data = file_get_contents($resource)) {
$messages = json_decode($data, true);
if (0 < $errorCode = json_last_error()) {
throw new InvalidResourceException('Error parsing JSON: '.$this->getJSONErrorMessage($errorCode));
}
}
return $messages;
}
/**
* Translates JSON_ERROR_* constant into meaningful message.
*/
private function getJSONErrorMessage(int $errorCode): string
{
return match ($errorCode) {
\JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
\JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
\JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
\JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
\JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded',
default => 'Unknown error',
};
}
}
================================================
FILE: Loader/LoaderInterface.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\MessageCatalogue;
/**
* LoaderInterface is the interface implemented by all translation loaders.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface LoaderInterface
{
/**
* Loads a locale.
*
* @throws NotFoundResourceException when the resource cannot be found
* @throws InvalidResourceException when the resource cannot be loaded
*/
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue;
}
================================================
FILE: Loader/MoFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\Exception\InvalidResourceException;
/**
* @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
*/
class MoFileLoader extends FileLoader
{
/**
* Magic used for validating the format of an MO file as well as
* detecting if the machine used to create that file was little endian.
*/
public const MO_LITTLE_ENDIAN_MAGIC = 0x950412DE;
/**
* Magic used for validating the format of an MO file as well as
* detecting if the machine used to create that file was big endian.
*/
public const MO_BIG_ENDIAN_MAGIC = 0xDE120495;
/**
* The size of the header of an MO file in bytes.
*/
public const MO_HEADER_SIZE = 28;
/**
* Parses machine object (MO) format, independent of the machine's endian it
* was created on. Both 32bit and 64bit systems are supported.
*/
protected function loadResource(string $resource): array
{
$stream = fopen($resource, 'r');
$stat = fstat($stream);
if ($stat['size'] < self::MO_HEADER_SIZE) {
throw new InvalidResourceException('MO stream content has an invalid format.');
}
$magic = unpack('V1', fread($stream, 4));
$magic = hexdec(substr(dechex(current($magic)), -8));
if (self::MO_LITTLE_ENDIAN_MAGIC == $magic) {
$isBigEndian = false;
} elseif (self::MO_BIG_ENDIAN_MAGIC == $magic) {
$isBigEndian = true;
} else {
throw new InvalidResourceException('MO stream content has an invalid format.');
}
// formatRevision
$this->readLong($stream, $isBigEndian);
$count = $this->readLong($stream, $isBigEndian);
$offsetId = $this->readLong($stream, $isBigEndian);
$offsetTranslated = $this->readLong($stream, $isBigEndian);
// sizeHashes
$this->readLong($stream, $isBigEndian);
// offsetHashes
$this->readLong($stream, $isBigEndian);
$messages = [];
for ($i = 0; $i < $count; ++$i) {
$pluralId = null;
$translated = null;
fseek($stream, $offsetId + $i * 8);
$length = $this->readLong($stream, $isBigEndian);
$offset = $this->readLong($stream, $isBigEndian);
if ($length < 1) {
continue;
}
fseek($stream, $offset);
$singularId = fread($stream, $length);
if (str_contains($singularId, "\000")) {
[$singularId, $pluralId] = explode("\000", $singularId);
}
fseek($stream, $offsetTranslated + $i * 8);
$length = $this->readLong($stream, $isBigEndian);
$offset = $this->readLong($stream, $isBigEndian);
if ($length < 1) {
continue;
}
fseek($stream, $offset);
$translated = fread($stream, $length);
if (str_contains($translated, "\000")) {
$translated = explode("\000", $translated);
}
$ids = ['singular' => $singularId, 'plural' => $pluralId];
$item = compact('ids', 'translated');
if (!empty($item['ids']['singular'])) {
$id = $item['ids']['singular'];
if (isset($item['ids']['plural'])) {
$id .= '|'.$item['ids']['plural'];
}
$messages[$id] = stripcslashes(implode('|', (array) $item['translated']));
}
}
fclose($stream);
return array_filter($messages);
}
/**
* Reads an unsigned long from stream respecting endianness.
*
* @param resource $stream
*/
private function readLong($stream, bool $isBigEndian): int
{
$result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
$result = current($result);
return (int) substr($result, -8);
}
}
================================================
FILE: Loader/PhpFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
/**
* PhpFileLoader loads translations from PHP files returning an array of translations.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class PhpFileLoader extends FileLoader
{
private static ?array $cache = [];
protected function loadResource(string $resource): array
{
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))) {
self::$cache = null;
}
if (null === self::$cache) {
return require $resource;
}
return self::$cache[$resource] ??= require $resource;
}
}
================================================
FILE: Loader/PoFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
/**
* @copyright Copyright (c) 2010, Union of RAD https://github.com/UnionOfRAD/lithium
* @copyright Copyright (c) 2012, Clemens Tolboom
*/
class PoFileLoader extends FileLoader
{
/**
* Parses portable object (PO) format.
*
* From https://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
* we should be able to parse files having:
*
* white-space
* # translator-comments
* #. extracted-comments
* #: reference...
* #, flag...
* #| msgid previous-untranslated-string
* msgid untranslated-string
* msgstr translated-string
*
* extra or different lines are:
*
* #| msgctxt previous-context
* #| msgid previous-untranslated-string
* msgctxt context
*
* #| msgid previous-untranslated-string-singular
* #| msgid_plural previous-untranslated-string-plural
* msgid untranslated-string-singular
* msgid_plural untranslated-string-plural
* msgstr[0] translated-string-case-0
* ...
* msgstr[N] translated-string-case-n
*
* The definition states:
* - white-space and comments are optional.
* - msgid "" that an empty singleline defines a header.
*
* This parser sacrifices some features of the reference implementation the
* differences to that implementation are as follows.
* - No support for comments spanning multiple lines.
* - Translator and extracted comments are treated as being the same type.
* - Message IDs are allowed to have other encodings as just US-ASCII.
*
* Items with an empty id are ignored.
*/
protected function loadResource(string $resource): array
{
$stream = fopen($resource, 'r');
$defaults = [
'ids' => [],
'translated' => null,
];
$messages = [];
$item = $defaults;
$flags = [];
while ($line = fgets($stream)) {
$line = trim($line);
if ('' === $line) {
// Whitespace indicated current item is done
if (!\in_array('fuzzy', $flags, true)) {
$this->addMessage($messages, $item);
}
$item = $defaults;
$flags = [];
} elseif (str_starts_with($line, '#,')) {
$flags = array_map('trim', explode(',', substr($line, 2)));
} elseif (str_starts_with($line, 'msgid "')) {
// We start a new msg so save previous
// TODO: this fails when comments or contexts are added
$this->addMessage($messages, $item);
$item = $defaults;
$item['ids']['singular'] = substr($line, 7, -1);
} elseif (str_starts_with($line, 'msgstr "')) {
$item['translated'] = substr($line, 8, -1);
} elseif ('"' === $line[0]) {
$continues = isset($item['translated']) ? 'translated' : 'ids';
if (\is_array($item[$continues])) {
end($item[$continues]);
$item[$continues][key($item[$continues])] .= substr($line, 1, -1);
} else {
$item[$continues] .= substr($line, 1, -1);
}
} elseif (str_starts_with($line, 'msgid_plural "')) {
$item['ids']['plural'] = substr($line, 14, -1);
} elseif (str_starts_with($line, 'msgstr[')) {
$size = strpos($line, ']');
$item['translated'][(int) substr($line, 7, 1)] = substr($line, $size + 3, -1);
}
}
// save last item
if (!\in_array('fuzzy', $flags, true)) {
$this->addMessage($messages, $item);
}
fclose($stream);
return $messages;
}
/**
* Save a translation item to the messages.
*
* A .po file could contain by error missing plural indexes. We need to
* fix these before saving them.
*/
private function addMessage(array &$messages, array $item): void
{
if (!empty($item['ids']['singular'])) {
$id = stripcslashes($item['ids']['singular']);
if (isset($item['ids']['plural'])) {
$id .= '|'.stripcslashes($item['ids']['plural']);
}
$translated = (array) $item['translated'];
// PO are by definition indexed so sort by index.
ksort($translated);
// Make sure every index is filled.
end($translated);
$count = key($translated);
// Fill missing spots with '-'.
$empties = array_fill(0, $count + 1, '-');
$translated += $empties;
ksort($translated);
$messages[$id] = stripcslashes(implode('|', $translated));
}
}
}
================================================
FILE: Loader/QtFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\Exception\RuntimeException;
use Symfony\Component\Translation\MessageCatalogue;
/**
* QtFileLoader loads translations from QT Translations XML files.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class QtFileLoader implements LoaderInterface
{
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
{
if (!class_exists(XmlUtils::class)) {
throw new RuntimeException('Loading translations from the QT format requires the Symfony Config component.');
}
if (!stream_is_local($resource)) {
throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource));
}
if (!file_exists($resource)) {
throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource));
}
try {
$dom = XmlUtils::loadFile($resource);
} catch (\InvalidArgumentException $e) {
throw new InvalidResourceException(\sprintf('Unable to load "%s".', $resource), $e->getCode(), $e);
}
$internalErrors = libxml_use_internal_errors(true);
libxml_clear_errors();
$xpath = new \DOMXPath($dom);
$nodes = $xpath->evaluate('//TS/context/name[text()="'.$domain.'"]');
$catalogue = new MessageCatalogue($locale);
if (1 == $nodes->length) {
$translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message');
foreach ($translations as $translation) {
$translationValue = (string) $translation->getElementsByTagName('translation')->item(0)->nodeValue;
if ($translationValue) {
$catalogue->set(
(string) $translation->getElementsByTagName('source')->item(0)->nodeValue,
$translationValue,
$domain
);
}
}
if (class_exists(FileResource::class)) {
$catalogue->addResource(new FileResource($resource));
}
}
libxml_use_internal_errors($internalErrors);
return $catalogue;
}
}
================================================
FILE: Loader/XliffFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Util\Exception\InvalidXmlException;
use Symfony\Component\Config\Util\Exception\XmlParsingException;
use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\Exception\RuntimeException;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
use Symfony\Component\Translation\Util\XliffUtils;
/**
* XliffFileLoader loads translations from XLIFF files.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class XliffFileLoader implements LoaderInterface
{
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
{
if (!class_exists(XmlUtils::class)) {
throw new RuntimeException('Loading translations from the Xliff format requires the Symfony Config component.');
}
if (!$this->isXmlString($resource)) {
if (!stream_is_local($resource)) {
throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource));
}
if (!file_exists($resource)) {
throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource));
}
if (!is_file($resource)) {
throw new InvalidResourceException(\sprintf('This is neither a file nor an XLIFF string "%s".', $resource));
}
}
try {
if ($this->isXmlString($resource)) {
$dom = XmlUtils::parse($resource);
} else {
$dom = XmlUtils::loadFile($resource);
}
} catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) {
throw new InvalidResourceException(\sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e);
}
if ($errors = XliffUtils::validateSchema($dom)) {
throw new InvalidResourceException(\sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors));
}
$catalogue = new MessageCatalogue($locale);
$this->extract($dom, $catalogue, $domain);
if (is_file($resource) && class_exists(FileResource::class)) {
$catalogue->addResource(new FileResource($resource));
}
return $catalogue;
}
private function extract(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void
{
$xliffVersion = XliffUtils::getVersionNumber($dom);
if ('1.2' === $xliffVersion) {
$this->extractXliff1($dom, $catalogue, $domain);
}
if (\in_array($xliffVersion, ['2.0', '2.1', '2.2'], true)) {
$this->extractXliff2($dom, $catalogue, $domain);
}
}
/**
* Extract messages and metadata from DOMDocument into a MessageCatalogue.
*/
private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void
{
$xml = simplexml_import_dom($dom);
$encoding = $dom->encoding ? strtoupper($dom->encoding) : null;
$namespace = 'urn:oasis:names:tc:xliff:document:1.2';
$xml->registerXPathNamespace('xliff', $namespace);
foreach ($xml->xpath('//xliff:file') as $file) {
$fileAttributes = $file->attributes();
$file->registerXPathNamespace('xliff', $namespace);
foreach ($file->xpath('.//xliff:prop') as $prop) {
$catalogue->setCatalogueMetadata($prop->attributes()['prop-type'], (string) $prop, $domain);
}
foreach ($file->xpath('.//xliff:trans-unit') as $translation) {
$attributes = $translation->attributes();
if (!(isset($attributes['resname']) || isset($translation->source))) {
continue;
}
$source = (string) (isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source);
if (isset($translation->target)
&& 'needs-translation' === (string) $translation->target->attributes()['state']
&& \in_array((string) $translation->target, [$source, (string) $translation->source], true)
) {
continue;
}
// If the xlf file has another encoding specified, try to convert it because
// simple_xml will always return utf-8 encoded values
$target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding);
$catalogue->set($source, $target, $domain);
$metadata = [
'source' => (string) $translation->source,
'file' => [
'original' => (string) $fileAttributes['original'],
],
];
if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) {
$metadata['notes'] = $notes;
}
if (isset($translation->target) && $translation->target->attributes()) {
$metadata['target-attributes'] = [];
foreach ($translation->target->attributes() as $key => $value) {
$metadata['target-attributes'][$key] = (string) $value;
}
}
if (isset($attributes['id'])) {
$metadata['id'] = (string) $attributes['id'];
}
$catalogue->setMetadata($source, $metadata, $domain);
}
}
}
private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void
{
$xml = simplexml_import_dom($dom);
$encoding = $dom->encoding ? strtoupper($dom->encoding) : null;
$xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0');
foreach ($xml->xpath('//xliff:unit') as $unit) {
if (null !== $pgsSwitch = $unit->attributes('urn:oasis:names:tc:xliff:pgs:1.0')['switch'] ?? null) {
$this->extractXliff2PgsUnit($unit, $catalogue, $domain, (string) $pgsSwitch, $encoding);
continue;
}
foreach ($unit->segment as $segment) {
$attributes = $unit->attributes();
$source = $attributes['name'] ?? $segment->source;
// If the xlf file has another encoding specified, try to convert it because
// simple_xml will always return utf-8 encoded values
$target = $this->utf8ToCharset((string) ($segment->target ?? $segment->source), $encoding);
$catalogue->set((string) $source, $target, $domain);
$metadata = [];
if ($segment->attributes()) {
$metadata['segment-attributes'] = [];
foreach ($segment->attributes() as $key => $value) {
$metadata['segment-attributes'][$key] = (string) $value;
}
}
if (isset($segment->target) && $segment->target->attributes()) {
$metadata['target-attributes'] = [];
foreach ($segment->target->attributes() as $key => $value) {
$metadata['target-attributes'][$key] = (string) $value;
}
}
if (isset($unit->notes)) {
$metadata['notes'] = [];
foreach ($unit->notes->note as $noteNode) {
$note = [];
foreach ($noteNode->attributes() as $key => $value) {
$note[$key] = (string) $value;
}
$note['content'] = (string) $noteNode;
$metadata['notes'][] = $note;
}
}
$catalogue->setMetadata((string) $source, $metadata, $domain);
}
}
}
private function extractXliff2PgsUnit(\SimpleXMLElement $unit, MessageCatalogue $catalogue, string $domain, string $pgsSwitch, ?string $encoding): void
{
$switches = $this->parsePgsSwitch($pgsSwitch);
$attributes = $unit->attributes();
$source = (string) ($attributes['name'] ?? $attributes['id']);
$cases = [];
foreach ($unit->segment as $segment) {
if (null === $pgsCase = $segment->attributes('urn:oasis:names:tc:xliff:pgs:1.0')['case'] ?? null) {
continue;
}
$cases[(string) $pgsCase] = $this->extractPgsSegmentText($segment->target ?? $segment->source, $switches);
}
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
$catalogue->set($source, $this->utf8ToCharset($this->buildIcuMessage($switches, $cases), $encoding), $intlDomain);
$metadata = ['pgs-switch' => $pgsSwitch];
if (isset($unit->notes)) {
$metadata['notes'] = [];
foreach ($unit->notes->note as $noteNode) {
$note = array_map('strval', $noteNode->attributes() ?? []);
$note['content'] = (string) $noteNode;
$metadata['notes'][] = $note;
}
}
$catalogue->setMetadata($source, $metadata, $intlDomain);
}
private function parsePgsSwitch(string $pgsSwitch): array
{
$switches = [];
foreach (preg_split('/\s+/', trim($pgsSwitch)) as $item) {
$switches[] = array_combine(['type', 'variable'], explode(':', $item, 2));
}
return $switches;
}
private function extractPgsSegmentText(\SimpleXMLElement $element, array $switches): string
{
$pluralVariables = [];
foreach ($switches as $switch) {
if ('plural' === $switch['type'] || 'ordinal' === $switch['type']) {
$pluralVariables[$switch['variable']] = true;
}
}
$text = '';
foreach (dom_import_simplexml($element)->childNodes as $child) {
if (\XML_TEXT_NODE === $child->nodeType) {
$text .= $child->textContent;
} elseif (\XML_ELEMENT_NODE === $child->nodeType && 'ph' === $child->localName) {
if (($disp = $child->getAttribute('disp')) && isset($pluralVariables[$disp])) {
$text .= '#';
} elseif ($disp) {
$text .= '{'.$disp.'}';
}
}
}
return $text;
}
private function buildIcuMessage(array $switches, array $cases): string
{
if (1 === \count($switches)) {
$switch = $switches[0];
$icuType = $this->getIcuType($switch['type']);
$icuCases = [];
foreach ($cases as $caseValue => $text) {
$icuCases[] = $this->formatIcuCase($caseValue, $switch['type']).' {'.$text.'}';
}
return '{'.$switch['variable'].', '.$icuType.', '.implode(' ', $icuCases).'}';
}
$outerSwitch = $switches[0];
$innerSwitches = \array_slice($switches, 1);
$icuType = $this->getIcuType($outerSwitch['type']);
$grouped = [];
foreach ($cases as $caseKey => $text) {
$caseParts = explode(' ', $caseKey, 2);
$grouped[$caseParts[0]][$caseParts[1] ?? 'other'] = $text;
}
$icuCases = [];
foreach ($grouped as $caseValue => $innerCases) {
$icuCases[] = $this->formatIcuCase($caseValue, $outerSwitch['type']).' {'.$this->buildIcuMessage($innerSwitches, $innerCases).'}';
}
return '{'.$outerSwitch['variable'].', '.$icuType.', '.implode(' ', $icuCases).'}';
}
private function getIcuType(string $pgsType): string
{
return match ($pgsType) {
'plural' => 'plural',
'ordinal' => 'selectordinal',
default => 'select',
};
}
private function formatIcuCase(int|string $caseValue, string $switchType): string
{
return (\in_array($switchType, ['plural', 'ordinal'], true) && is_numeric($caseValue) ? '=' : '').$caseValue;
}
/**
* Convert a UTF8 string to the specified encoding.
*/
private function utf8ToCharset(string $content, ?string $encoding = null): string
{
if ('UTF-8' !== $encoding && $encoding) {
return mb_convert_encoding($content, $encoding, 'UTF-8');
}
return $content;
}
private function parseNotesMetadata(?\SimpleXMLElement $noteElement = null, ?string $encoding = null): array
{
$notes = [];
if (null === $noteElement) {
return $notes;
}
/** @var \SimpleXMLElement $xmlNote */
foreach ($noteElement as $xmlNote) {
$noteAttributes = $xmlNote->attributes();
$note = ['content' => $this->utf8ToCharset((string) $xmlNote, $encoding)];
if (isset($noteAttributes['priority'])) {
$note['priority'] = (int) $noteAttributes['priority'];
}
if (isset($noteAttributes['from'])) {
$note['from'] = (string) $noteAttributes['from'];
}
$notes[] = $note;
}
return $notes;
}
private function isXmlString(string $resource): bool
{
return str_starts_with($resource, '<?xml');
}
}
================================================
FILE: Loader/YamlFileLoader.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Loader;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\LogicException;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Yaml\Yaml;
/**
* YamlFileLoader loads translations from Yaml files.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class YamlFileLoader extends FileLoader
{
private YamlParser $yamlParser;
protected function loadResource(string $resource): array
{
if (!isset($this->yamlParser)) {
if (!class_exists(YamlParser::class)) {
throw new LogicException('Loading translations from the YAML format requires the Symfony Yaml component.');
}
$this->yamlParser = new YamlParser();
}
try {
$messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT);
} catch (ParseException $e) {
throw new InvalidResourceException(\sprintf('The file "%s" does not contain valid YAML: ', $resource).$e->getMessage(), 0, $e);
}
if (null !== $messages && !\is_array($messages)) {
throw new InvalidResourceException(\sprintf('Unable to load file "%s".', $resource));
}
return $messages ?: [];
}
}
================================================
FILE: LocaleFallbackProvider.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
/**
* Derives fallback locales based on ICU parent locale information, by shortening locale
* sub tags and ultimately by going through a list of configured fallback locales.
*
* Also provides locale string validation.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
final class LocaleFallbackProvider
{
/**
* @param string[] $localeFallbacks List of fallback locales to add _after_ the ones derived from ICU information
*
* @throws InvalidArgumentException If a locale contains invalid characters
*/
public function __construct(
private array $localeFallbacks = [],
) {
foreach ($localeFallbacks as $locale) {
self::validateLocale($locale);
}
}
/**
* @return string[]
*/
public function computeFallbackLocales(string $locale): array
{
self::validateLocale($locale);
static $parentLocales;
$parentLocales ??= require __DIR__.'/Resources/data/parents.php';
$originLocale = $locale;
$locales = [];
while ($locale) {
if ($parent = $parentLocales[$locale] ?? null) {
$locale = 'root' !== $parent ? $parent : null;
} elseif (\function_exists('locale_parse')) {
$localeSubTags = locale_parse($locale);
$locale = null;
if (1 < \count($localeSubTags)) {
array_pop($localeSubTags);
$locale = locale_compose($localeSubTags) ?: null;
}
} elseif ($i = strrpos($locale, '_') ?: strrpos($locale, '-')) {
$locale = substr($locale, 0, $i);
} else {
$locale = null;
}
if (null !== $locale) {
$locales[$locale] = $locale;
}
}
foreach ($this->localeFallbacks as $fallback) {
if ($fallback === $originLocale) {
continue;
}
$locales[$fallback] = $fallback;
}
return array_keys($locales);
}
/**
* Asserts that the locale is valid, throws an Exception if not.
*
* @throws InvalidArgumentException If the locale contains invalid characters
*/
public static function validateLocale(string $locale): void
{
if (!preg_match('/^[a-z0-9@_\.\-]*$/i', $locale)) {
throw new InvalidArgumentException(\sprintf('Invalid "%s" locale.', $locale));
}
}
}
================================================
FILE: LocaleSwitcher.php
================================================
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation;
use Symfony\Component\Routing\RequestContext;
use Symfony\Contracts\Translation\LocaleAwareInterface;
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
class LocaleSwitcher implements LocaleAwareInterface
{
private string $defaultLocale;
/**
* @param LocaleAwareInterface[] $localeAwareServices
*/
public function __construct(
private string $locale,
private iterable $localeAwareServices,
private ?RequestContext $requestContext = null,
) {
$this->defaultLocale = $l
gitextract_etp_7s_u/ ├── .gitattributes ├── .github/ │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ └── close-pull-request.yml ├── .gitignore ├── CHANGELOG.md ├── Catalogue/ │ ├── AbstractOperation.php │ ├── MergeOperation.php │ ├── OperationInterface.php │ └── TargetOperation.php ├── CatalogueMetadataAwareInterface.php ├── Command/ │ ├── TranslationLintCommand.php │ ├── TranslationPullCommand.php │ ├── TranslationPushCommand.php │ ├── TranslationTrait.php │ └── XliffLintCommand.php ├── DataCollector/ │ └── TranslationDataCollector.php ├── DataCollectorTranslator.php ├── DependencyInjection/ │ ├── DataCollectorTranslatorPass.php │ ├── LoggingTranslatorPass.php │ ├── TranslationDumperPass.php │ ├── TranslationExtractorPass.php │ ├── TranslatorPass.php │ └── TranslatorPathsPass.php ├── Dumper/ │ ├── CsvFileDumper.php │ ├── DumperInterface.php │ ├── FileDumper.php │ ├── IcuResFileDumper.php │ ├── IniFileDumper.php │ ├── JsonFileDumper.php │ ├── MoFileDumper.php │ ├── PhpFileDumper.php │ ├── PoFileDumper.php │ ├── QtFileDumper.php │ ├── XliffFileDumper.php │ └── YamlFileDumper.php ├── Exception/ │ ├── ExceptionInterface.php │ ├── IncompleteDsnException.php │ ├── InvalidArgumentException.php │ ├── InvalidResourceException.php │ ├── LogicException.php │ ├── MissingRequiredOptionException.php │ ├── NotFoundResourceException.php │ ├── ProviderException.php │ ├── ProviderExceptionInterface.php │ ├── RuntimeException.php │ └── UnsupportedSchemeException.php ├── Extractor/ │ ├── AbstractFileExtractor.php │ ├── ChainExtractor.php │ ├── ExtractorInterface.php │ ├── PhpAstExtractor.php │ └── Visitor/ │ ├── AbstractVisitor.php │ ├── ConstraintVisitor.php │ ├── TransMethodVisitor.php │ └── TranslatableMessageVisitor.php ├── Formatter/ │ ├── IntlFormatter.php │ ├── IntlFormatterInterface.php │ ├── MessageFormatter.php │ └── MessageFormatterInterface.php ├── IdentityTranslator.php ├── LICENSE ├── Loader/ │ ├── ArrayLoader.php │ ├── CsvFileLoader.php │ ├── FileLoader.php │ ├── IcuDatFileLoader.php │ ├── IcuResFileLoader.php │ ├── IniFileLoader.php │ ├── JsonFileLoader.php │ ├── LoaderInterface.php │ ├── MoFileLoader.php │ ├── PhpFileLoader.php │ ├── PoFileLoader.php │ ├── QtFileLoader.php │ ├── XliffFileLoader.php │ └── YamlFileLoader.php ├── LocaleFallbackProvider.php ├── LocaleSwitcher.php ├── LoggingTranslator.php ├── MessageCatalogue.php ├── MessageCatalogueInterface.php ├── MetadataAwareInterface.php ├── Provider/ │ ├── AbstractProviderFactory.php │ ├── Dsn.php │ ├── FilteringProvider.php │ ├── NullProvider.php │ ├── NullProviderFactory.php │ ├── ProviderFactoryInterface.php │ ├── ProviderInterface.php │ ├── TranslationProviderCollection.php │ └── TranslationProviderCollectionFactory.php ├── PseudoLocalizationTranslator.php ├── README.md ├── Reader/ │ ├── TranslationReader.php │ └── TranslationReaderInterface.php ├── Resources/ │ ├── bin/ │ │ └── translation-status.php │ ├── data/ │ │ ├── parents.json │ │ └── parents.php │ ├── functions.php │ └── schemas/ │ ├── xliff-core-1.2-transitional.xsd │ ├── xliff-core-2.0.xsd │ ├── xliff-core-2.2.xsd │ └── xml.xsd ├── StaticMessage.php ├── Test/ │ ├── AbstractProviderFactoryTestCase.php │ ├── IncompleteDsnTestTrait.php │ └── ProviderTestCase.php ├── Tests/ │ ├── Catalogue/ │ │ ├── AbstractOperationTestCase.php │ │ ├── MergeOperationTest.php │ │ ├── MessageCatalogueTest.php │ │ └── TargetOperationTest.php │ ├── Command/ │ │ ├── TranslationLintCommandTest.php │ │ ├── TranslationProviderTestCase.php │ │ ├── TranslationPullCommandTest.php │ │ ├── TranslationPushCommandTest.php │ │ └── XliffLintCommandTest.php │ ├── DataCollector/ │ │ └── TranslationDataCollectorTest.php │ ├── DataCollectorTranslatorTest.php │ ├── DependencyInjection/ │ │ ├── DataCollectorTranslatorPassTest.php │ │ ├── Fixtures/ │ │ │ ├── ControllerArguments.php │ │ │ ├── ServiceArguments.php │ │ │ ├── ServiceMethodCalls.php │ │ │ ├── ServiceProperties.php │ │ │ └── ServiceSubscriber.php │ │ ├── LoggingTranslatorPassTest.php │ │ ├── TranslationDumperPassTest.php │ │ ├── TranslationExtractorPassTest.php │ │ ├── TranslationPathsPassTest.php │ │ └── TranslatorPassTest.php │ ├── Dumper/ │ │ ├── CsvFileDumperTest.php │ │ ├── FileDumperTest.php │ │ ├── IcuResFileDumperTest.php │ │ ├── IniFileDumperTest.php │ │ ├── JsonFileDumperTest.php │ │ ├── MoFileDumperTest.php │ │ ├── PhpFileDumperTest.php │ │ ├── PoFileDumperTest.php │ │ ├── QtFileDumperTest.php │ │ ├── XliffFileDumperTest.php │ │ └── YamlFileDumperTest.php │ ├── Exception/ │ │ ├── ProviderExceptionTest.php │ │ └── UnsupportedSchemeExceptionTest.php │ ├── Extractor/ │ │ └── PhpAstExtractorTest.php │ ├── Fixtures/ │ │ ├── empty-translation.mo │ │ ├── empty-translation.po │ │ ├── empty.csv │ │ ├── empty.ini │ │ ├── empty.json │ │ ├── empty.mo │ │ ├── empty.po │ │ ├── empty.xlf │ │ ├── empty.yml │ │ ├── encoding.xlf │ │ ├── escaped-id-plurals.po │ │ ├── escaped-id.po │ │ ├── extractor/ │ │ │ ├── resource.format.engine │ │ │ ├── this.is.a.template.format.engine │ │ │ ├── translatable-fqn.html.php │ │ │ ├── translatable-short.html.php │ │ │ ├── translatable.html.php │ │ │ └── translation.html.php │ │ ├── extractor-7.3/ │ │ │ └── translation.html.php │ │ ├── extractor-ast/ │ │ │ ├── resource.format.engine │ │ │ ├── this.is.a.template.format.engine │ │ │ ├── translatable-fqn.html.php │ │ │ ├── translatable-short-fqn.html.php │ │ │ ├── translatable-short.html.php │ │ │ ├── translatable.html.php │ │ │ ├── translation.html.php │ │ │ └── validator-constraints.php │ │ ├── fuzzy-translations.po │ │ ├── invalid-xml-resources.xlf │ │ ├── malformed.json │ │ ├── messages.yml │ │ ├── messages_linear.yml │ │ ├── missing-plurals.po │ │ ├── non-string.yml │ │ ├── non-valid.xlf │ │ ├── non-valid.yml │ │ ├── plurals.mo │ │ ├── plurals.po │ │ ├── resname.xlf │ │ ├── resourcebundle/ │ │ │ ├── dat/ │ │ │ │ ├── en.res │ │ │ │ ├── en.txt │ │ │ │ ├── fr.res │ │ │ │ ├── fr.txt │ │ │ │ └── packagelist.txt │ │ │ └── res/ │ │ │ └── en.res │ │ ├── resources-2.0+intl-icu.xlf │ │ ├── resources-2.0-clean.xlf │ │ ├── resources-2.0-empty-notes.xlf │ │ ├── resources-2.0-multi-segment-unit.xlf │ │ ├── resources-2.0-name.xlf │ │ ├── resources-2.0-segment-attributes.xlf │ │ ├── resources-2.0.xlf │ │ ├── resources-2.1.xlf │ │ ├── resources-2.2-pgs-combined.xlf │ │ ├── resources-2.2-pgs-gender.xlf │ │ ├── resources-2.2-pgs-plural.xlf │ │ ├── resources-2.2.xlf │ │ ├── resources-clean.xlf │ │ ├── resources-clean.xliff │ │ ├── resources-multi-files.xlf │ │ ├── resources-notes-meta.xlf │ │ ├── resources-target-attributes.xlf │ │ ├── resources-tool-info.xlf │ │ ├── resources.csv │ │ ├── resources.dump.json │ │ ├── resources.ini │ │ ├── resources.json │ │ ├── resources.mo │ │ ├── resources.php │ │ ├── resources.po │ │ ├── resources.ts │ │ ├── resources.xlf │ │ ├── resources.yml │ │ ├── valid.csv │ │ ├── with-attributes.xlf │ │ ├── withdoctype.xlf │ │ └── withnote.xlf │ ├── Formatter/ │ │ ├── IntlFormatterTest.php │ │ └── MessageFormatterTest.php │ ├── IdentityTranslatorTest.php │ ├── Loader/ │ │ ├── CsvFileLoaderTest.php │ │ ├── IcuDatFileLoaderTest.php │ │ ├── IcuResFileLoaderTest.php │ │ ├── IniFileLoaderTest.php │ │ ├── JsonFileLoaderTest.php │ │ ├── LocalizedTestCase.php │ │ ├── MoFileLoaderTest.php │ │ ├── PhpFileLoaderTest.php │ │ ├── PoFileLoaderTest.php │ │ ├── QtFileLoaderTest.php │ │ ├── XliffFileLoaderTest.php │ │ └── YamlFileLoaderTest.php │ ├── LocaleFallbackProviderTest.php │ ├── LocaleSwitcherTest.php │ ├── LoggingTranslatorTest.php │ ├── MessageCatalogueTest.php │ ├── Provider/ │ │ ├── DsnTest.php │ │ ├── FilteringProviderTest.php │ │ ├── NullProviderFactoryTest.php │ │ └── TranslationProviderCollectionTest.php │ ├── PseudoLocalizationTranslatorTest.php │ ├── StaticMessageTest.php │ ├── TranslatableTest.php │ ├── TranslatorBagTest.php │ ├── TranslatorCacheTest.php │ ├── TranslatorTest.php │ ├── Util/ │ │ └── ArrayConverterTest.php │ └── Writer/ │ └── TranslationWriterTest.php ├── TranslatableMessage.php ├── Translator.php ├── TranslatorBag.php ├── TranslatorBagInterface.php ├── Util/ │ ├── ArrayConverter.php │ └── XliffUtils.php ├── Writer/ │ ├── TranslationWriter.php │ └── TranslationWriterInterface.php ├── composer.json └── phpunit.xml.dist
SYMBOL INDEX (953 symbols across 168 files)
FILE: Catalogue/AbstractOperation.php
class AbstractOperation (line 27) | abstract class AbstractOperation implements OperationInterface
method __construct (line 63) | public function __construct(
method getDomains (line 75) | public function getDomains(): array
method getMessages (line 95) | public function getMessages(string $domain): array
method getNewMessages (line 108) | public function getNewMessages(string $domain): array
method getObsoleteMessages (line 121) | public function getObsoleteMessages(string $domain): array
method getResult (line 134) | public function getResult(): MessageCatalogueInterface
method moveMessagesToIntlDomainsIfPossible (line 148) | public function moveMessagesToIntlDomainsIfPossible(string $batch = se...
method processDomain (line 182) | abstract protected function processDomain(string $domain): void;
FILE: Catalogue/MergeOperation.php
class MergeOperation (line 25) | class MergeOperation extends AbstractOperation
method processDomain (line 27) | protected function processDomain(string $domain): void
FILE: Catalogue/OperationInterface.php
type OperationInterface (line 35) | interface OperationInterface
method getDomains (line 40) | public function getDomains(): array;
method getMessages (line 45) | public function getMessages(string $domain): array;
method getNewMessages (line 50) | public function getNewMessages(string $domain): array;
method getObsoleteMessages (line 55) | public function getObsoleteMessages(string $domain): array;
method getResult (line 60) | public function getResult(): MessageCatalogueInterface;
FILE: Catalogue/TargetOperation.php
class TargetOperation (line 26) | class TargetOperation extends AbstractOperation
method processDomain (line 28) | protected function processDomain(string $domain): void
FILE: CatalogueMetadataAwareInterface.php
type CatalogueMetadataAwareInterface (line 19) | interface CatalogueMetadataAwareInterface
method getCatalogueMetadata (line 30) | public function getCatalogueMetadata(string $key = '', string $domain ...
method setCatalogueMetadata (line 35) | public function setCatalogueMetadata(string $key, mixed $value, string...
method deleteCatalogueMetadata (line 43) | public function deleteCatalogueMetadata(string $key = '', string $doma...
FILE: Command/TranslationLintCommand.php
class TranslationLintCommand (line 31) | #[AsCommand(name: 'lint:translations', description: 'Lint translations f...
method __construct (line 36) | public function __construct(
method complete (line 44) | public function complete(CompletionInput $input, CompletionSuggestions...
method configure (line 51) | protected function configure(): void
method initialize (line 65) | protected function initialize(InputInterface $input, OutputInterface $...
method execute (line 70) | protected function execute(InputInterface $input, OutputInterface $out...
FILE: Command/TranslationPullCommand.php
class TranslationPullCommand (line 32) | #[AsCommand(name: 'translation:pull', description: 'Pull translations fr...
method __construct (line 37) | public function __construct(
method complete (line 49) | public function complete(CompletionInput $input, CompletionSuggestions...
method configure (line 78) | protected function configure(): void
method execute (line 113) | protected function execute(InputInterface $input, OutputInterface $out...
FILE: Command/TranslationPushCommand.php
class TranslationPushCommand (line 32) | #[AsCommand(name: 'translation:push', description: 'Push translations to...
method __construct (line 37) | public function __construct(
method complete (line 47) | public function complete(CompletionInput $input, CompletionSuggestions...
method configure (line 71) | protected function configure(): void
method execute (line 108) | protected function execute(InputInterface $input, OutputInterface $out...
method getDomainsFromTranslatorBag (line 167) | private function getDomainsFromTranslatorBag(TranslatorBag $translator...
FILE: Command/TranslationTrait.php
type TranslationTrait (line 21) | trait TranslationTrait
method readLocalTranslations (line 23) | private function readLocalTranslations(array $locales, array $domains,...
method filterCatalogue (line 45) | private function filterCatalogue(MessageCatalogue $catalogue, string $...
FILE: Command/XliffLintCommand.php
class XliffLintCommand (line 35) | #[AsCommand(name: 'lint:xliff', description: 'Lint an XLIFF file and out...
method __construct (line 43) | public function __construct(
method configure (line 55) | protected function configure(): void
method execute (line 85) | protected function execute(InputInterface $input, OutputInterface $out...
method validate (line 114) | private function validate(string $content, ?string $file = null): array
method display (line 159) | private function display(SymfonyStyle $io, array $files): int
method displayTxt (line 169) | private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $...
method displayJson (line 201) | private function displayJson(SymfonyStyle $io, array $filesInfo): int
method getFiles (line 220) | private function getFiles(string $fileOrDirectory): iterable
method getDirectoryIterator (line 240) | private function getDirectoryIterator(string $directory): iterable
method isReadable (line 254) | private function isReadable(string $fileOrDirectory): bool
method getTargetLanguageFromFile (line 265) | private function getTargetLanguageFromFile(\DOMDocument $xliffContents...
method complete (line 276) | public function complete(CompletionInput $input, CompletionSuggestions...
method getAvailableFormatOptions (line 284) | private function getAvailableFormatOptions(): array
FILE: DataCollector/TranslationDataCollector.php
class TranslationDataCollector (line 26) | class TranslationDataCollector extends DataCollector implements LateData...
method __construct (line 28) | public function __construct(
method lateCollect (line 33) | public function lateCollect(): void
method collect (line 43) | public function collect(Request $request, Response $response, ?\Throwa...
method reset (line 50) | public function reset(): void
method getMessages (line 55) | public function getMessages(): array|Data
method getCountMissings (line 60) | public function getCountMissings(): int
method getCountFallbacks (line 65) | public function getCountFallbacks(): int
method getCountDefines (line 70) | public function getCountDefines(): int
method getLocale (line 75) | public function getLocale(): ?string
method getFallbackLocales (line 83) | public function getFallbackLocales(): Data|array
method getGlobalParameters (line 91) | public function getGlobalParameters(): Data|array
method getName (line 96) | public function getName(): string
method sanitizeCollectedMessages (line 101) | private function sanitizeCollectedMessages(array $messages): array
method computeCount (line 126) | private function computeCount(array $messages): array
method sanitizeString (line 141) | private function sanitizeString(string $string, int $length = 80): string
FILE: DataCollectorTranslator.php
class DataCollectorTranslator (line 22) | final class DataCollectorTranslator implements TranslatorInterface, Tran...
method __construct (line 30) | public function __construct(
method reset (line 35) | public function reset(): void
method trans (line 40) | public function trans(?string $id, array $parameters = [], ?string $do...
method setLocale (line 48) | public function setLocale(string $locale): void
method getLocale (line 53) | public function getLocale(): string
method getCatalogue (line 58) | public function getCatalogue(?string $locale = null): MessageCatalogue...
method getCatalogues (line 63) | public function getCatalogues(): array
method warmUp (line 68) | public function warmUp(string $cacheDir, ?string $buildDir = null): array
method getFallbackLocales (line 77) | public function getFallbackLocales(): array
method getGlobalParameters (line 86) | public function getGlobalParameters(): array
method __call (line 95) | public function __call(string $method, array $args): mixed
method getCollectedMessages (line 100) | public function getCollectedMessages(): array
method collectMessage (line 105) | private function collectMessage(?string $locale, ?string $domain, stri...
FILE: DependencyInjection/DataCollectorTranslatorPass.php
class DataCollectorTranslatorPass (line 21) | class DataCollectorTranslatorPass implements CompilerPassInterface
method process (line 23) | public function process(ContainerBuilder $container): void
FILE: DependencyInjection/LoggingTranslatorPass.php
class LoggingTranslatorPass (line 23) | class LoggingTranslatorPass implements CompilerPassInterface
method process (line 25) | public function process(ContainerBuilder $container): void
FILE: DependencyInjection/TranslationDumperPass.php
class TranslationDumperPass (line 21) | class TranslationDumperPass implements CompilerPassInterface
method process (line 23) | public function process(ContainerBuilder $container): void
FILE: DependencyInjection/TranslationExtractorPass.php
class TranslationExtractorPass (line 21) | class TranslationExtractorPass implements CompilerPassInterface
method process (line 23) | public function process(ContainerBuilder $container): void
FILE: DependencyInjection/TranslatorPass.php
class TranslatorPass (line 19) | class TranslatorPass implements CompilerPassInterface
method process (line 21) | public function process(ContainerBuilder $container): void
FILE: DependencyInjection/TranslatorPathsPass.php
class TranslatorPathsPass (line 24) | class TranslatorPathsPass extends AbstractRecursivePass
method process (line 45) | public function process(ContainerBuilder $container): void
method processValue (line 88) | protected function processValue(mixed $value, bool $isRoot = false): m...
method findControllerArguments (line 124) | private function findControllerArguments(ContainerBuilder $container):...
FILE: Dumper/CsvFileDumper.php
class CsvFileDumper (line 21) | class CsvFileDumper extends FileDumper
method formatCatalogue (line 26) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method setCsvControl (line 44) | public function setCsvControl(string $delimiter = ';', string $enclosu...
method getExtension (line 50) | protected function getExtension(): string
FILE: Dumper/DumperInterface.php
type DumperInterface (line 22) | interface DumperInterface
method dump (line 29) | public function dump(MessageCatalogue $messages, array $options = []):...
FILE: Dumper/FileDumper.php
class FileDumper (line 26) | abstract class FileDumper implements DumperInterface
method setRelativePathTemplate (line 36) | public function setRelativePathTemplate(string $relativePathTemplate):...
method dump (line 41) | public function dump(MessageCatalogue $messages, array $options = []):...
method formatCatalogue (line 83) | abstract public function formatCatalogue(MessageCatalogue $messages, s...
method getExtension (line 88) | abstract protected function getExtension(): string;
method getRelativePath (line 93) | private function getRelativePath(string $domain, string $locale): string
FILE: Dumper/IcuResFileDumper.php
class IcuResFileDumper (line 21) | class IcuResFileDumper extends FileDumper
method formatCatalogue (line 25) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method writePadding (line 79) | private function writePadding(string $data): ?string
method getPosition (line 86) | private function getPosition(string $data): float|int
method getExtension (line 91) | protected function getExtension(): string
FILE: Dumper/IniFileDumper.php
class IniFileDumper (line 21) | class IniFileDumper extends FileDumper
method formatCatalogue (line 23) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method getExtension (line 35) | protected function getExtension(): string
FILE: Dumper/JsonFileDumper.php
class JsonFileDumper (line 21) | class JsonFileDumper extends FileDumper
method formatCatalogue (line 23) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method getExtension (line 30) | protected function getExtension(): string
FILE: Dumper/MoFileDumper.php
class MoFileDumper (line 22) | class MoFileDumper extends FileDumper
method formatCatalogue (line 24) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method getExtension (line 64) | protected function getExtension(): string
method writeLong (line 69) | private function writeLong(mixed $str): string
FILE: Dumper/PhpFileDumper.php
class PhpFileDumper (line 21) | class PhpFileDumper extends FileDumper
method formatCatalogue (line 23) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method getExtension (line 28) | protected function getExtension(): string
FILE: Dumper/PoFileDumper.php
class PoFileDumper (line 21) | class PoFileDumper extends FileDumper
method formatCatalogue (line 23) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method getStandardRules (line 68) | private function getStandardRules(string $id): array
method getExtension (line 111) | protected function getExtension(): string
method escape (line 116) | private function escape(string $str): string
method formatComments (line 121) | private function formatComments(string|array $comments, string $prefix...
FILE: Dumper/QtFileDumper.php
class QtFileDumper (line 21) | class QtFileDumper extends FileDumper
method formatCatalogue (line 23) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method getExtension (line 51) | protected function getExtension(): string
FILE: Dumper/XliffFileDumper.php
class XliffFileDumper (line 22) | class XliffFileDumper extends FileDumper
method __construct (line 24) | public function __construct(
method formatCatalogue (line 29) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method getExtension (line 52) | protected function getExtension(): string
method dumpXliff1 (line 57) | private function dumpXliff1(string $defaultLocale, MessageCatalogue $m...
method dumpXliff2 (line 140) | private function dumpXliff2(string $defaultLocale, MessageCatalogue $m...
method hasMetadataArrayInfo (line 223) | private function hasMetadataArrayInfo(string $key, ?array $metadata = ...
FILE: Dumper/YamlFileDumper.php
class YamlFileDumper (line 24) | class YamlFileDumper extends FileDumper
method __construct (line 26) | public function __construct(
method formatCatalogue (line 31) | public function formatCatalogue(MessageCatalogue $messages, string $do...
method getExtension (line 50) | protected function getExtension(): string
FILE: Exception/ExceptionInterface.php
type ExceptionInterface (line 19) | interface ExceptionInterface extends \Throwable
FILE: Exception/IncompleteDsnException.php
class IncompleteDsnException (line 14) | class IncompleteDsnException extends InvalidArgumentException
method __construct (line 16) | public function __construct(string $message, ?string $dsn = null, ?\Th...
FILE: Exception/InvalidArgumentException.php
class InvalidArgumentException (line 19) | class InvalidArgumentException extends \InvalidArgumentException impleme...
FILE: Exception/InvalidResourceException.php
class InvalidResourceException (line 19) | class InvalidResourceException extends \InvalidArgumentException impleme...
FILE: Exception/LogicException.php
class LogicException (line 19) | class LogicException extends \LogicException implements ExceptionInterface
FILE: Exception/MissingRequiredOptionException.php
class MissingRequiredOptionException (line 17) | class MissingRequiredOptionException extends IncompleteDsnException
method __construct (line 19) | public function __construct(string $option, ?string $dsn = null, ?\Thr...
FILE: Exception/NotFoundResourceException.php
class NotFoundResourceException (line 19) | class NotFoundResourceException extends \InvalidArgumentException implem...
FILE: Exception/ProviderException.php
class ProviderException (line 19) | class ProviderException extends RuntimeException implements ProviderExce...
method __construct (line 23) | public function __construct(
method getResponse (line 34) | public function getResponse(): ResponseInterface
method getDebug (line 39) | public function getDebug(): string
FILE: Exception/ProviderExceptionInterface.php
type ProviderExceptionInterface (line 17) | interface ProviderExceptionInterface extends ExceptionInterface
method getDebug (line 22) | public function getDebug(): string;
FILE: Exception/RuntimeException.php
class RuntimeException (line 19) | class RuntimeException extends \RuntimeException implements ExceptionInt...
FILE: Exception/UnsupportedSchemeException.php
class UnsupportedSchemeException (line 17) | class UnsupportedSchemeException extends LogicException
method __construct (line 38) | public function __construct(Dsn $dsn, ?string $name = null, array $sup...
FILE: Extractor/AbstractFileExtractor.php
class AbstractFileExtractor (line 21) | abstract class AbstractFileExtractor
method extractFiles (line 23) | protected function extractFiles(string|iterable $resource): iterable
method toSplFileInfo (line 41) | private function toSplFileInfo(string $file): \SplFileInfo
method isFile (line 49) | protected function isFile(string $file): bool
method canBeExtracted (line 58) | abstract protected function canBeExtracted(string $file): bool;
method extractFromDirectory (line 60) | abstract protected function extractFromDirectory(string|array $resourc...
FILE: Extractor/ChainExtractor.php
class ChainExtractor (line 21) | class ChainExtractor implements ExtractorInterface
method addExtractor (line 33) | public function addExtractor(string $format, ExtractorInterface $extra...
method setPrefix (line 38) | public function setPrefix(string $prefix): void
method extract (line 45) | public function extract(string|iterable $directory, MessageCatalogue $...
FILE: Extractor/ExtractorInterface.php
type ExtractorInterface (line 22) | interface ExtractorInterface
method extract (line 29) | public function extract(string|iterable $resource, MessageCatalogue $c...
method setPrefix (line 34) | public function setPrefix(string $prefix): void;
FILE: Extractor/PhpAstExtractor.php
class PhpAstExtractor (line 27) | final class PhpAstExtractor extends AbstractFileExtractor implements Ext...
method __construct (line 31) | public function __construct(
method extract (line 45) | public function extract(iterable|string $resource, MessageCatalogue $c...
method setPrefix (line 64) | public function setPrefix(string $prefix): void
method canBeExtracted (line 69) | protected function canBeExtracted(string $file): bool
method extractFromDirectory (line 76) | protected function extractFromDirectory(array|string $resource): itera...
FILE: Extractor/Visitor/AbstractVisitor.php
class AbstractVisitor (line 20) | abstract class AbstractVisitor
method initialize (line 26) | public function initialize(MessageCatalogue $catalogue, \SplFileInfo $...
method addMessageToCatalogue (line 33) | protected function addMessageToCatalogue(string $message, ?string $dom...
method getStringArguments (line 43) | protected function getStringArguments(Node\Expr\CallLike|Node\Attribut...
method hasNodeNamedArguments (line 58) | protected function hasNodeNamedArguments(Node\Expr\CallLike|Node\Attri...
method nodeFirstNamedArgumentIndex (line 71) | protected function nodeFirstNamedArgumentIndex(Node\Expr\CallLike|Node...
method getStringNamedArguments (line 84) | private function getStringNamedArguments(Node\Expr\CallLike|Node\Attri...
method getStringValue (line 100) | private function getStringValue(Node $node): ?string
FILE: Extractor/Visitor/ConstraintVisitor.php
class ConstraintVisitor (line 22) | final class ConstraintVisitor extends AbstractVisitor implements NodeVis...
method __construct (line 24) | public function __construct(
method beforeTraverse (line 29) | public function beforeTraverse(array $nodes): ?Node
method enterNode (line 34) | public function enterNode(Node $node): ?Node
method leaveNode (line 39) | public function leaveNode(Node $node): ?Node
method afterTraverse (line 107) | public function afterTraverse(array $nodes): ?Node
FILE: Extractor/Visitor/TransMethodVisitor.php
class TransMethodVisitor (line 20) | final class TransMethodVisitor extends AbstractVisitor implements NodeVi...
method beforeTraverse (line 22) | public function beforeTraverse(array $nodes): ?Node
method enterNode (line 27) | public function enterNode(Node $node): ?Node
method leaveNode (line 32) | public function leaveNode(Node $node): ?Node
method afterTraverse (line 61) | public function afterTraverse(array $nodes): ?Node
FILE: Extractor/Visitor/TranslatableMessageVisitor.php
class TranslatableMessageVisitor (line 20) | final class TranslatableMessageVisitor extends AbstractVisitor implement...
method beforeTraverse (line 22) | public function beforeTraverse(array $nodes): ?Node
method enterNode (line 27) | public function enterNode(Node $node): ?Node
method leaveNode (line 32) | public function leaveNode(Node $node): ?Node
method afterTraverse (line 61) | public function afterTraverse(array $nodes): ?Node
FILE: Formatter/IntlFormatter.php
class IntlFormatter (line 21) | class IntlFormatter implements IntlFormatterInterface
method formatIntl (line 26) | public function formatIntl(string $message, string $locale, array $par...
FILE: Formatter/IntlFormatterInterface.php
type IntlFormatterInterface (line 19) | interface IntlFormatterInterface
method formatIntl (line 26) | public function formatIntl(string $message, string $locale, array $par...
FILE: Formatter/MessageFormatter.php
class MessageFormatter (line 23) | class MessageFormatter implements MessageFormatterInterface, IntlFormatt...
method __construct (line 31) | public function __construct(?TranslatorInterface $translator = null, ?...
method format (line 37) | public function format(string $message, string $locale, array $paramet...
method formatIntl (line 42) | public function formatIntl(string $message, string $locale, array $par...
FILE: Formatter/MessageFormatterInterface.php
type MessageFormatterInterface (line 18) | interface MessageFormatterInterface
method format (line 27) | public function format(string $message, string $locale, array $paramet...
FILE: IdentityTranslator.php
class IdentityTranslator (line 23) | class IdentityTranslator implements TranslatorInterface, LocaleAwareInte...
method setLocale (line 27) | public function setLocale(string $locale): void
FILE: Loader/ArrayLoader.php
class ArrayLoader (line 21) | class ArrayLoader implements LoaderInterface
method load (line 23) | public function load(mixed $resource, string $locale, string $domain =...
method flatten (line 40) | private function flatten(array $messages): array
FILE: Loader/CsvFileLoader.php
class CsvFileLoader (line 21) | class CsvFileLoader extends FileLoader
method loadResource (line 26) | protected function loadResource(string $resource): array
method setCsvControl (line 55) | public function setCsvControl(string $delimiter = ';', string $enclosu...
FILE: Loader/FileLoader.php
class FileLoader (line 22) | abstract class FileLoader extends ArrayLoader
method load (line 24) | public function load(mixed $resource, string $locale, string $domain =...
method loadResource (line 56) | abstract protected function loadResource(string $resource): array;
FILE: Loader/IcuDatFileLoader.php
class IcuDatFileLoader (line 24) | class IcuDatFileLoader extends IcuResFileLoader
method load (line 26) | public function load(mixed $resource, string $locale, string $domain =...
FILE: Loader/IcuResFileLoader.php
class IcuResFileLoader (line 24) | class IcuResFileLoader implements LoaderInterface
method load (line 26) | public function load(mixed $resource, string $locale, string $domain =...
method flatten (line 73) | protected function flatten(\ResourceBundle $rb, array &$messages = [],...
FILE: Loader/IniFileLoader.php
class IniFileLoader (line 19) | class IniFileLoader extends FileLoader
method loadResource (line 21) | protected function loadResource(string $resource): array
FILE: Loader/JsonFileLoader.php
class JsonFileLoader (line 21) | class JsonFileLoader extends FileLoader
method loadResource (line 23) | protected function loadResource(string $resource): array
method getJSONErrorMessage (line 40) | private function getJSONErrorMessage(int $errorCode): string
FILE: Loader/LoaderInterface.php
type LoaderInterface (line 23) | interface LoaderInterface
method load (line 31) | public function load(mixed $resource, string $locale, string $domain =...
FILE: Loader/MoFileLoader.php
class MoFileLoader (line 19) | class MoFileLoader extends FileLoader
method loadResource (line 42) | protected function loadResource(string $resource): array
method readLong (line 131) | private function readLong($stream, bool $isBigEndian): int
FILE: Loader/PhpFileLoader.php
class PhpFileLoader (line 19) | class PhpFileLoader extends FileLoader
method loadResource (line 23) | protected function loadResource(string $resource): array
FILE: Loader/PoFileLoader.php
class PoFileLoader (line 18) | class PoFileLoader extends FileLoader
method loadResource (line 61) | protected function loadResource(string $resource): array
method addMessage (line 125) | private function addMessage(array &$messages, array $item): void
FILE: Loader/QtFileLoader.php
class QtFileLoader (line 26) | class QtFileLoader implements LoaderInterface
method load (line 28) | public function load(mixed $resource, string $locale, string $domain =...
FILE: Loader/XliffFileLoader.php
class XliffFileLoader (line 30) | class XliffFileLoader implements LoaderInterface
method load (line 32) | public function load(mixed $resource, string $locale, string $domain =...
method extract (line 76) | private function extract(\DOMDocument $dom, MessageCatalogue $catalogu...
method extractXliff1 (line 92) | private function extractXliff1(\DOMDocument $dom, MessageCatalogue $ca...
method extractXliff2 (line 157) | private function extractXliff2(\DOMDocument $dom, MessageCatalogue $ca...
method extractXliff2PgsUnit (line 212) | private function extractXliff2PgsUnit(\SimpleXMLElement $unit, Message...
method parsePgsSwitch (line 244) | private function parsePgsSwitch(string $pgsSwitch): array
method extractPgsSegmentText (line 254) | private function extractPgsSegmentText(\SimpleXMLElement $element, arr...
method buildIcuMessage (line 279) | private function buildIcuMessage(array $switches, array $cases): string
method getIcuType (line 311) | private function getIcuType(string $pgsType): string
method formatIcuCase (line 320) | private function formatIcuCase(int|string $caseValue, string $switchTy...
method utf8ToCharset (line 328) | private function utf8ToCharset(string $content, ?string $encoding = nu...
method parseNotesMetadata (line 337) | private function parseNotesMetadata(?\SimpleXMLElement $noteElement = ...
method isXmlString (line 363) | private function isXmlString(string $resource): bool
FILE: Loader/YamlFileLoader.php
class YamlFileLoader (line 25) | class YamlFileLoader extends FileLoader
method loadResource (line 29) | protected function loadResource(string $resource): array
FILE: LocaleFallbackProvider.php
class LocaleFallbackProvider (line 24) | final class LocaleFallbackProvider
method __construct (line 31) | public function __construct(
method computeFallbackLocales (line 42) | public function computeFallbackLocales(string $locale): array
method validateLocale (line 89) | public static function validateLocale(string $locale): void
FILE: LocaleSwitcher.php
class LocaleSwitcher (line 20) | class LocaleSwitcher implements LocaleAwareInterface
method __construct (line 27) | public function __construct(
method setLocale (line 35) | public function setLocale(string $locale): void
method getLocale (line 53) | public function getLocale(): string
method runWithLocale (line 67) | public function runWithLocale(string $locale, callable $callback): mixed
method reset (line 79) | public function reset(): void
FILE: LoggingTranslator.php
class LoggingTranslator (line 21) | class LoggingTranslator implements TranslatorInterface, TranslatorBagInt...
method __construct (line 23) | public function __construct(
method trans (line 29) | public function trans(?string $id, array $parameters = [], ?string $do...
method setLocale (line 37) | public function setLocale(string $locale): void
method getLocale (line 48) | public function getLocale(): string
method getCatalogue (line 53) | public function getCatalogue(?string $locale = null): MessageCatalogue...
method getCatalogues (line 58) | public function getCatalogues(): array
method getFallbackLocales (line 63) | public function getFallbackLocales(): array
method __call (line 72) | public function __call(string $method, array $args): mixed
method log (line 80) | private function log(string $id, ?string $domain, ?string $locale): void
FILE: MessageCatalogue.php
class MessageCatalogue (line 20) | class MessageCatalogue implements MessageCatalogueInterface, MetadataAwa...
method __construct (line 31) | public function __construct(
method getLocale (line 37) | public function getLocale(): string
method getDomains (line 42) | public function getDomains(): array
method all (line 56) | public function all(?string $domain = null): array
method set (line 81) | public function set(string $id, string $translation, string $domain = ...
method has (line 86) | public function has(string $id, string $domain = 'messages'): bool
method defines (line 99) | public function defines(string $id, string $domain = 'messages'): bool
method get (line 104) | public function get(string $id, string $domain = 'messages'): string
method replace (line 121) | public function replace(array $messages, string $domain = 'messages'):...
method add (line 128) | public function add(array $messages, string $domain = 'messages'): void
method addCatalogue (line 141) | public function addCatalogue(MessageCatalogueInterface $catalogue): void
method addFallbackCatalogue (line 170) | public function addFallbackCatalogue(MessageCatalogueInterface $catalo...
method getFallbackCatalogue (line 199) | public function getFallbackCatalogue(): ?MessageCatalogueInterface
method getResources (line 204) | public function getResources(): array
method addResource (line 209) | public function addResource(ResourceInterface $resource): void
method getMetadata (line 214) | public function getMetadata(string $key = '', string $domain = 'messag...
method setMetadata (line 243) | public function setMetadata(string $key, mixed $value, string $domain ...
method deleteMetadata (line 248) | public function deleteMetadata(string $key = '', string $domain = 'mes...
method getCatalogueMetadata (line 259) | public function getCatalogueMetadata(string $key = '', string $domain ...
method setCatalogueMetadata (line 278) | public function setCatalogueMetadata(string $key, mixed $value, string...
method deleteCatalogueMetadata (line 283) | public function deleteCatalogueMetadata(string $key = '', string $doma...
method addMetadata (line 299) | private function addMetadata(array $values): void
method addCatalogueMetadata (line 308) | private function addCatalogueMetadata(array $values): void
FILE: MessageCatalogueInterface.php
type MessageCatalogueInterface (line 21) | interface MessageCatalogueInterface
method getLocale (line 28) | public function getLocale(): string;
method getDomains (line 33) | public function getDomains(): array;
method all (line 40) | public function all(?string $domain = null): array;
method set (line 49) | public function set(string $id, string $translation, string $domain = ...
method has (line 57) | public function has(string $id, string $domain = 'messages'): bool;
method defines (line 65) | public function defines(string $id, string $domain = 'messages'): bool;
method get (line 73) | public function get(string $id, string $domain = 'messages'): string;
method replace (line 81) | public function replace(array $messages, string $domain = 'messages'):...
method add (line 89) | public function add(array $messages, string $domain = 'messages'): void;
method addCatalogue (line 96) | public function addCatalogue(self $catalogue): void;
method addFallbackCatalogue (line 104) | public function addFallbackCatalogue(self $catalogue): void;
method getFallbackCatalogue (line 109) | public function getFallbackCatalogue(): ?self;
method getResources (line 116) | public function getResources(): array;
method addResource (line 121) | public function addResource(ResourceInterface $resource): void;
FILE: MetadataAwareInterface.php
type MetadataAwareInterface (line 19) | interface MetadataAwareInterface
method getMetadata (line 30) | public function getMetadata(string $key = '', string $domain = 'messag...
method setMetadata (line 35) | public function setMetadata(string $key, mixed $value, string $domain ...
method deleteMetadata (line 43) | public function deleteMetadata(string $key = '', string $domain = 'mes...
FILE: Provider/AbstractProviderFactory.php
class AbstractProviderFactory (line 16) | abstract class AbstractProviderFactory implements ProviderFactoryInterface
method supports (line 18) | public function supports(Dsn $dsn): bool
method getSupportedSchemes (line 26) | abstract protected function getSupportedSchemes(): array;
method getUser (line 28) | protected function getUser(Dsn $dsn): string
method getPassword (line 33) | protected function getPassword(Dsn $dsn): string
FILE: Provider/Dsn.php
class Dsn (line 21) | final class Dsn
method __construct (line 32) | public function __construct(#[\SensitiveParameter] string $dsn)
method getScheme (line 57) | public function getScheme(): string
method getHost (line 62) | public function getHost(): string
method getUser (line 67) | public function getUser(): ?string
method getPassword (line 72) | public function getPassword(): ?string
method getPort (line 77) | public function getPort(?int $default = null): ?int
method getOption (line 82) | public function getOption(string $key, mixed $default = null): mixed
method getRequiredOption (line 87) | public function getRequiredOption(string $key): mixed
method getOptions (line 96) | public function getOptions(): array
method getPath (line 101) | public function getPath(): ?string
method getOriginalDsn (line 106) | public function getOriginalDsn(): string
FILE: Provider/FilteringProvider.php
class FilteringProvider (line 22) | class FilteringProvider implements ProviderInterface
method __construct (line 24) | public function __construct(
method __toString (line 32) | public function __toString(): string
method write (line 37) | public function write(TranslatorBagInterface $translatorBag): void
method read (line 42) | public function read(array $domains, array $locales): TranslatorBag
method delete (line 50) | public function delete(TranslatorBagInterface $translatorBag): void
method getDomains (line 55) | public function getDomains(): array
FILE: Provider/NullProvider.php
class NullProvider (line 20) | class NullProvider implements ProviderInterface
method __toString (line 22) | public function __toString(): string
method write (line 27) | public function write(TranslatorBagInterface $translatorBag, bool $ove...
method read (line 31) | public function read(array $domains, array $locales): TranslatorBag
method delete (line 36) | public function delete(TranslatorBagInterface $translatorBag): void
FILE: Provider/NullProviderFactory.php
class NullProviderFactory (line 19) | final class NullProviderFactory extends AbstractProviderFactory
method create (line 21) | public function create(Dsn $dsn): ProviderInterface
method getSupportedSchemes (line 30) | protected function getSupportedSchemes(): array
FILE: Provider/ProviderFactoryInterface.php
type ProviderFactoryInterface (line 17) | interface ProviderFactoryInterface
method create (line 23) | public function create(Dsn $dsn): ProviderInterface;
method supports (line 25) | public function supports(Dsn $dsn): bool;
FILE: Provider/ProviderInterface.php
type ProviderInterface (line 17) | interface ProviderInterface extends \Stringable
method write (line 25) | public function write(TranslatorBagInterface $translatorBag): void;
method read (line 27) | public function read(array $domains, array $locales): TranslatorBag;
method delete (line 29) | public function delete(TranslatorBagInterface $translatorBag): void;
FILE: Provider/TranslationProviderCollection.php
class TranslationProviderCollection (line 19) | final class TranslationProviderCollection
method __construct (line 29) | public function __construct(iterable $providers)
method __toString (line 34) | public function __toString(): string
method has (line 39) | public function has(string $name): bool
method get (line 44) | public function get(string $name): ProviderInterface
method keys (line 53) | public function keys(): array
FILE: Provider/TranslationProviderCollectionFactory.php
class TranslationProviderCollectionFactory (line 19) | class TranslationProviderCollectionFactory
method __construct (line 24) | public function __construct(
method fromConfig (line 30) | public function fromConfig(array $config): TranslationProviderCollection
method fromDsnObject (line 44) | public function fromDsnObject(Dsn $dsn, array $locales, array $domains...
FILE: PseudoLocalizationTranslator.php
class PseudoLocalizationTranslator (line 20) | final class PseudoLocalizationTranslator implements TranslatorInterface,...
method __construct (line 67) | public function __construct(
method trans (line 88) | public function trans(string $id, array $parameters = [], ?string $dom...
method getLocale (line 114) | public function getLocale(): string
method getCatalogue (line 119) | public function getCatalogue(?string $locale = null): MessageCatalogue...
method getCatalogues (line 128) | public function getCatalogues(): array
method getParts (line 137) | private function getParts(string $originalTrans): array
method parseNode (line 156) | private function parseNode(\DOMNode $node): array
method addAccents (line 194) | private function addAccents(string &$trans, string $text): void
method expand (line 295) | private function expand(string &$trans, string $visibleText): void
method addBrackets (line 371) | private function addBrackets(string &$trans): void
method strlen (line 380) | private function strlen(string $s): int
FILE: Reader/TranslationReader.php
class TranslationReader (line 23) | class TranslationReader implements TranslationReaderInterface
method addLoader (line 37) | public function addLoader(string $format, LoaderInterface $loader): void
method read (line 42) | public function read(string $directory, MessageCatalogue $catalogue): ...
FILE: Reader/TranslationReaderInterface.php
type TranslationReaderInterface (line 21) | interface TranslationReaderInterface
method read (line 26) | public function read(string $directory, MessageCatalogue $catalogue): ...
FILE: Resources/bin/translation-status.php
function findTranslationFiles (line 98) | function findTranslationFiles($originalFilePath, $localeToAnalyze): array
function calculateTranslationStatus (line 121) | function calculateTranslationStatus($originalFilePath, $translationFileP...
function isTranslationCompleted (line 143) | function isTranslationCompleted(array $translationStatus): bool
function printTranslationStatus (line 148) | function printTranslationStatus($originalFilePath, $translationStatus, $...
function extractLocaleFromFilePath (line 155) | function extractLocaleFromFilePath($filePath)
function extractTranslationKeys (line 162) | function extractTranslationKeys($filePath): array
function findTransUnitMismatches (line 180) | function findTransUnitMismatches(array $baseTranslationKeys, array $tran...
function printTitle (line 199) | function printTitle($title): void
function printTable (line 205) | function printTable($translations, $verboseOutput, bool $includeComplete...
function textColorGreen (line 261) | function textColorGreen(): void
function textColorRed (line 266) | function textColorRed(): void
function textColorNormal (line 271) | function textColorNormal(): void
FILE: Resources/functions.php
function t (line 18) | function t(string $message, array $parameters = [], ?string $domain = nu...
FILE: StaticMessage.php
class StaticMessage (line 17) | final class StaticMessage implements TranslatableInterface
method __construct (line 19) | public function __construct(
method getMessage (line 24) | public function getMessage(): string
method trans (line 29) | public function trans(TranslatorInterface $translator, ?string $locale...
FILE: Test/AbstractProviderFactoryTestCase.php
class AbstractProviderFactoryTestCase (line 20) | abstract class AbstractProviderFactoryTestCase extends TestCase
method createFactory (line 22) | abstract public function createFactory(): ProviderFactoryInterface;
method supportsProvider (line 27) | abstract public static function supportsProvider(): iterable;
method createProvider (line 32) | abstract public static function createProvider(): iterable;
method unsupportedSchemeProvider (line 37) | abstract public static function unsupportedSchemeProvider(): iterable;
method testSupports (line 42) | #[DataProvider('supportsProvider')]
method testCreate (line 53) | #[DataProvider('createProvider')]
method testUnsupportedSchemeException (line 65) | #[DataProvider('unsupportedSchemeProvider')]
FILE: Test/IncompleteDsnTestTrait.php
type IncompleteDsnTestTrait (line 18) | trait IncompleteDsnTestTrait
method incompleteDsnProvider (line 23) | abstract public static function incompleteDsnProvider(): iterable;
method testIncompleteDsnException (line 28) | #[DataProvider('incompleteDsnProvider')]
FILE: Test/ProviderTestCase.php
class ProviderTestCase (line 33) | abstract class ProviderTestCase extends TestCase
method createProvider (line 42) | abstract public static function createProvider(HttpClientInterface $cl...
method toStringProvider (line 47) | abstract public static function toStringProvider(): iterable;
method testToString (line 52) | #[DataProvider('toStringProvider')]
method getClient (line 58) | protected function getClient(): MockHttpClient
method getLoader (line 63) | protected function getLoader(): LoaderInterface
method getLogger (line 68) | protected function getLogger(): LoggerInterface
method getDefaultLocale (line 73) | protected function getDefaultLocale(): string
method getXliffFileDumper (line 78) | protected function getXliffFileDumper(): XliffFileDumper
method getTranslatorBag (line 83) | protected function getTranslatorBag(): TranslatorBagInterface
FILE: Tests/Catalogue/AbstractOperationTestCase.php
class AbstractOperationTestCase (line 19) | abstract class AbstractOperationTestCase extends TestCase
method testGetEmptyDomains (line 21) | public function testGetEmptyDomains()
method testGetMergedDomains (line 32) | public function testGetMergedDomains()
method testGetMessagesFromUnknownDomain (line 43) | public function testGetMessagesFromUnknownDomain()
method testGetEmptyMessages (line 52) | public function testGetEmptyMessages()
method testGetEmptyResult (line 63) | public function testGetEmptyResult()
method testSourceAndTargetWithDifferentLocales (line 74) | public function testSourceAndTargetWithDifferentLocales()
method createOperation (line 84) | abstract protected function createOperation(MessageCatalogueInterface ...
FILE: Tests/Catalogue/MergeOperationTest.php
class MergeOperationTest (line 18) | class MergeOperationTest extends AbstractOperationTestCase
method testGetMessagesFromSingleDomain (line 20) | public function testGetMessagesFromSingleDomain()
method testGetResultFromSingleDomain (line 43) | public function testGetResultFromSingleDomain()
method testGetResultFromIntlDomain (line 56) | public function testGetResultFromIntlDomain()
method testGetResultWithMetadata (line 70) | public function testGetResultWithMetadata()
method testGetResultWithMetadataFromIntlDomain (line 93) | public function testGetResultWithMetadataFromIntlDomain()
method createOperation (line 116) | protected function createOperation(MessageCatalogueInterface $source, ...
FILE: Tests/Catalogue/MessageCatalogueTest.php
class MessageCatalogueTest (line 17) | class MessageCatalogueTest extends TestCase
method testIcuMetadataKept (line 19) | public function testIcuMetadataKept()
FILE: Tests/Catalogue/TargetOperationTest.php
class TargetOperationTest (line 18) | class TargetOperationTest extends AbstractOperationTestCase
method testGetMessagesFromSingleDomain (line 20) | public function testGetMessagesFromSingleDomain()
method testGetResultFromSingleDomain (line 43) | public function testGetResultFromSingleDomain()
method testGetResultFromIntlDomain (line 56) | public function testGetResultFromIntlDomain()
method testGetResultWithMixedDomains (line 70) | public function testGetResultWithMixedDomains()
method testGetResultWithMetadata (line 114) | public function testGetResultWithMetadata()
method testGetResultWithMetadataFromIntlDomain (line 136) | public function testGetResultWithMetadataFromIntlDomain()
method createOperation (line 158) | protected function createOperation(MessageCatalogueInterface $source, ...
FILE: Tests/Command/TranslationLintCommandTest.php
class TranslationLintCommandTest (line 23) | final class TranslationLintCommandTest extends TestCase
method testLintCorrectTranslations (line 25) | #[RequiresPhpExtension('intl')]
method testLintMalformedIcuTranslations (line 64) | #[RequiresPhpExtension('intl')]
method createCommand (line 159) | private function createCommand(Translator $translator, array $enabledL...
method getNormalizedDisplay (line 172) | private function getNormalizedDisplay(CommandTester $commandTester): s...
FILE: Tests/Command/TranslationProviderTestCase.php
class TranslationProviderTestCase (line 23) | abstract class TranslationProviderTestCase extends TestCase
method setUp (line 30) | protected function setUp(): void
method tearDown (line 40) | protected function tearDown(): void
method getProviderCollection (line 46) | protected function getProviderCollection(ProviderInterface $provider, ...
method createYamlFile (line 57) | protected function createYamlFile(array $messages = ['node' => 'NOTE']...
method createFile (line 73) | protected function createFile(array $messages = ['note' => 'NOTE'], $t...
FILE: Tests/Command/TranslationPullCommandTest.php
class TranslationPullCommandTest (line 33) | class TranslationPullCommandTest extends TranslationProviderTestCase
method setUp (line 37) | protected function setUp(): void
method tearDown (line 44) | protected function tearDown(): void
method testPullNewXlf12Messages (line 50) | public function testPullNewXlf12Messages()
method testPullNewXlf20Messages (line 172) | public function testPullNewXlf20Messages()
method testPullNewYamlMessagesAsInlined (line 248) | public function testPullNewYamlMessagesAsInlined()
method testPullNewYamlMessagesAsTree (line 296) | public function testPullNewYamlMessagesAsTree()
method testPullForceMessages (line 346) | public function testPullForceMessages()
method testPullForceIntlIcuMessages (line 479) | #[RequiresPhpExtension('intl')]
method testPullMessagesWithDefaultLocale (line 559) | public function testPullMessagesWithDefaultLocale()
method testPullMessagesMultipleDomains (line 637) | public function testPullMessagesMultipleDomains()
method testComplete (line 716) | #[DataProvider('provideCompletionSuggestions')]
method provideCompletionSuggestions (line 727) | public static function provideCompletionSuggestions(): \Generator
method createCommandTester (line 745) | private function createCommandTester(ProviderInterface $provider, arra...
method createCommand (line 754) | private function createCommand(ProviderInterface $provider, array $loc...
FILE: Tests/Command/TranslationPushCommandTest.php
class TranslationPushCommandTest (line 30) | class TranslationPushCommandTest extends TranslationProviderTestCase
method setUp (line 34) | protected function setUp(): void
method tearDown (line 41) | protected function tearDown(): void
method testPushNewMessages (line 47) | public function testPushNewMessages()
method testPushNewIntlIcuMessages (line 93) | public function testPushNewIntlIcuMessages()
method testPushForceMessages (line 139) | public function testPushForceMessages()
method testDeleteMissingMessages (line 184) | public function testDeleteMissingMessages()
method testPushForceAndDeleteMissingMessages (line 248) | public function testPushForceAndDeleteMissingMessages()
method testPushWithProviderDomains (line 315) | public function testPushWithProviderDomains()
method testComplete (line 377) | #[DataProvider('provideCompletionSuggestions')]
method provideCompletionSuggestions (line 388) | public static function provideCompletionSuggestions(): \Generator
method createCommandTester (line 406) | private function createCommandTester(ProviderInterface $provider, arra...
method createCommand (line 415) | private function createCommand(ProviderInterface $provider, array $loc...
FILE: Tests/Command/XliffLintCommandTest.php
class XliffLintCommandTest (line 28) | class XliffLintCommandTest extends TestCase
method testLintCorrectFile (line 32) | public function testLintCorrectFile()
method testLintCorrectFiles (line 46) | public function testLintCorrectFiles()
method testStrictFilenames (line 61) | #[DataProvider('provideStrictFilenames')]
method testLintIncorrectXmlSyntax (line 76) | public function testLintIncorrectXmlSyntax()
method testLintIncorrectTargetLanguage (line 87) | public function testLintIncorrectTargetLanguage()
method testLintTargetLanguageIsCaseInsensitive (line 98) | public function testLintTargetLanguageIsCaseInsensitive()
method testLintSucceedsWhenLocaleInFileAndInTargetLanguageNameUsesDashesInsteadOfUnderscores (line 109) | public function testLintSucceedsWhenLocaleInFileAndInTargetLanguageNam...
method testLintFileNotReadable (line 120) | public function testLintFileNotReadable()
method testGetHelp (line 131) | public function testGetHelp()
method testLintIncorrectFileWithGithubFormat (line 147) | public function testLintIncorrectFileWithGithubFormat()
method testLintAutodetectsGithubActionEnvironment (line 156) | public function testLintAutodetectsGithubActionEnvironment()
method testPassingClosureAndCallableToConstructor (line 174) | public function testPassingClosureAndCallableToConstructor()
method createFile (line 184) | private function createFile($sourceContent = 'note', $targetLanguage =...
method createCommand (line 208) | private function createCommand($requireStrictFileNames = true, $applic...
method createCommandTester (line 222) | private function createCommandTester($requireStrictFileNames = true, $...
method setUp (line 227) | protected function setUp(): void
method tearDown (line 233) | protected function tearDown(): void
method provideStrictFilenames (line 243) | public static function provideStrictFilenames()
method testComplete (line 255) | #[DataProvider('provideCompletionSuggestions')]
method provideCompletionSuggestions (line 263) | public static function provideCompletionSuggestions()
FILE: Tests/DataCollector/TranslationDataCollectorTest.php
class TranslationDataCollectorTest (line 22) | class TranslationDataCollectorTest extends TestCase
method testCollectEmptyMessages (line 24) | public function testCollectEmptyMessages()
method testCollect (line 35) | public function testCollect()
method testCollectAndReset (line 98) | public function testCollectAndReset()
FILE: Tests/DataCollectorTranslatorTest.php
class DataCollectorTranslatorTest (line 20) | class DataCollectorTranslatorTest extends TestCase
method testCollectMessages (line 22) | public function testCollectMessages()
method testGetGlobalParameters (line 88) | public function testGetGlobalParameters()
method createCollector (line 100) | private function createCollector()
FILE: Tests/DependencyInjection/DataCollectorTranslatorPassTest.php
class DataCollectorTranslatorPassTest (line 24) | class DataCollectorTranslatorPassTest extends TestCase
method setUp (line 29) | protected function setUp(): void
method testProcessKeepsDataCollectorTranslatorIfItImplementsTranslatorBagInterface (line 47) | #[DataProvider('getImplementingTranslatorBagInterfaceTranslatorClassNa...
method testProcessKeepsDataCollectorIfTranslatorImplementsTranslatorBagInterface (line 57) | #[DataProvider('getImplementingTranslatorBagInterfaceTranslatorClassNa...
method getImplementingTranslatorBagInterfaceTranslatorClassNames (line 67) | public static function getImplementingTranslatorBagInterfaceTranslator...
method testProcessRemovesDataCollectorTranslatorIfItDoesNotImplementTranslatorBagInterface (line 75) | #[DataProvider('getNotImplementingTranslatorBagInterfaceTranslatorClas...
method testProcessRemovesDataCollectorIfTranslatorDoesNotImplementTranslatorBagInterface (line 85) | #[DataProvider('getNotImplementingTranslatorBagInterfaceTranslatorClas...
method getNotImplementingTranslatorBagInterfaceTranslatorClassNames (line 95) | public static function getNotImplementingTranslatorBagInterfaceTransla...
class TranslatorWithoutTranslatorBag (line 104) | class TranslatorWithoutTranslatorBag implements TranslatorInterface
method trans (line 106) | public function trans(string $id, array $parameters = [], ?string $dom...
method getLocale (line 110) | public function getLocale(): string
FILE: Tests/DependencyInjection/Fixtures/ControllerArguments.php
class ControllerArguments (line 16) | class ControllerArguments
method __invoke (line 18) | public function __invoke(TranslatorInterface $translator)
method index (line 22) | public function index(TranslatorInterface $translator)
FILE: Tests/DependencyInjection/Fixtures/ServiceArguments.php
class ServiceArguments (line 16) | class ServiceArguments
method __construct (line 18) | public function __construct(TranslatorInterface $translator)
FILE: Tests/DependencyInjection/Fixtures/ServiceMethodCalls.php
class ServiceMethodCalls (line 16) | class ServiceMethodCalls
method setTranslator (line 18) | public function setTranslator(TranslatorInterface $translator)
FILE: Tests/DependencyInjection/Fixtures/ServiceProperties.php
class ServiceProperties (line 14) | class ServiceProperties
FILE: Tests/DependencyInjection/Fixtures/ServiceSubscriber.php
class ServiceSubscriber (line 18) | class ServiceSubscriber implements ServiceSubscriberInterface
method __construct (line 20) | public function __construct(ContainerInterface $container)
method getSubscribedServices (line 24) | public static function getSubscribedServices(): array
FILE: Tests/DependencyInjection/LoggingTranslatorPassTest.php
class LoggingTranslatorPassTest (line 20) | class LoggingTranslatorPassTest extends TestCase
method testProcess (line 22) | public function testProcess()
method testThatCompilerPassIsIgnoredIfThereIsNotLoggerDefinition (line 49) | public function testThatCompilerPassIsIgnoredIfThereIsNotLoggerDefinit...
method testThatCompilerPassIsIgnoredIfThereIsNotTranslatorDefinition (line 66) | public function testThatCompilerPassIsIgnoredIfThereIsNotTranslatorDef...
FILE: Tests/DependencyInjection/TranslationDumperPassTest.php
class TranslationDumperPassTest (line 19) | class TranslationDumperPassTest extends TestCase
method testProcess (line 21) | public function testProcess()
method testProcessNoDefinitionFound (line 34) | public function testProcessNoDefinitionFound()
FILE: Tests/DependencyInjection/TranslationExtractorPassTest.php
class TranslationExtractorPassTest (line 19) | class TranslationExtractorPassTest extends TestCase
method testProcess (line 21) | public function testProcess()
method testProcessNoDefinitionFound (line 34) | public function testProcessNoDefinitionFound()
method testProcessMissingAlias (line 49) | public function testProcessMissingAlias()
FILE: Tests/DependencyInjection/TranslationPathsPassTest.php
class TranslationPathsPassTest (line 27) | class TranslationPathsPassTest extends TestCase
method testProcess (line 29) | public function testProcess()
FILE: Tests/DependencyInjection/TranslatorPassTest.php
class TranslatorPassTest (line 26) | class TranslatorPassTest extends TestCase
method testValidCollector (line 28) | public function testValidCollector()
method testValidCommandsViewPathsArgument (line 63) | public function testValidCommandsViewPathsArgument()
method testCommandsViewPathsArgumentsAreIgnoredWithOldServiceDefinitions (line 91) | public function testCommandsViewPathsArgumentsAreIgnoredWithOldService...
method testValidPhpAstExtractorConstraintVisitorArguments (line 128) | public function testValidPhpAstExtractorConstraintVisitorArguments()
FILE: Tests/Dumper/CsvFileDumperTest.php
class CsvFileDumperTest (line 18) | class CsvFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
FILE: Tests/Dumper/FileDumperTest.php
class FileDumperTest (line 18) | class FileDumperTest extends TestCase
method testDump (line 20) | public function testDump()
method testDumpIntl (line 35) | public function testDumpIntl()
method testDumpCreatesNestedDirectoriesAndFile (line 59) | public function testDumpCreatesNestedDirectoriesAndFile()
class ConcreteFileDumper (line 79) | class ConcreteFileDumper extends FileDumper
method formatCatalogue (line 81) | public function formatCatalogue(MessageCatalogue $messages, $domain, a...
method getExtension (line 86) | protected function getExtension(): string
FILE: Tests/Dumper/IcuResFileDumperTest.php
class IcuResFileDumperTest (line 18) | class IcuResFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
FILE: Tests/Dumper/IniFileDumperTest.php
class IniFileDumperTest (line 18) | class IniFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
FILE: Tests/Dumper/JsonFileDumperTest.php
class JsonFileDumperTest (line 18) | class JsonFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
method testDumpWithCustomEncoding (line 30) | public function testDumpWithCustomEncoding()
FILE: Tests/Dumper/MoFileDumperTest.php
class MoFileDumperTest (line 18) | class MoFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
FILE: Tests/Dumper/PhpFileDumperTest.php
class PhpFileDumperTest (line 18) | class PhpFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
FILE: Tests/Dumper/PoFileDumperTest.php
class PoFileDumperTest (line 18) | class PoFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
method testDumpPlurals (line 49) | public function testDumpPlurals()
FILE: Tests/Dumper/QtFileDumperTest.php
class QtFileDumperTest (line 18) | class QtFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
FILE: Tests/Dumper/XliffFileDumperTest.php
class XliffFileDumperTest (line 18) | class XliffFileDumperTest extends TestCase
method testFormatCatalogue (line 20) | public function testFormatCatalogue()
method testFormatCatalogueXliff2 (line 39) | public function testFormatCatalogueXliff2()
method testFormatIcuCatalogueXliff2 (line 58) | public function testFormatIcuCatalogueXliff2()
method testFormatCatalogueWithCustomToolInfo (line 73) | public function testFormatCatalogueWithCustomToolInfo()
method testFormatCatalogueWithTargetAttributesMetadata (line 91) | public function testFormatCatalogueWithTargetAttributesMetadata()
method testFormatCatalogueWithNotesMetadata (line 107) | public function testFormatCatalogueWithNotesMetadata()
method testDumpCatalogueWithXliffExtension (line 132) | public function testDumpCatalogueWithXliffExtension()
method testEmptyMetadataNotes (line 151) | public function testEmptyMetadataNotes()
method testFormatCatalogueXliff2WithSegmentAttributes (line 169) | public function testFormatCatalogueXliff2WithSegmentAttributes()
FILE: Tests/Dumper/YamlFileDumperTest.php
class YamlFileDumperTest (line 18) | class YamlFileDumperTest extends TestCase
method testTreeFormatCatalogue (line 20) | public function testTreeFormatCatalogue()
method testLinearFormatCatalogue (line 33) | public function testLinearFormatCatalogue()
FILE: Tests/Exception/ProviderExceptionTest.php
class ProviderExceptionTest (line 18) | class ProviderExceptionTest extends TestCase
method testExceptionWithDebugMessage (line 20) | public function testExceptionWithDebugMessage()
method testExceptionWithNullAsDebugMessage (line 29) | public function testExceptionWithNullAsDebugMessage()
FILE: Tests/Exception/UnsupportedSchemeExceptionTest.php
class UnsupportedSchemeExceptionTest (line 25) | #[RunTestsInSeparateProcesses]
method setUpBeforeClass (line 28) | public static function setUpBeforeClass(): void
method testMessageWhereSchemeIsPartOfSchemeToPackageMap (line 39) | #[DataProvider('messageWhereSchemeIsPartOfSchemeToPackageMapProvider')]
method messageWhereSchemeIsPartOfSchemeToPackageMapProvider (line 50) | public static function messageWhereSchemeIsPartOfSchemeToPackageMapPro...
method testMessageWhereSchemeIsNotPartOfSchemeToPackageMap (line 58) | #[DataProvider('messageWhereSchemeIsNotPartOfSchemeToPackageMapProvide...
method messageWhereSchemeIsNotPartOfSchemeToPackageMapProvider (line 67) | public static function messageWhereSchemeIsNotPartOfSchemeToPackageMap...
FILE: Tests/Extractor/PhpAstExtractorTest.php
class PhpAstExtractorTest (line 22) | final class PhpAstExtractorTest extends TestCase
method testExtraction (line 26) | #[DataProvider('resourcesProvider')]
method testExtractionFromIndentedHeredocNowdoc (line 186) | public function testExtractionFromIndentedHeredocNowdoc()
method resourcesProvider (line 212) | public static function resourcesProvider(): array
FILE: Tests/Fixtures/extractor-ast/validator-constraints.php
class Foo (line 6) | class Foo
class Foo2 (line 27) | class Foo2
method index (line 29) | public function index()
FILE: Tests/Formatter/IntlFormatterTest.php
class IntlFormatterTest (line 21) | #[RequiresPhpExtension('intl')]
method testFormat (line 24) | #[DataProvider('provideDataForFormat')]
method testInvalidFormat (line 30) | public function testInvalidFormat()
method testFormatWithNamedArguments (line 36) | public function testFormatWithNamedArguments()
method provideDataForFormat (line 71) | public static function provideDataForFormat()
method testPercentsAndBracketsAreTrimmed (line 92) | #[DataProvider('percentAndBracketsAreTrimmedProvider')]
method percentAndBracketsAreTrimmedProvider (line 100) | public static function percentAndBracketsAreTrimmedProvider(): array
FILE: Tests/Formatter/MessageFormatterTest.php
class MessageFormatterTest (line 18) | class MessageFormatterTest extends TestCase
method testFormat (line 20) | #[DataProvider('getTransMessages')]
method getTransMessages (line 26) | public static function getTransMessages()
method getMessageFormatter (line 46) | private function getMessageFormatter()
FILE: Tests/IdentityTranslatorTest.php
class IdentityTranslatorTest (line 18) | class IdentityTranslatorTest extends TranslatorTest
method setUp (line 22) | protected function setUp(): void
method tearDown (line 30) | protected function tearDown(): void
method getTranslator (line 37) | public function getTranslator(): TranslatorInterface
FILE: Tests/Loader/CsvFileLoaderTest.php
class CsvFileLoaderTest (line 20) | class CsvFileLoaderTest extends TestCase
method testLoad (line 22) | public function testLoad()
method testLoadDoesNothingIfEmpty (line 33) | public function testLoadDoesNothingIfEmpty()
method testLoadNonExistingResource (line 44) | public function testLoadNonExistingResource()
method testLoadNonLocalResource (line 51) | public function testLoadNonLocalResource()
FILE: Tests/Loader/IcuDatFileLoaderTest.php
class IcuDatFileLoaderTest (line 20) | #[RequiresPhpExtension('intl')]
method testLoadInvalidResource (line 23) | public function testLoadInvalidResource()
method testDatEnglishLoad (line 30) | public function testDatEnglishLoad()
method testDatFrenchLoad (line 44) | public function testDatFrenchLoad()
method testLoadNonExistingResource (line 55) | public function testLoadNonExistingResource()
FILE: Tests/Loader/IcuResFileLoaderTest.php
class IcuResFileLoaderTest (line 20) | #[RequiresPhpExtension('intl')]
method testLoad (line 23) | public function testLoad()
method testLoadNonExistingResource (line 35) | public function testLoadNonExistingResource()
method testLoadInvalidResource (line 42) | public function testLoadInvalidResource()
FILE: Tests/Loader/IniFileLoaderTest.php
class IniFileLoaderTest (line 19) | class IniFileLoaderTest extends TestCase
method testLoad (line 21) | public function testLoad()
method testLoadDoesNothingIfEmpty (line 32) | public function testLoadDoesNothingIfEmpty()
method testLoadNonExistingResource (line 43) | public function testLoadNonExistingResource()
FILE: Tests/Loader/JsonFileLoaderTest.php
class JsonFileLoaderTest (line 20) | class JsonFileLoaderTest extends TestCase
method testLoad (line 22) | public function testLoad()
method testLoadDoesNothingIfEmpty (line 33) | public function testLoadDoesNothingIfEmpty()
method testLoadNonExistingResource (line 44) | public function testLoadNonExistingResource()
method testParseException (line 51) | public function testParseException()
FILE: Tests/Loader/LocalizedTestCase.php
class LocalizedTestCase (line 16) | abstract class LocalizedTestCase extends TestCase
method setUp (line 18) | protected function setUp(): void
FILE: Tests/Loader/MoFileLoaderTest.php
class MoFileLoaderTest (line 20) | class MoFileLoaderTest extends TestCase
method testLoad (line 22) | public function testLoad()
method testLoadPlurals (line 33) | public function testLoadPlurals()
method testLoadNonExistingResource (line 47) | public function testLoadNonExistingResource()
method testLoadInvalidResource (line 54) | public function testLoadInvalidResource()
method testLoadEmptyTranslation (line 61) | public function testLoadEmptyTranslation()
FILE: Tests/Loader/PhpFileLoaderTest.php
class PhpFileLoaderTest (line 20) | class PhpFileLoaderTest extends TestCase
method testLoad (line 22) | public function testLoad()
method testLoadNonExistingResource (line 33) | public function testLoadNonExistingResource()
method testLoadThrowsAnExceptionIfFileNotLocal (line 40) | public function testLoadThrowsAnExceptionIfFileNotLocal()
FILE: Tests/Loader/PoFileLoaderTest.php
class PoFileLoaderTest (line 19) | class PoFileLoaderTest extends TestCase
method testLoad (line 21) | public function testLoad()
method testLoadPlurals (line 32) | public function testLoadPlurals()
method testLoadDoesNothingIfEmpty (line 46) | public function testLoadDoesNothingIfEmpty()
method testLoadNonExistingResource (line 57) | public function testLoadNonExistingResource()
method testLoadEmptyTranslation (line 64) | public function testLoadEmptyTranslation()
method testEscapedId (line 75) | public function testEscapedId()
method testEscapedIdPlurals (line 86) | public function testEscapedIdPlurals()
method testSkipFuzzyTranslations (line 97) | public function testSkipFuzzyTranslations()
method testMissingPlurals (line 109) | public function testMissingPlurals()
FILE: Tests/Loader/QtFileLoaderTest.php
class QtFileLoaderTest (line 20) | class QtFileLoaderTest extends TestCase
method testLoad (line 22) | public function testLoad()
method testLoadNonExistingResource (line 37) | public function testLoadNonExistingResource()
method testLoadNonLocalResource (line 44) | public function testLoadNonLocalResource()
method testLoadInvalidResource (line 51) | public function testLoadInvalidResource()
method testLoadEmptyResource (line 58) | public function testLoadEmptyResource()
FILE: Tests/Loader/XliffFileLoaderTest.php
class XliffFileLoaderTest (line 21) | class XliffFileLoaderTest extends TestCase
method testLoadFile (line 23) | public function testLoadFile()
method testLoadRawXliff (line 35) | public function testLoadRawXliff()
method testLoadWithInternalErrorsEnabled (line 80) | public function testLoadWithInternalErrorsEnabled()
method testLoadWithExternalEntitiesDisabled (line 98) | public function testLoadWithExternalEntitiesDisabled()
method testLoadWithResname (line 108) | public function testLoadWithResname()
method testIncompleteResource (line 116) | public function testIncompleteResource()
method testEncoding (line 124) | public function testEncoding()
method testTargetAttributesAreStoredCorrectly (line 144) | public function testTargetAttributesAreStoredCorrectly()
method testLoadInvalidResource (line 153) | public function testLoadInvalidResource()
method testLoadResourceDoesNotValidate (line 160) | public function testLoadResourceDoesNotValidate()
method testLoadNonExistingResource (line 167) | public function testLoadNonExistingResource()
method testLoadThrowsAnExceptionIfFileNotLocal (line 174) | public function testLoadThrowsAnExceptionIfFileNotLocal()
method testDocTypeIsNotAllowed (line 181) | public function testDocTypeIsNotAllowed()
method testParseEmptyFile (line 189) | public function testParseEmptyFile()
method testLoadNotes (line 199) | public function testLoadNotes()
method testLoadVersion2 (line 244) | public function testLoadVersion2()
method testLoadVersion21 (line 262) | public function testLoadVersion21()
method testLoadVersion22 (line 280) | public function testLoadVersion22()
method testLoadVersion2WithNoteMeta (line 298) | public function testLoadVersion2WithNoteMeta()
method testLoadVersion2WithMultiSegmentUnit (line 338) | public function testLoadVersion2WithMultiSegmentUnit()
method testLoadWithMultipleFileNodes (line 367) | public function testLoadWithMultipleFileNodes()
method testLoadVersion2WithName (line 395) | public function testLoadVersion2WithName()
method testLoadVersion2WithSegmentAttributes (line 403) | public function testLoadVersion2WithSegmentAttributes()
method testLoadVersion22WithPgsPlural (line 428) | public function testLoadVersion22WithPgsPlural()
method testLoadVersion22WithPgsGender (line 443) | public function testLoadVersion22WithPgsGender()
method testLoadVersion22WithPgsCombined (line 456) | public function testLoadVersion22WithPgsCombined()
FILE: Tests/Loader/YamlFileLoaderTest.php
class YamlFileLoaderTest (line 20) | class YamlFileLoaderTest extends TestCase
method testLoad (line 22) | public function testLoad()
method testLoadNonStringMessages (line 33) | public function testLoadNonStringMessages()
method testLoadDoesNothingIfEmpty (line 42) | public function testLoadDoesNothingIfEmpty()
method testLoadNonExistingResource (line 53) | public function testLoadNonExistingResource()
method testLoadThrowsAnExceptionIfFileNotLocal (line 63) | public function testLoadThrowsAnExceptionIfFileNotLocal()
method testLoadThrowsAnExceptionIfNotAnArray (line 73) | public function testLoadThrowsAnExceptionIfNotAnArray()
FILE: Tests/LocaleFallbackProviderTest.php
class LocaleFallbackProviderTest (line 19) | class LocaleFallbackProviderTest extends TestCase
method testConstructorValidatesLocales (line 21) | public function testConstructorValidatesLocales()
method testComputeFallbackLocalesValidatesLocale (line 28) | public function testComputeFallbackLocalesValidatesLocale()
method testComputeFallbackLocalesShortensSubTags (line 35) | public function testComputeFallbackLocalesShortensSubTags()
method testComputeFallbackLocalesUsesIcuParents (line 42) | #[DataProvider('provideIcuParentLocales')]
method provideIcuParentLocales (line 50) | public static function provideIcuParentLocales(): array
method testComputeFallbackLocalesAppendsUltimateFallbacks (line 59) | public function testComputeFallbackLocalesAppendsUltimateFallbacks()
method testComputeFallbackLocalesExcludesOriginFromUltimateFallbacks (line 68) | public function testComputeFallbackLocalesExcludesOriginFromUltimateFa...
method testComputeFallbackLocalesReturnsUniqueLocales (line 77) | public function testComputeFallbackLocalesReturnsUniqueLocales()
method testComputeFallbackLocalesForRootIcuParentReturnsEmpty (line 87) | public function testComputeFallbackLocalesForRootIcuParentReturnsEmpty()
method testValidateLocalePassesForValidLocales (line 95) | #[DataProvider('provideValidLocales')]
method provideValidLocales (line 103) | public static function provideValidLocales(): array
method testValidateLocaleThrowsForInvalidLocales (line 115) | #[DataProvider('provideInvalidLocales')]
method provideInvalidLocales (line 123) | public static function provideInvalidLocales(): array
FILE: Tests/LocaleSwitcherTest.php
class LocaleSwitcherTest (line 20) | #[RequiresPhpExtension('intl')]
method setUp (line 25) | protected function setUp(): void
method tearDown (line 30) | protected function tearDown(): void
method testCanSwitchLocale (line 35) | public function testCanSwitchLocale()
method testCanSwitchLocaleForCallback (line 53) | public function testCanSwitchLocaleForCallback()
method testWithRequestContext (line 76) | public function testWithRequestContext()
class DummyLocaleAware (line 95) | class DummyLocaleAware implements LocaleAwareInterface
method __construct (line 97) | public function __construct(private string $locale)
method setLocale (line 101) | public function setLocale(string $locale): void
method getLocale (line 106) | public function getLocale(): string
FILE: Tests/LoggingTranslatorTest.php
class LoggingTranslatorTest (line 19) | class LoggingTranslatorTest extends TestCase
method testTransWithNoTranslationIsLogged (line 21) | public function testTransWithNoTranslationIsLogged()
FILE: Tests/MessageCatalogueTest.php
class MessageCatalogueTest (line 19) | class MessageCatalogueTest extends TestCase
method testGetLocale (line 21) | public function testGetLocale()
method testGetDomains (line 28) | public function testGetDomains()
method testAll (line 35) | public function testAll()
method testAllIntlIcu (line 61) | public function testAllIntlIcu()
method testHas (line 85) | public function testHas()
method testGetSet (line 95) | public function testGetSet()
method testAdd (line 105) | public function testAdd()
method testAddIntlIcu (line 121) | public function testAddIntlIcu()
method testReplace (line 131) | public function testReplace()
method testAddCatalogue (line 139) | public function testAddCatalogue()
method testAddFallbackCatalogue (line 163) | public function testAddFallbackCatalogue()
method testAddFallbackCatalogueWithParentCircularReference (line 192) | public function testAddFallbackCatalogueWithParentCircularReference()
method testAddFallbackCatalogueWithFallbackCircularReference (line 204) | public function testAddFallbackCatalogueWithFallbackCircularReference()
method testAddCatalogueWhenLocaleIsNotTheSameAsTheCurrentOne (line 218) | public function testAddCatalogueWhenLocaleIsNotTheSameAsTheCurrentOne()
method testGetAddResource (line 227) | public function testGetAddResource()
method testMetadataDelete (line 241) | public function testMetadataDelete()
method testMetadataSetGetDelete (line 250) | public function testMetadataSetGetDelete()
method testMetadataMerge (line 266) | public function testMetadataMerge()
FILE: Tests/Provider/DsnTest.php
class DsnTest (line 20) | final class DsnTest extends TestCase
method testConstruct (line 22) | #[DataProvider('constructProvider')]
method constructProvider (line 37) | public static function constructProvider(): iterable
method testInvalidDsn (line 142) | #[DataProvider('invalidDsnProvider')]
method invalidDsnProvider (line 151) | public static function invalidDsnProvider(): iterable
method testGetOption (line 169) | #[DataProvider('getOptionProvider')]
method getOptionProvider (line 177) | public static function getOptionProvider(): iterable
method testGetRequiredOption (line 205) | #[DataProvider('getRequiredOptionProvider')]
method getRequiredOptionProvider (line 213) | public static function getRequiredOptionProvider(): iterable
method testGetRequiredOptionThrowsMissingRequiredOptionException (line 228) | #[DataProvider('getRequiredOptionThrowsMissingRequiredOptionExceptionP...
method getRequiredOptionThrowsMissingRequiredOptionExceptionProvider (line 239) | public static function getRequiredOptionThrowsMissingRequiredOptionExc...
FILE: Tests/Provider/FilteringProviderTest.php
class FilteringProviderTest (line 19) | class FilteringProviderTest extends TestCase
method testReadDelegatesWithFilteredLocales (line 21) | public function testReadDelegatesWithFilteredLocales()
FILE: Tests/Provider/NullProviderFactoryTest.php
class NullProviderFactoryTest (line 23) | class NullProviderFactoryTest extends TestCase
method testCreateThrowsUnsupportedSchemeException (line 25) | public function testCreateThrowsUnsupportedSchemeException()
method testCreate (line 32) | public function testCreate()
FILE: Tests/Provider/TranslationProviderCollectionTest.php
class TranslationProviderCollectionTest (line 18) | class TranslationProviderCollectionTest extends TestCase
method testKeys (line 20) | public function testKeys()
method testKeysWithGenerator (line 25) | public function testKeysWithGenerator()
method testToString (line 36) | public function testToString()
method testHas (line 41) | public function testHas()
method testGet (line 46) | public function testGet()
method testGetThrowsException (line 56) | public function testGetThrowsException()
method createProviderCollection (line 64) | private function createProviderCollection(): TranslationProviderCollec...
FILE: Tests/PseudoLocalizationTranslatorTest.php
class PseudoLocalizationTranslatorTest (line 19) | final class PseudoLocalizationTranslatorTest extends TestCase
method testTrans (line 21) | #[DataProvider('provideTrans')]
method provideTrans (line 28) | public static function provideTrans(): array
method testInvalidExpansionFactor (line 50) | #[DataProvider('provideInvalidExpansionFactor')]
method provideInvalidExpansionFactor (line 61) | public static function provideInvalidExpansionFactor(): array
method getIsolatedOptions (line 70) | private static function getIsolatedOptions(array $options): array
FILE: Tests/StaticMessageTest.php
class StaticMessageTest (line 19) | class StaticMessageTest extends TestCase
method testTrans (line 21) | public function testTrans()
FILE: Tests/TranslatableTest.php
class TranslatableTest (line 20) | class TranslatableTest extends TestCase
method testTrans (line 22) | #[DataProvider('getTransTests')]
method testFlattenedTrans (line 32) | #[DataProvider('getFlattenedTransTests')]
method getTransTests (line 42) | public static function getTransTests()
method getFlattenedTransTests (line 58) | public static function getFlattenedTransTests()
FILE: Tests/TranslatorBagTest.php
class TranslatorBagTest (line 18) | class TranslatorBagTest extends TestCase
method testAll (line 20) | public function testAll()
method testDiff (line 47) | public function testDiff()
method testDiffWithIntlDomain (line 69) | public function testDiffWithIntlDomain()
method testIntersect (line 97) | public function testIntersect()
method getAllMessagesFromTranslatorBag (line 119) | private function getAllMessagesFromTranslatorBag(TranslatorBag $transl...
FILE: Tests/TranslatorCacheTest.php
class TranslatorCacheTest (line 23) | class TranslatorCacheTest extends TestCase
method setUp (line 27) | protected function setUp(): void
method tearDown (line 33) | protected function tearDown(): void
method deleteTmpDir (line 38) | protected function deleteTmpDir()
method testThatACacheIsUsed (line 58) | #[DataProvider('runForDebugAndProduction')]
method testCatalogueIsReloadedWhenResourcesAreNoLongerFresh (line 86) | public function testCatalogueIsReloadedWhenResourcesAreNoLongerFresh()
method testDifferentTranslatorsForSameLocaleDoNotOverwriteEachOthersCache (line 127) | #[DataProvider('runForDebugAndProduction')]
method testGeneratedCacheFilesAreOnlyBelongRequestedLocales (line 158) | public function testGeneratedCacheFilesAreOnlyBelongRequestedLocales()
method testDifferentCacheFilesAreUsedForDifferentSetsOfFallbackLocales (line 169) | public function testDifferentCacheFilesAreUsedForDifferentSetsOfFallba...
method testPrimaryAndFallbackCataloguesContainTheSameMessagesRegardlessOfCaching (line 199) | public function testPrimaryAndFallbackCataloguesContainTheSameMessages...
method testRefreshCacheWhenResourcesAreNoLongerFresh (line 250) | public function testRefreshCacheWhenResourcesAreNoLongerFresh()
method testCachedCatalogueIsReDumpedWhenCacheVaryChange (line 273) | public function testCachedCatalogueIsReDumpedWhenCacheVaryChange()
method getCatalogue (line 289) | protected function getCatalogue($locale, $messages, $resources = [])
method runForDebugAndProduction (line 302) | public static function runForDebugAndProduction()
method createFailingLoader (line 307) | private function createFailingLoader(): LoaderInterface
class StaleResource (line 318) | class StaleResource implements SelfCheckingResourceInterface
method isFresh (line 320) | public function isFresh(int $timestamp): bool
method getResource (line 325) | public function getResource()
method __toString (line 329) | public function __toString(): string
FILE: Tests/TranslatorTest.php
class TranslatorTest (line 28) | class TranslatorTest extends TestCase
method setUp (line 32) | protected function setUp(): void
method tearDown (line 38) | protected function tearDown(): void
method testConstructorInvalidLocale (line 43) | #[DataProvider('getInvalidLocalesTests')]
method testConstructorValidLocale (line 50) | #[DataProvider('getValidLocalesTests')]
method testSetGetLocale (line 58) | public function testSetGetLocale()
method testSetInvalidLocale (line 68) | #[DataProvider('getInvalidLocalesTests')]
method testSetValidLocale (line 78) | #[DataProvider('getValidLocalesTests')]
method testGetCatalogue (line 87) | public function testGetCatalogue()
method testGetCatalogueReturnsConsolidatedCatalogue (line 97) | public function testGetCatalogueReturnsConsolidatedCatalogue()
method testSetFallbackLocales (line 121) | public function testSetFallbackLocales()
method testSetFallbackLocalesMultiple (line 135) | public function testSetFallbackLocalesMultiple()
method testSetFallbackInvalidLocales (line 149) | #[DataProvider('getInvalidLocalesTests')]
method testSetFallbackValidLocales (line 157) | #[DataProvider('getValidLocalesTests')]
method testTransWithFallbackLocale (line 166) | public function testTransWithFallbackLocale()
method testAddResourceInvalidLocales (line 177) | #[DataProvider('getInvalidLocalesTests')]
method testAddResourceValidLocales (line 187) | #[DataProvider('getValidLocalesTests')]
method testAddResourceAfterTrans (line 196) | public function testAddResourceAfterTrans()
method testTransWithoutFallbackLocaleFile (line 210) | #[DataProvider('getTransFileTests')]
method testTransWithFallbackLocaleFile (line 225) | #[DataProvider('getTransFileTests')]
method testTransWithIcuFallbackLocale (line 237) | public function testTransWithIcuFallbackLocale()
method testTransWithIcuVariantFallbackLocale (line 249) | public function testTransWithIcuVariantFallbackLocale()
method testTransWithIcuRootFallbackLocale (line 269) | public function testTransWithIcuRootFallbackLocale()
method testTransWithFallbackLocaleBis (line 279) | #[DataProvider('getFallbackLocales')]
method getFallbackLocales (line 289) | public static function getFallbackLocales()
method testTransWithFallbackLocaleTer (line 309) | public function testTransWithFallbackLocaleTer()
method testTransNonExistentWithFallback (line 322) | public function testTransNonExistentWithFallback()
method testWhenAResourceHasNoRegisteredLoader (line 330) | public function testWhenAResourceHasNoRegisteredLoader()
method testNestedFallbackCatalogueWhenUsingMultipleLocales (line 340) | public function testNestedFallbackCatalogueWhenUsingMultipleLocales()
method testFallbackCatalogueResources (line 350) | public function testFallbackCatalogueResources()
method testTrans (line 370) | #[DataProvider('getTransTests')]
method testTransICU (line 380) | #[DataProvider('getTransICUTests')]
method testTransInvalidLocale (line 390) | #[DataProvider('getInvalidLocalesTests')]
method testTransValidLocale (line 402) | #[DataProvider('getValidLocalesTests')]
method testFlattenedTrans (line 413) | #[DataProvider('getFlattenedTransTests')]
method testTransNullId (line 423) | public function testTransNullId()
method getTransFileTests (line 436) | public static function getTransFileTests()
method getTransTests (line 451) | public static function getTransTests(): array
method getTransICUTests (line 464) | public static function getTransICUTests()
method getFlattenedTransTests (line 475) | public static function getFlattenedTransTests()
method getInvalidLocalesTests (line 498) | public static function getInvalidLocalesTests()
method getValidLocalesTests (line 515) | public static function getValidLocalesTests()
method testIntlFormattedDomain (line 531) | #[RequiresPhpExtension('intl')]
method testIntlDomainOverlapseWithIntlResourceBefore (line 544) | public function testIntlDomainOverlapseWithIntlResourceBefore()
method testMissingLoaderForResourceError (line 564) | public function testMissingLoaderForResourceError()
method testTransWithGlobalParameters (line 575) | public function testTransWithGlobalParameters()
method testTransWithGlobalTranslatableParameters (line 589) | public function testTransWithGlobalTranslatableParameters()
method testTransICUWithGlobalParameters (line 607) | #[RequiresPhpExtension('intl')]
class StringClass (line 624) | class StringClass
method __construct (line 626) | public function __construct(
method __toString (line 631) | public function __toString(): string
FILE: Tests/Util/ArrayConverterTest.php
class ArrayConverterTest (line 18) | class ArrayConverterTest extends TestCase
method testDump (line 20) | #[DataProvider('messagesData')]
method messagesData (line 26) | public static function messagesData()
FILE: Tests/Writer/TranslationWriterTest.php
class TranslationWriterTest (line 23) | class TranslationWriterTest extends TestCase
method testWrite (line 25) | public function testWrite()
method testGetFormats (line 37) | public function testGetFormats()
method testFormatIsNotSupported (line 46) | public function testFormatIsNotSupported()
method testUnwritableDirectory (line 55) | public function testUnwritableDirectory()
FILE: TranslatableMessage.php
class TranslatableMessage (line 20) | class TranslatableMessage implements TranslatableInterface
method __construct (line 22) | public function __construct(
method getMessage (line 29) | public function getMessage(): string
method getParameters (line 34) | public function getParameters(): array
method getDomain (line 39) | public function getDomain(): ?string
method trans (line 44) | public function trans(TranslatorInterface $translator, ?string $locale...
FILE: Translator.php
class Translator (line 34) | class Translator implements TranslatorInterface, TranslatorBagInterface,...
method __construct (line 76) | public function __construct(
method setConfigCacheFactory (line 90) | public function setConfigCacheFactory(ConfigCacheFactoryInterface $con...
method addLoader (line 100) | public function addLoader(string $format, LoaderInterface $loader): void
method addResource (line 113) | public function addResource(string $format, mixed $resource, string $l...
method setLocale (line 129) | public function setLocale(string $locale): void
method getLocale (line 135) | public function getLocale(): string
method setFallbackLocales (line 147) | public function setFallbackLocales(array $locales): void
method getFallbackLocales (line 161) | public function getFallbackLocales(): array
method addGlobalParameter (line 166) | public function addGlobalParameter(string $id, string|int|float|Transl...
method getGlobalParameters (line 172) | public function getGlobalParameters(): array
method trans (line 177) | public function trans(?string $id, array $parameters = [], ?string $do...
method getCatalogue (line 226) | public function getCatalogue(?string $locale = null): MessageCatalogue...
method getCatalogues (line 241) | public function getCatalogues(): array
method getLoaders (line 251) | protected function getLoaders(): array
method loadCatalogue (line 256) | protected function loadCatalogue(string $locale): void
method initializeCatalogue (line 265) | protected function initializeCatalogue(string $locale): void
method initializeCacheCatalogue (line 279) | private function initializeCacheCatalogue(string $locale): void
method dumpCatalogue (line 302) | private function dumpCatalogue(string $locale, ConfigCacheInterface $c...
method getFallbackContent (line 326) | private function getFallbackContent(MessageCatalogue $catalogue): string
method getCatalogueCachePath (line 355) | private function getCatalogueCachePath(string $locale): string
method doLoadCatalogue (line 363) | protected function doLoadCatalogue(string $locale): void
method loadFallbackCatalogues (line 381) | private function loadFallbackCatalogues(string $locale): void
method computeFallbackLocales (line 399) | protected function computeFallbackLocales(string $locale): array
method assertValidLocale (line 409) | protected function assertValidLocale(string $locale): void
method getConfigCacheFactory (line 418) | private function getConfigCacheFactory(): ConfigCacheFactoryInterface
method getAllMessages (line 425) | private function getAllMessages(MessageCatalogueInterface $catalogue):...
FILE: TranslatorBag.php
class TranslatorBag (line 17) | final class TranslatorBag implements TranslatorBagInterface
method addCatalogue (line 22) | public function addCatalogue(MessageCatalogue $catalogue): void
method addBag (line 31) | public function addBag(TranslatorBagInterface $bag): void
method getCatalogue (line 38) | public function getCatalogue(?string $locale = null): MessageCatalogue...
method getCatalogues (line 47) | public function getCatalogues(): array
method diff (line 52) | public function diff(TranslatorBagInterface $diffBag): self
method intersect (line 77) | public function intersect(TranslatorBagInterface $intersectBag): self
FILE: TranslatorBagInterface.php
type TranslatorBagInterface (line 19) | interface TranslatorBagInterface
method getCatalogue (line 28) | public function getCatalogue(?string $locale = null): MessageCatalogue...
method getCatalogues (line 35) | public function getCatalogues(): array;
FILE: Util/ArrayConverter.php
class ArrayConverter (line 26) | class ArrayConverter
method expandToTree (line 34) | public static function expandToTree(array $messages): array
method getElementByPath (line 49) | private static function &getElementByPath(array &$tree, array $parts):...
method cancelExpand (line 86) | private static function cancelExpand(array &$tree, string $prefix, arr...
method getKeyParts (line 102) | private static function getKeyParts(string $key): array
FILE: Util/XliffUtils.php
class XliffUtils (line 23) | class XliffUtils
method getVersionNumber (line 32) | public static function getVersionNumber(\DOMDocument $dom): string
method validateSchema (line 59) | public static function validateSchema(\DOMDocument $dom): array
method shouldEnableEntityLoader (line 85) | private static function shouldEnableEntityLoader(): bool
method getErrorsAsString (line 110) | public static function getErrorsAsString(array $xmlErrors): string
method getSchema (line 128) | private static function getSchema(string $xliffVersion): string
method fixXmlLocation (line 149) | private static function fixXmlLocation(string $schemaSource, string $x...
method getXmlErrors (line 174) | private static function getXmlErrors(bool $internalErrors): array
FILE: Writer/TranslationWriter.php
class TranslationWriter (line 24) | class TranslationWriter implements TranslationWriterInterface
method addDumper (line 34) | public function addDumper(string $format, DumperInterface $dumper): void
method getFormats (line 42) | public function getFormats(): array
method write (line 55) | public function write(MessageCatalogue $catalogue, string $format, arr...
FILE: Writer/TranslationWriterInterface.php
type TranslationWriterInterface (line 22) | interface TranslationWriterInterface
method write (line 32) | public function write(MessageCatalogue $catalogue, string $format, arr...
Condensed preview — 259 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (827K chars).
[
{
"path": ".gitattributes",
"chars": 74,
"preview": "/Tests export-ignore\n/phpunit.xml.dist export-ignore\n/.git* export-ignore\n"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 278,
"preview": "Please do not submit any Pull Requests here. They will be closed.\n---\n\nPlease submit your PR here instead:\nhttps://githu"
},
{
"path": ".github/workflows/close-pull-request.yml",
"chars": 544,
"preview": "name: Close Pull Request\n\non:\n pull_request_target:\n types: [opened]\n\njobs:\n run:\n runs-on: ubuntu-latest\n st"
},
{
"path": ".gitignore",
"chars": 34,
"preview": "vendor/\ncomposer.lock\nphpunit.xml\n"
},
{
"path": "CHANGELOG.md",
"chars": 8991,
"preview": "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"
},
{
"path": "Catalogue/AbstractOperation.php",
"chars": 5943,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Catalogue/MergeOperation.php",
"chars": 2633,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Catalogue/OperationInterface.php",
"chars": 1840,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Catalogue/TargetOperation.php",
"chars": 3649,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "CatalogueMetadataAwareInterface.php",
"chars": 1454,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Command/TranslationLintCommand.php",
"chars": 4484,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Command/TranslationPullCommand.php",
"chars": 7744,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Command/TranslationPushCommand.php",
"chars": 7633,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Command/TranslationTrait.php",
"chars": 2389,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Command/XliffLintCommand.php",
"chars": 11075,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "DataCollector/TranslationDataCollector.php",
"chars": 4551,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "DataCollectorTranslator.php",
"chars": 4305,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "DependencyInjection/DataCollectorTranslatorPass.php",
"chars": 1151,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "DependencyInjection/LoggingTranslatorPass.php",
"chars": 2357,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "DependencyInjection/TranslationDumperPass.php",
"chars": 1085,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "DependencyInjection/TranslationExtractorPass.php",
"chars": 1110,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "DependencyInjection/TranslatorPass.php",
"chars": 3769,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "DependencyInjection/TranslatorPathsPass.php",
"chars": 4812,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/CsvFileDumper.php",
"chars": 1374,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/DumperInterface.php",
"chars": 742,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/FileDumper.php",
"chars": 3481,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/IcuResFileDumper.php",
"chars": 2909,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/IniFileDumper.php",
"chars": 950,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/JsonFileDumper.php",
"chars": 837,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/MoFileDumper.php",
"chars": 2243,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/PhpFileDumper.php",
"chars": 792,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/PoFileDumper.php",
"chars": 4137,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/QtFileDumper.php",
"chars": 1884,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/XliffFileDumper.php",
"chars": 9374,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Dumper/YamlFileDumper.php",
"chars": 1485,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/ExceptionInterface.php",
"chars": 469,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/IncompleteDsnException.php",
"chars": 631,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/InvalidArgumentException.php",
"chars": 521,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/InvalidResourceException.php",
"chars": 493,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/LogicException.php",
"chars": 487,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/MissingRequiredOptionException.php",
"chars": 671,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/NotFoundResourceException.php",
"chars": 492,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/ProviderException.php",
"chars": 992,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/ProviderExceptionInterface.php",
"chars": 559,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/RuntimeException.php",
"chars": 497,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Exception/UnsupportedSchemeException.php",
"chars": 2064,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Extractor/AbstractFileExtractor.php",
"chars": 1682,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Extractor/ChainExtractor.php",
"chars": 1252,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Extractor/ExtractorInterface.php",
"chars": 1001,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Extractor/PhpAstExtractor.php",
"chars": 2886,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Extractor/Visitor/AbstractVisitor.php",
"chars": 4526,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Extractor/Visitor/ConstraintVisitor.php",
"chars": 2879,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Extractor/Visitor/TransMethodVisitor.php",
"chars": 1783,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Extractor/Visitor/TranslatableMessageVisitor.php",
"chars": 1619,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Formatter/IntlFormatter.php",
"chars": 2127,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Formatter/IntlFormatterInterface.php",
"chars": 690,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Formatter/MessageFormatter.php",
"chars": 1514,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Formatter/MessageFormatterInterface.php",
"chars": 854,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "IdentityTranslator.php",
"chars": 759,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "LICENSE",
"chars": 1068,
"preview": "Copyright (c) 2004-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "Loader/ArrayLoader.php",
"chars": 1487,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/CsvFileLoader.php",
"chars": 1657,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/FileLoader.php",
"chars": 1728,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/IcuDatFileLoader.php",
"chars": 1831,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/IcuResFileLoader.php",
"chars": 2793,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/IniFileLoader.php",
"chars": 537,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/JsonFileLoader.php",
"chars": 1529,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/LoaderInterface.php",
"chars": 950,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/MoFileLoader.php",
"chars": 4267,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/PhpFileLoader.php",
"chars": 1054,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/PoFileLoader.php",
"chars": 5114,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/QtFileLoader.php",
"chars": 2769,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/XliffFileLoader.php",
"chars": 13999,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Loader/YamlFileLoader.php",
"chars": 1604,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "LocaleFallbackProvider.php",
"chars": 2833,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "LocaleSwitcher.php",
"chars": 2011,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "LoggingTranslator.php",
"chars": 2837,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "MessageCatalogue.php",
"chars": 10028,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "MessageCatalogueInterface.php",
"chars": 3352,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "MetadataAwareInterface.php",
"chars": 1376,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/AbstractProviderFactory.php",
"chars": 1055,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/Dsn.php",
"chars": 2927,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/FilteringProvider.php",
"chars": 1585,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/NullProvider.php",
"chars": 910,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/NullProviderFactory.php",
"chars": 843,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/ProviderFactoryInterface.php",
"chars": 669,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/ProviderInterface.php",
"chars": 927,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/TranslationProviderCollection.php",
"chars": 1401,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Provider/TranslationProviderCollectionFactory.php",
"chars": 1591,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "PseudoLocalizationTranslator.php",
"chars": 11925,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "README.md",
"chars": 1033,
"preview": "Translation Component\n=====================\n\nThe Translation component provides tools to internationalize your applicati"
},
{
"path": "Reader/TranslationReader.php",
"chars": 1734,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Reader/TranslationReaderInterface.php",
"chars": 680,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Resources/bin/translation-status.php",
"chars": 8986,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Resources/data/parents.json",
"chars": 3601,
"preview": "{\n \"az_Cyrl\": \"root\",\n \"bs_Cyrl\": \"root\",\n \"en_150\": \"en_001\",\n \"en_AG\": \"en_001\",\n \"en_AI\": \"en_001\",\n "
},
{
"path": "Resources/data/parents.php",
"chars": 3931,
"preview": "<?php\n\nreturn [\n 'az_Cyrl' => 'root',\n 'bs_Cyrl' => 'root',\n 'en_150' => 'en_001',\n 'en_AG' => 'en_001',\n "
},
{
"path": "Resources/functions.php",
"chars": 563,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Resources/schemas/xliff-core-1.2-transitional.xsd",
"chars": 105363,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\nMay-19-2004:\n- Changed the <choice> for ElemType_header, moving minOccurs=\""
},
{
"path": "Resources/schemas/xliff-core-2.0.xsd",
"chars": 16748,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n XLIFF Version 2.0\n OASIS Standard\n 05 August 2014\n Copyright ("
},
{
"path": "Resources/schemas/xliff-core-2.2.xsd",
"chars": 16793,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n XLIFF Version 2.2\n Based on XLIFF Version 2.0 OASIS Standard with ad"
},
{
"path": "Resources/schemas/xml.xsd",
"chars": 8848,
"preview": "<?xml version='1.0'?>\n<?xml-stylesheet href=\"../2008/09/xsd.xsl\" type=\"text/xsl\"?>\n<xs:schema targetNamespace=\"http://ww"
},
{
"path": "StaticMessage.php",
"chars": 761,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Test/AbstractProviderFactoryTestCase.php",
"chars": 2204,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Test/IncompleteDsnTestTrait.php",
"chars": 1097,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Test/ProviderTestCase.php",
"chars": 2714,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Catalogue/AbstractOperationTestCase.php",
"chars": 2458,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Catalogue/MergeOperationTest.php",
"chars": 4634,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Catalogue/MessageCatalogueTest.php",
"chars": 826,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Catalogue/TargetOperationTest.php",
"chars": 6092,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Command/TranslationLintCommandTest.php",
"chars": 6837,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Command/TranslationProviderTestCase.php",
"chars": 4477,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Command/TranslationPullCommandTest.php",
"chars": 32603,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Command/TranslationPushCommandTest.php",
"chars": 17403,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Command/XliffLintCommandTest.php",
"chars": 9913,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DataCollector/TranslationDataCollectorTest.php",
"chars": 4626,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DataCollectorTranslatorTest.php",
"chars": 3791,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/DataCollectorTranslatorPassTest.php",
"chars": 4324,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/Fixtures/ControllerArguments.php",
"chars": 547,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/Fixtures/ServiceArguments.php",
"chars": 475,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/Fixtures/ServiceMethodCalls.php",
"chars": 479,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/Fixtures/ServiceProperties.php",
"chars": 367,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/Fixtures/ServiceSubscriber.php",
"chars": 740,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/LoggingTranslatorPassTest.php",
"chars": 3181,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/TranslationDumperPassTest.php",
"chars": 1670,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/TranslationExtractorPassTest.php",
"chars": 2215,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/TranslationPathsPassTest.php",
"chars": 4313,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/DependencyInjection/TranslatorPassTest.php",
"chars": 6352,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/CsvFileDumperTest.php",
"chars": 829,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/FileDumperTest.php",
"chars": 2728,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/IcuResFileDumperTest.php",
"chars": 814,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/IniFileDumperTest.php",
"chars": 793,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/JsonFileDumperTest.php",
"chars": 1165,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/MoFileDumperTest.php",
"chars": 789,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/PhpFileDumperTest.php",
"chars": 793,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/PoFileDumperTest.php",
"chars": 1797,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/QtFileDumperTest.php",
"chars": 1395,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/XliffFileDumperTest.php",
"chars": 6719,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Dumper/YamlFileDumperTest.php",
"chars": 1299,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Exception/ProviderExceptionTest.php",
"chars": 1128,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Exception/UnsupportedSchemeExceptionTest.php",
"chars": 3314,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Extractor/PhpAstExtractorTest.php",
"chars": 18184,
"preview": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the ful"
},
{
"path": "Tests/Fixtures/empty-translation.po",
"chars": 23,
"preview": "msgid \"foo\"\nmsgstr \"\"\n\n"
},
{
"path": "Tests/Fixtures/empty.csv",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/empty.ini",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/empty.json",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/empty.mo",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/empty.po",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/empty.xlf",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/empty.yml",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/encoding.xlf",
"chars": 482,
"preview": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file "
},
{
"path": "Tests/Fixtures/escaped-id-plurals.po",
"chars": 230,
"preview": "msgid \"\"\nmsgstr \"\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: en\\n\"\n\nmsg"
},
{
"path": "Tests/Fixtures/escaped-id.po",
"chars": 166,
"preview": "msgid \"\"\nmsgstr \"\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: en\\n\"\n\nmsg"
},
{
"path": "Tests/Fixtures/extractor/resource.format.engine",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/extractor/this.is.a.template.format.engine",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/extractor/translatable-fqn.html.php",
"chars": 2242,
"preview": "This template is used for translation message extraction tests\n<?php new \\Symfony\\Component\\Translation\\TranslatableMess"
},
{
"path": "Tests/Fixtures/extractor/translatable-short.html.php",
"chars": 1426,
"preview": "This template is used for translation message extraction tests\n<?php t('translatable-short single-quoted key'); ?>\n<?php"
},
{
"path": "Tests/Fixtures/extractor/translatable.html.php",
"chars": 1682,
"preview": "This template is used for translation message extraction tests\n<?php new TranslatableMessage('translatable single-quoted"
},
{
"path": "Tests/Fixtures/extractor/translation.html.php",
"chars": 1603,
"preview": "This template is used for translation message extraction tests\n<?php echo $view['translator']->trans('single-quoted key'"
},
{
"path": "Tests/Fixtures/extractor-7.3/translation.html.php",
"chars": 260,
"preview": "This template is used for translation message extraction tests\n<?php echo $view['translator']->trans(<<<EOF\n heredoc\n"
},
{
"path": "Tests/Fixtures/extractor-ast/resource.format.engine",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/extractor-ast/this.is.a.template.format.engine",
"chars": 0,
"preview": ""
},
{
"path": "Tests/Fixtures/extractor-ast/translatable-fqn.html.php",
"chars": 2242,
"preview": "This template is used for translation message extraction tests\n<?php new \\Symfony\\Component\\Translation\\TranslatableMess"
},
{
"path": "Tests/Fixtures/extractor-ast/translatable-short-fqn.html.php",
"chars": 1986,
"preview": "This template is used for translation message extraction tests\n<?php \\Symfony\\Component\\Translation\\t('translatable-shor"
},
{
"path": "Tests/Fixtures/extractor-ast/translatable-short.html.php",
"chars": 1426,
"preview": "This template is used for translation message extraction tests\n<?php t('translatable-short single-quoted key'); ?>\n<?php"
},
{
"path": "Tests/Fixtures/extractor-ast/translatable.html.php",
"chars": 1682,
"preview": "This template is used for translation message extraction tests\n<?php new TranslatableMessage('translatable single-quoted"
},
{
"path": "Tests/Fixtures/extractor-ast/translation.html.php",
"chars": 3247,
"preview": "This template is used for translation message extraction tests\n<?php echo $view['translator']->trans('single-quoted key'"
},
{
"path": "Tests/Fixtures/extractor-ast/validator-constraints.php",
"chars": 1635,
"preview": "This template is used for translation message extraction tests\n<?php\n\nuse Symfony\\Component\\Validator\\Constraints as Ass"
},
{
"path": "Tests/Fixtures/fuzzy-translations.po",
"chars": 124,
"preview": "#, php-format\nmsgid \"foo1\"\nmsgstr \"bar1\"\n\n#, fuzzy, php-format\nmsgid \"foo2\"\nmsgstr \"fuzzy bar2\"\n\nmsgid \"foo3\"\nmsgstr \"ba"
},
{
"path": "Tests/Fixtures/invalid-xml-resources.xlf",
"chars": 749,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file sou"
},
{
"path": "Tests/Fixtures/malformed.json",
"chars": 19,
"preview": "{\n \"foo\" \"bar\"\n}"
},
{
"path": "Tests/Fixtures/messages.yml",
"chars": 39,
"preview": "foo:\n bar1: value1\n bar2: value2\n"
},
{
"path": "Tests/Fixtures/messages_linear.yml",
"chars": 34,
"preview": "foo.bar1: value1\nfoo.bar2: value2\n"
},
{
"path": "Tests/Fixtures/missing-plurals.po",
"chars": 65,
"preview": "msgid \"foo\"\nmsgid_plural \"foos\"\nmsgstr[3] \"bars\"\nmsgstr[1] \"bar\"\n"
},
{
"path": "Tests/Fixtures/non-string.yml",
"chars": 38,
"preview": "root:\n foo1:\n foo2: ''\n bar: 'bar'\n"
},
{
"path": "Tests/Fixtures/non-valid.xlf",
"chars": 340,
"preview": "<?xml version=\"1.0\"?>\n<xliff version=\"1.2\" xmlns=\"urn:oasis:names:tc:xliff:document:1.2\">\n <file source-language=\"en\""
},
{
"path": "Tests/Fixtures/non-valid.yml",
"chars": 4,
"preview": "foo\n"
},
{
"path": "Tests/Fixtures/plurals.po",
"chars": 266,
"preview": "msgid \"\"\nmsgstr \"\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Language: en\\n\"\n\nmsg"
},
{
"path": "Tests/Fixtures/resname.xlf",
"chars": 660,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file sourc"
},
{
"path": "Tests/Fixtures/resourcebundle/dat/en.txt",
"chars": 37,
"preview": "en{\n symfony{\"Symfony is great\"}\n}"
},
{
"path": "Tests/Fixtures/resourcebundle/dat/fr.txt",
"chars": 39,
"preview": "fr{\n symfony{\"Symfony est génial\"}\n}"
},
{
"path": "Tests/Fixtures/resourcebundle/dat/packagelist.txt",
"chars": 14,
"preview": "en.res\nfr.res\n"
},
{
"path": "Tests/Fixtures/resources-2.0+intl-icu.xlf",
"chars": 325,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR"
},
{
"path": "Tests/Fixtures/resources-2.0-clean.xlf",
"chars": 868,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR"
},
{
"path": "Tests/Fixtures/resources-2.0-empty-notes.xlf",
"chars": 607,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR"
},
{
"path": "Tests/Fixtures/resources-2.0-multi-segment-unit.xlf",
"chars": 562,
"preview": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en-US\" trgLang=\"en-US\">\n <file id=\"f1\">\n "
},
{
"path": "Tests/Fixtures/resources-2.0-name.xlf",
"chars": 829,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en-US"
},
{
"path": "Tests/Fixtures/resources-2.0-segment-attributes.xlf",
"chars": 518,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR"
},
{
"path": "Tests/Fixtures/resources-2.0.xlf",
"chars": 839,
"preview": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"en-US\" trgLang=\"ja-JP\">\n <file id=\"f1\" or"
},
{
"path": "Tests/Fixtures/resources-2.1.xlf",
"chars": 839,
"preview": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.1\" srcLang=\"en-US\" trgLang=\"ja-JP\">\n <file id=\"f1\" or"
},
{
"path": "Tests/Fixtures/resources-2.2-pgs-combined.xlf",
"chars": 2950,
"preview": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" xmlns:pgs=\"urn:oasis:names:tc:xliff:pgs:1.0\"\n version=\"2.2\" s"
},
{
"path": "Tests/Fixtures/resources-2.2-pgs-gender.xlf",
"chars": 871,
"preview": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" xmlns:pgs=\"urn:oasis:names:tc:xliff:pgs:1.0\"\n version=\"2.2\" s"
},
{
"path": "Tests/Fixtures/resources-2.2-pgs-plural.xlf",
"chars": 903,
"preview": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" xmlns:pgs=\"urn:oasis:names:tc:xliff:pgs:1.0\"\n version=\"2.2\" s"
},
{
"path": "Tests/Fixtures/resources-2.2.xlf",
"chars": 839,
"preview": "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.2\" srcLang=\"en-US\" trgLang=\"ja-JP\">\n <file id=\"f1\" or"
},
{
"path": "Tests/Fixtures/resources-clean.xlf",
"chars": 844,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file sourc"
},
{
"path": "Tests/Fixtures/resources-clean.xliff",
"chars": 844,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file sourc"
},
{
"path": "Tests/Fixtures/resources-multi-files.xlf",
"chars": 743,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file sourc"
},
{
"path": "Tests/Fixtures/resources-notes-meta.xlf",
"chars": 776,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\" srcLang=\"fr-FR"
},
{
"path": "Tests/Fixtures/resources-target-attributes.xlf",
"chars": 476,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file sourc"
},
{
"path": "Tests/Fixtures/resources-tool-info.xlf",
"chars": 480,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file sourc"
},
{
"path": "Tests/Fixtures/resources.csv",
"chars": 124,
"preview": "\"foo\"; \"bar\"\n#\"bar\"; \"foo\"\n\n# all incorrect examples:\n\"incorrect\"; \"number\"; \"columns\"; \"will\"; \"be\"; \"ignored\"\n\"incorre"
}
]
// ... and 59 more files (download for full content)
About this extraction
This page contains the full source code of the symfony/translation GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 259 files (759.8 KB), approximately 197.2k tokens, and a symbol index with 953 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.