[Web] Update composer libs
- Removing symfony/deprecation-contracts (v2.4.0) - Upgrading ddeboer/imap (1.12.1 => 1.13.1) - Upgrading directorytree/ldaprecord (v2.6.3 => v2.10.1) - Upgrading illuminate/contracts (v8.53.1 => v9.3.0) - Upgrading nesbot/carbon (2.51.1 => 2.57.0) - Upgrading phpmailer/phpmailer (v6.5.0 => v6.6.0) - Upgrading psr/container (1.1.1 => 2.0.2) - Upgrading psr/log (1.1.4 => 3.0.0) - Upgrading psr/simple-cache (1.0.1 => 2.0.0) - Upgrading robthree/twofactorauth (1.8.0 => 1.8.1) - Upgrading symfony/polyfill-ctype (v1.23.0 => v1.24.0) - Upgrading symfony/polyfill-mbstring (v1.23.1 => v1.24.0) - Upgrading symfony/polyfill-php80 (v1.23.1 => v1.24.0) - Upgrading symfony/translation (v5.3.4 => v6.0.5) - Upgrading symfony/translation-contracts (v2.4.0 => v3.0.0) - Upgrading symfony/var-dumper (v5.3.6 => v6.0.5) - Upgrading tightenco/collect (v8.34.0 => v8.83.2) - Upgrading twig/twig (v3.3.2 => v3.3.8)
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
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
|
||||
---
|
||||
|
||||
|
@@ -80,10 +80,21 @@ abstract class AbstractOperation implements OperationInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDomains()
|
||||
public function getDomains(): array
|
||||
{
|
||||
if (null === $this->domains) {
|
||||
$this->domains = array_values(array_unique(array_merge($this->source->getDomains(), $this->target->getDomains())));
|
||||
$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;
|
||||
@@ -92,7 +103,7 @@ abstract class AbstractOperation implements OperationInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessages(string $domain)
|
||||
public function getMessages(string $domain): array
|
||||
{
|
||||
if (!\in_array($domain, $this->getDomains())) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
|
||||
@@ -108,7 +119,7 @@ abstract class AbstractOperation implements OperationInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewMessages(string $domain)
|
||||
public function getNewMessages(string $domain): array
|
||||
{
|
||||
if (!\in_array($domain, $this->getDomains())) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
|
||||
@@ -124,7 +135,7 @@ abstract class AbstractOperation implements OperationInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getObsoleteMessages(string $domain)
|
||||
public function getObsoleteMessages(string $domain): array
|
||||
{
|
||||
if (!\in_array($domain, $this->getDomains())) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
|
||||
@@ -140,7 +151,7 @@ abstract class AbstractOperation implements OperationInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResult()
|
||||
public function getResult(): MessageCatalogueInterface
|
||||
{
|
||||
foreach ($this->getDomains() as $domain) {
|
||||
if (!isset($this->messages[$domain])) {
|
||||
|
@@ -36,36 +36,26 @@ interface OperationInterface
|
||||
{
|
||||
/**
|
||||
* Returns domains affected by operation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDomains();
|
||||
public function getDomains(): array;
|
||||
|
||||
/**
|
||||
* Returns all valid messages ('all') after operation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMessages(string $domain);
|
||||
public function getMessages(string $domain): array;
|
||||
|
||||
/**
|
||||
* Returns new messages ('new') after operation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getNewMessages(string $domain);
|
||||
public function getNewMessages(string $domain): array;
|
||||
|
||||
/**
|
||||
* Returns obsolete messages ('obsolete') after operation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getObsoleteMessages(string $domain);
|
||||
public function getObsoleteMessages(string $domain): array;
|
||||
|
||||
/**
|
||||
* Returns resulting catalogue ('result').
|
||||
*
|
||||
* @return MessageCatalogueInterface
|
||||
*/
|
||||
public function getResult();
|
||||
public function getResult(): MessageCatalogueInterface;
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ class TargetOperation extends AbstractOperation
|
||||
foreach ($this->source->all($domain) as $id => $message) {
|
||||
if ($this->target->has($id, $domain)) {
|
||||
$this->messages[$domain]['all'][$id] = $message;
|
||||
$d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;
|
||||
$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);
|
||||
|
@@ -11,7 +11,10 @@
|
||||
|
||||
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;
|
||||
@@ -25,22 +28,18 @@ use Symfony\Component\Translation\Writer\TranslationWriterInterface;
|
||||
|
||||
/**
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
#[AsCommand(name: 'translation:pull', description: 'Pull translations from a given provider.')]
|
||||
final class TranslationPullCommand extends Command
|
||||
{
|
||||
use TranslationTrait;
|
||||
|
||||
protected static $defaultName = 'translation:pull';
|
||||
protected static $defaultDescription = 'Pull translations from a given provider.';
|
||||
|
||||
private $providerCollection;
|
||||
private $writer;
|
||||
private $reader;
|
||||
private $defaultLocale;
|
||||
private $transPaths;
|
||||
private $enabledLocales;
|
||||
private string $defaultLocale;
|
||||
private array $transPaths;
|
||||
private array $enabledLocales;
|
||||
|
||||
public function __construct(TranslationProviderCollection $providerCollection, TranslationWriterInterface $writer, TranslationReaderInterface $reader, string $defaultLocale, array $transPaths = [], array $enabledLocales = [])
|
||||
{
|
||||
@@ -54,6 +53,36 @@ final class TranslationPullCommand extends Command
|
||||
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 ($provider && method_exists($provider, 'getDomains')) {
|
||||
$domains = $provider->getDomains();
|
||||
$suggestions->suggestValues($domains);
|
||||
}
|
||||
|
||||
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']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -81,7 +110,7 @@ You can overwrite existing translations (and remove the missing ones on local si
|
||||
|
||||
Full example:
|
||||
|
||||
<info>php %command.full_name% provider --force --domains=messages,validators --locales=en</>
|
||||
<info>php %command.full_name% provider --force --domains=messages --domains=validators --locales=en</>
|
||||
|
||||
This command pulls all translations associated with the <comment>messages</> and <comment>validators</> domains for the <comment>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.
|
||||
@@ -119,6 +148,7 @@ EOF
|
||||
$writeOptions = [
|
||||
'path' => end($this->transPaths),
|
||||
'xliff_version' => $xliffVersion,
|
||||
'default_locale' => $this->defaultLocale,
|
||||
];
|
||||
|
||||
if (!$domains) {
|
||||
|
@@ -11,7 +11,10 @@
|
||||
|
||||
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;
|
||||
@@ -24,20 +27,16 @@ use Symfony\Component\Translation\TranslatorBag;
|
||||
|
||||
/**
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
#[AsCommand(name: 'translation:push', description: 'Push translations to a given provider.')]
|
||||
final class TranslationPushCommand extends Command
|
||||
{
|
||||
use TranslationTrait;
|
||||
|
||||
protected static $defaultName = 'translation:push';
|
||||
protected static $defaultDescription = 'Push translations to a given provider.';
|
||||
|
||||
private $providers;
|
||||
private $reader;
|
||||
private $transPaths;
|
||||
private $enabledLocales;
|
||||
private array $transPaths;
|
||||
private array $enabledLocales;
|
||||
|
||||
public function __construct(TranslationProviderCollection $providers, TranslationReaderInterface $reader, array $transPaths = [], array $enabledLocales = [])
|
||||
{
|
||||
@@ -49,6 +48,30 @@ final class TranslationPushCommand extends Command
|
||||
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 ($provider && method_exists($provider, 'getDomains')) {
|
||||
$domains = $provider->getDomains();
|
||||
$suggestions->suggestValues($domains);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('locales')) {
|
||||
$suggestions->suggestValues($this->enabledLocales);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -79,7 +102,7 @@ You can delete provider translations which are not present locally by using the
|
||||
|
||||
Full example:
|
||||
|
||||
<info>php %command.full_name% provider --force --delete-missing --domains=messages,validators --locales=en</>
|
||||
<info>php %command.full_name% provider --force --delete-missing --domains=messages --domains=validators --locales=en</>
|
||||
|
||||
This command pushes all translations associated with the <comment>messages</> and <comment>validators</> domains for the <comment>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.
|
||||
|
@@ -32,8 +32,7 @@ trait TranslationTrait
|
||||
|
||||
if ($domains) {
|
||||
foreach ($domains as $domain) {
|
||||
$catalogue = $this->filterCatalogue($catalogue, $domain);
|
||||
$bag->addCatalogue($catalogue);
|
||||
$bag->addCatalogue($this->filterCatalogue($catalogue, $domain));
|
||||
}
|
||||
} else {
|
||||
$bag->addCatalogue($catalogue);
|
||||
|
@@ -11,7 +11,11 @@
|
||||
|
||||
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;
|
||||
@@ -28,23 +32,21 @@ use Symfony\Component\Translation\Util\XliffUtils;
|
||||
* @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
|
||||
{
|
||||
protected static $defaultName = 'lint:xliff';
|
||||
protected static $defaultDescription = 'Lint an XLIFF file and outputs encountered errors';
|
||||
|
||||
private $format;
|
||||
private $displayCorrectFiles;
|
||||
private $directoryIteratorProvider;
|
||||
private $isReadableProvider;
|
||||
private $requireStrictFileNames;
|
||||
private string $format;
|
||||
private bool $displayCorrectFiles;
|
||||
private ?\Closure $directoryIteratorProvider;
|
||||
private ?\Closure $isReadableProvider;
|
||||
private bool $requireStrictFileNames;
|
||||
|
||||
public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null, bool $requireStrictFileNames = true)
|
||||
{
|
||||
parent::__construct($name);
|
||||
|
||||
$this->directoryIteratorProvider = $directoryIteratorProvider;
|
||||
$this->isReadableProvider = $isReadableProvider;
|
||||
$this->directoryIteratorProvider = null === $directoryIteratorProvider || $directoryIteratorProvider instanceof \Closure ? $directoryIteratorProvider : \Closure::fromCallable($directoryIteratorProvider);
|
||||
$this->isReadableProvider = null === $isReadableProvider || $isReadableProvider instanceof \Closure ? $isReadableProvider : \Closure::fromCallable($isReadableProvider);
|
||||
$this->requireStrictFileNames = $requireStrictFileNames;
|
||||
}
|
||||
|
||||
@@ -54,9 +56,8 @@ class XliffLintCommand extends Command
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription(self::$defaultDescription)
|
||||
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
|
||||
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
|
||||
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format')
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command lints an XLIFF file and outputs to STDOUT
|
||||
the first encountered syntax error.
|
||||
@@ -79,11 +80,11 @@ EOF
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$filenames = (array) $input->getArgument('filename');
|
||||
$this->format = $input->getOption('format');
|
||||
$this->format = $input->getOption('format') ?? (GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt');
|
||||
$this->displayCorrectFiles = $output->isVerbose();
|
||||
|
||||
if (['-'] === $filenames) {
|
||||
@@ -160,15 +161,18 @@ EOF
|
||||
return $this->displayTxt($io, $files);
|
||||
case 'json':
|
||||
return $this->displayJson($io, $files);
|
||||
case 'github':
|
||||
return $this->displayTxt($io, $files, true);
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
|
||||
}
|
||||
}
|
||||
|
||||
private function displayTxt(SymfonyStyle $io, array $filesInfo)
|
||||
private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false)
|
||||
{
|
||||
$countFiles = \count($filesInfo);
|
||||
$erroredFiles = 0;
|
||||
$githubReporter = $errorAsGithubAnnotations ? new GithubActionReporter($io) : null;
|
||||
|
||||
foreach ($filesInfo as $info) {
|
||||
if ($info['valid'] && $this->displayCorrectFiles) {
|
||||
@@ -176,9 +180,15 @@ EOF
|
||||
} elseif (!$info['valid']) {
|
||||
++$erroredFiles;
|
||||
$io->text('<error> ERROR </error>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
|
||||
$io->listing(array_map(function ($error) {
|
||||
$io->listing(array_map(function ($error) use ($info, $githubReporter) {
|
||||
// general document errors have a '-1' line number
|
||||
return -1 === $error['line'] ? $error['message'] : sprintf('Line %d, Column %d: %s', $error['line'], $error['column'], $error['message']);
|
||||
$line = -1 === $error['line'] ? null : $error['line'];
|
||||
|
||||
if ($githubReporter) {
|
||||
$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']));
|
||||
}
|
||||
}
|
||||
@@ -264,4 +274,11 @@ EOF
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues(['txt', 'json', 'github']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -62,34 +62,22 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|Data
|
||||
*/
|
||||
public function getMessages()
|
||||
public function getMessages(): array|Data
|
||||
{
|
||||
return $this->data['messages'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCountMissings()
|
||||
public function getCountMissings(): int
|
||||
{
|
||||
return $this->data[DataCollectorTranslator::MESSAGE_MISSING] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCountFallbacks()
|
||||
public function getCountFallbacks(): int
|
||||
{
|
||||
return $this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCountDefines()
|
||||
public function getCountDefines(): int
|
||||
{
|
||||
return $this->data[DataCollectorTranslator::MESSAGE_DEFINED] ?? 0;
|
||||
}
|
||||
@@ -110,7 +98,7 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
public function getName(): string
|
||||
{
|
||||
return 'translation';
|
||||
}
|
||||
|
@@ -25,15 +25,11 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
public const MESSAGE_MISSING = 1;
|
||||
public const MESSAGE_EQUALS_FALLBACK = 2;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface|TranslatorBagInterface
|
||||
*/
|
||||
private $translator;
|
||||
|
||||
private $messages = [];
|
||||
private array $messages = [];
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
|
||||
* @param TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
{
|
||||
@@ -47,7 +43,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null)
|
||||
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);
|
||||
@@ -66,7 +62,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocale()
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->translator->getLocale();
|
||||
}
|
||||
@@ -74,7 +70,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue(string $locale = null)
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface
|
||||
{
|
||||
return $this->translator->getCatalogue($locale);
|
||||
}
|
||||
@@ -92,7 +88,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function warmUp(string $cacheDir)
|
||||
public function warmUp(string $cacheDir): array
|
||||
{
|
||||
if ($this->translator instanceof WarmableInterface) {
|
||||
return (array) $this->translator->warmUp($cacheDir);
|
||||
@@ -103,10 +99,8 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
|
||||
/**
|
||||
* Gets the fallback locales.
|
||||
*
|
||||
* @return array The fallback locales
|
||||
*/
|
||||
public function getFallbackLocales()
|
||||
public function getFallbackLocales(): array
|
||||
{
|
||||
if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) {
|
||||
return $this->translator->getFallbackLocales();
|
||||
@@ -123,10 +117,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
return $this->translator->{$method}(...$args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getCollectedMessages()
|
||||
public function getCollectedMessages(): array
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
|
@@ -20,28 +20,15 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
*/
|
||||
class TranslationDumperPass implements CompilerPassInterface
|
||||
{
|
||||
private $writerServiceId;
|
||||
private $dumperTag;
|
||||
|
||||
public function __construct(string $writerServiceId = 'translation.writer', string $dumperTag = 'translation.dumper')
|
||||
{
|
||||
if (1 < \func_num_args()) {
|
||||
trigger_deprecation('symfony/translation', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
|
||||
}
|
||||
|
||||
$this->writerServiceId = $writerServiceId;
|
||||
$this->dumperTag = $dumperTag;
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition($this->writerServiceId)) {
|
||||
if (!$container->hasDefinition('translation.writer')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$definition = $container->getDefinition($this->writerServiceId);
|
||||
$definition = $container->getDefinition('translation.writer');
|
||||
|
||||
foreach ($container->findTaggedServiceIds($this->dumperTag, true) as $id => $attributes) {
|
||||
foreach ($container->findTaggedServiceIds('translation.dumper', true) as $id => $attributes) {
|
||||
$definition->addMethodCall('addDumper', [$attributes[0]['alias'], new Reference($id)]);
|
||||
}
|
||||
}
|
||||
|
@@ -21,28 +21,15 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
*/
|
||||
class TranslationExtractorPass implements CompilerPassInterface
|
||||
{
|
||||
private $extractorServiceId;
|
||||
private $extractorTag;
|
||||
|
||||
public function __construct(string $extractorServiceId = 'translation.extractor', string $extractorTag = 'translation.extractor')
|
||||
{
|
||||
if (0 < \func_num_args()) {
|
||||
trigger_deprecation('symfony/translation', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
|
||||
}
|
||||
|
||||
$this->extractorServiceId = $extractorServiceId;
|
||||
$this->extractorTag = $extractorTag;
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition($this->extractorServiceId)) {
|
||||
if (!$container->hasDefinition('translation.extractor')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$definition = $container->getDefinition($this->extractorServiceId);
|
||||
$definition = $container->getDefinition('translation.extractor');
|
||||
|
||||
foreach ($container->findTaggedServiceIds($this->extractorTag, true) as $id => $attributes) {
|
||||
foreach ($container->findTaggedServiceIds('translation.extractor', true) as $id => $attributes) {
|
||||
if (!isset($attributes[0]['alias'])) {
|
||||
throw new RuntimeException(sprintf('The alias for the tag "translation.extractor" of service "%s" must be set.', $id));
|
||||
}
|
||||
|
@@ -18,34 +18,15 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class TranslatorPass implements CompilerPassInterface
|
||||
{
|
||||
private $translatorServiceId;
|
||||
private $readerServiceId;
|
||||
private $loaderTag;
|
||||
private $debugCommandServiceId;
|
||||
private $updateCommandServiceId;
|
||||
|
||||
public function __construct(string $translatorServiceId = 'translator.default', string $readerServiceId = 'translation.reader', string $loaderTag = 'translation.loader', string $debugCommandServiceId = 'console.command.translation_debug', string $updateCommandServiceId = 'console.command.translation_update')
|
||||
{
|
||||
if (0 < \func_num_args()) {
|
||||
trigger_deprecation('symfony/translation', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
|
||||
}
|
||||
|
||||
$this->translatorServiceId = $translatorServiceId;
|
||||
$this->readerServiceId = $readerServiceId;
|
||||
$this->loaderTag = $loaderTag;
|
||||
$this->debugCommandServiceId = $debugCommandServiceId;
|
||||
$this->updateCommandServiceId = $updateCommandServiceId;
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition($this->translatorServiceId)) {
|
||||
if (!$container->hasDefinition('translator.default')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loaders = [];
|
||||
$loaderRefs = [];
|
||||
foreach ($container->findTaggedServiceIds($this->loaderTag, true) as $id => $attributes) {
|
||||
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'])) {
|
||||
@@ -53,8 +34,8 @@ class TranslatorPass implements CompilerPassInterface
|
||||
}
|
||||
}
|
||||
|
||||
if ($container->hasDefinition($this->readerServiceId)) {
|
||||
$definition = $container->getDefinition($this->readerServiceId);
|
||||
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]]);
|
||||
@@ -63,7 +44,7 @@ class TranslatorPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
$container
|
||||
->findDefinition($this->translatorServiceId)
|
||||
->findDefinition('translator.default')
|
||||
->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs))
|
||||
->replaceArgument(3, $loaders)
|
||||
;
|
||||
@@ -73,16 +54,16 @@ class TranslatorPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
$paths = array_keys($container->getDefinition('twig.template_iterator')->getArgument(1));
|
||||
if ($container->hasDefinition($this->debugCommandServiceId)) {
|
||||
$definition = $container->getDefinition($this->debugCommandServiceId);
|
||||
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($this->updateCommandServiceId)) {
|
||||
$definition = $container->getDefinition($this->updateCommandServiceId);
|
||||
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) {
|
||||
|
@@ -22,30 +22,26 @@ use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
*/
|
||||
class TranslatorPathsPass extends AbstractRecursivePass
|
||||
{
|
||||
private $translatorServiceId;
|
||||
private $debugCommandServiceId;
|
||||
private $updateCommandServiceId;
|
||||
private $resolverServiceId;
|
||||
private $level = 0;
|
||||
private $paths = [];
|
||||
private $definitions = [];
|
||||
private $controllers = [];
|
||||
private int $level = 0;
|
||||
|
||||
public function __construct(string $translatorServiceId = 'translator', string $debugCommandServiceId = 'console.command.translation_debug', string $updateCommandServiceId = 'console.command.translation_update', string $resolverServiceId = 'argument_resolver.service')
|
||||
{
|
||||
if (0 < \func_num_args()) {
|
||||
trigger_deprecation('symfony/translation', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
|
||||
}
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private array $paths = [];
|
||||
|
||||
$this->translatorServiceId = $translatorServiceId;
|
||||
$this->debugCommandServiceId = $debugCommandServiceId;
|
||||
$this->updateCommandServiceId = $updateCommandServiceId;
|
||||
$this->resolverServiceId = $resolverServiceId;
|
||||
}
|
||||
/**
|
||||
* @var array<int, Definition>
|
||||
*/
|
||||
private array $definitions = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<string, bool>>
|
||||
*/
|
||||
private array $controllers = [];
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition($this->translatorServiceId)) {
|
||||
if (!$container->hasDefinition('translator')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -70,12 +66,12 @@ class TranslatorPathsPass extends AbstractRecursivePass
|
||||
}
|
||||
}
|
||||
if ($paths) {
|
||||
if ($container->hasDefinition($this->debugCommandServiceId)) {
|
||||
$definition = $container->getDefinition($this->debugCommandServiceId);
|
||||
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($this->updateCommandServiceId)) {
|
||||
$definition = $container->getDefinition($this->updateCommandServiceId);
|
||||
if ($container->hasDefinition('console.command.translation_extract')) {
|
||||
$definition = $container->getDefinition('console.command.translation_extract');
|
||||
$definition->replaceArgument(7, array_merge($definition->getArgument(7), $paths));
|
||||
}
|
||||
}
|
||||
@@ -86,10 +82,10 @@ class TranslatorPathsPass extends AbstractRecursivePass
|
||||
}
|
||||
}
|
||||
|
||||
protected function processValue($value, bool $isRoot = false)
|
||||
protected function processValue(mixed $value, bool $isRoot = false): mixed
|
||||
{
|
||||
if ($value instanceof Reference) {
|
||||
if ((string) $value === $this->translatorServiceId) {
|
||||
if ('translator' === (string) $value) {
|
||||
for ($i = $this->level - 1; $i >= 0; --$i) {
|
||||
$class = $this->definitions[$i]->getClass();
|
||||
|
||||
@@ -124,8 +120,8 @@ class TranslatorPathsPass extends AbstractRecursivePass
|
||||
|
||||
private function findControllerArguments(ContainerBuilder $container): array
|
||||
{
|
||||
if ($container->hasDefinition($this->resolverServiceId)) {
|
||||
$argument = $container->getDefinition($this->resolverServiceId)->getArgument(0);
|
||||
if ($container->hasDefinition('argument_resolver.service')) {
|
||||
$argument = $container->getDefinition('argument_resolver.service')->getArgument(0);
|
||||
if ($argument instanceof Reference) {
|
||||
$argument = $container->getDefinition($argument);
|
||||
}
|
||||
@@ -133,8 +129,8 @@ class TranslatorPathsPass extends AbstractRecursivePass
|
||||
return $argument->getArgument(0);
|
||||
}
|
||||
|
||||
if ($container->hasDefinition('debug.'.$this->resolverServiceId)) {
|
||||
$argument = $container->getDefinition('debug.'.$this->resolverServiceId)->getArgument(0);
|
||||
if ($container->hasDefinition('debug.'.'argument_resolver.service')) {
|
||||
$argument = $container->getDefinition('debug.'.'argument_resolver.service')->getArgument(0);
|
||||
if ($argument instanceof Reference) {
|
||||
$argument = $container->getDefinition($argument);
|
||||
}
|
||||
|
@@ -20,13 +20,13 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class CsvFileDumper extends FileDumper
|
||||
{
|
||||
private $delimiter = ';';
|
||||
private $enclosure = '"';
|
||||
private string $delimiter = ';';
|
||||
private string $enclosure = '"';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$handle = fopen('php://memory', 'r+');
|
||||
|
||||
@@ -53,7 +53,7 @@ class CsvFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'csv';
|
||||
}
|
||||
|
@@ -86,17 +86,13 @@ abstract class FileDumper implements DumperInterface
|
||||
|
||||
/**
|
||||
* Transforms a domain of a message catalogue to its string representation.
|
||||
*
|
||||
* @return string representation
|
||||
*/
|
||||
abstract public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []);
|
||||
abstract public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string;
|
||||
|
||||
/**
|
||||
* Gets the file extension of the dumper.
|
||||
*
|
||||
* @return string file extension
|
||||
*/
|
||||
abstract protected function getExtension();
|
||||
abstract protected function getExtension(): string;
|
||||
|
||||
/**
|
||||
* Gets the relative file path using the template.
|
||||
|
@@ -28,7 +28,7 @@ class IcuResFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$data = $indexes = $resources = '';
|
||||
|
||||
@@ -97,7 +97,7 @@ class IcuResFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'res';
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ class IniFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$output = '';
|
||||
|
||||
@@ -38,7 +38,7 @@ class IniFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'ini';
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ class JsonFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$flags = $options['json_encoding'] ?? \JSON_PRETTY_PRINT;
|
||||
|
||||
@@ -33,7 +33,7 @@ class JsonFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'json';
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ class MoFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$sources = $targets = $sourceOffsets = $targetOffsets = '';
|
||||
$offsets = [];
|
||||
@@ -70,12 +70,12 @@ class MoFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'mo';
|
||||
}
|
||||
|
||||
private function writeLong($str): string
|
||||
private function writeLong(mixed $str): string
|
||||
{
|
||||
return pack('V*', $str);
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ class PhpFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
return "<?php\n\nreturn ".var_export($messages->all($domain), true).";\n";
|
||||
}
|
||||
@@ -31,7 +31,7 @@ class PhpFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'php';
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ class PoFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$output = 'msgid ""'."\n";
|
||||
$output .= 'msgstr ""'."\n";
|
||||
@@ -114,7 +114,7 @@ EOF;
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'po';
|
||||
}
|
||||
@@ -124,7 +124,7 @@ EOF;
|
||||
return addcslashes($str, "\0..\37\42\134");
|
||||
}
|
||||
|
||||
private function formatComments($comments, string $prefix = ''): ?string
|
||||
private function formatComments(string|array $comments, string $prefix = ''): ?string
|
||||
{
|
||||
$output = null;
|
||||
|
||||
|
@@ -23,7 +23,7 @@ class QtFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||
$dom->formatOutput = true;
|
||||
@@ -54,7 +54,7 @@ class QtFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'ts';
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ class XliffFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$xliffVersion = '1.2';
|
||||
if (\array_key_exists('xliff_version', $options)) {
|
||||
@@ -50,7 +50,7 @@ class XliffFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'xlf';
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ use Symfony\Component\Yaml\Yaml;
|
||||
*/
|
||||
class YamlFileDumper extends FileDumper
|
||||
{
|
||||
private $extension;
|
||||
private string $extension;
|
||||
|
||||
public function __construct(string $extension = 'yml')
|
||||
{
|
||||
@@ -33,7 +33,7 @@ class YamlFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = [])
|
||||
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.');
|
||||
@@ -55,7 +55,7 @@ class YamlFileDumper extends FileDumper
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension()
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return $this->extension;
|
||||
}
|
||||
|
@@ -15,18 +15,16 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
class ProviderException extends RuntimeException implements ProviderExceptionInterface
|
||||
{
|
||||
private $response;
|
||||
private $debug;
|
||||
private string $debug;
|
||||
|
||||
public function __construct(string $message, ResponseInterface $response, int $code = 0, \Exception $previous = null)
|
||||
{
|
||||
$this->response = $response;
|
||||
$this->debug .= $response->getInfo('debug') ?? '';
|
||||
$this->debug = $response->getInfo('debug') ?? '';
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
@@ -13,8 +13,6 @@ namespace Symfony\Component\Translation\Exception;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
interface ProviderExceptionInterface extends ExceptionInterface
|
||||
{
|
||||
|
@@ -20,12 +20,7 @@ use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
||||
*/
|
||||
abstract class AbstractFileExtractor
|
||||
{
|
||||
/**
|
||||
* @param string|iterable $resource Files, a file or a directory
|
||||
*
|
||||
* @return iterable
|
||||
*/
|
||||
protected function extractFiles($resource)
|
||||
protected function extractFiles(string|iterable $resource): iterable
|
||||
{
|
||||
if (is_iterable($resource)) {
|
||||
$files = [];
|
||||
@@ -49,11 +44,9 @@ abstract class AbstractFileExtractor
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function isFile(string $file)
|
||||
protected function isFile(string $file): bool
|
||||
{
|
||||
if (!is_file($file)) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" file does not exist.', $file));
|
||||
@@ -68,9 +61,7 @@ abstract class AbstractFileExtractor
|
||||
abstract protected function canBeExtracted(string $file);
|
||||
|
||||
/**
|
||||
* @param string|array $resource Files, a file or a directory
|
||||
*
|
||||
* @return iterable files to be extracted
|
||||
* @return iterable
|
||||
*/
|
||||
abstract protected function extractFromDirectory($resource);
|
||||
abstract protected function extractFromDirectory(string|array $resource);
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ class ChainExtractor implements ExtractorInterface
|
||||
*
|
||||
* @var ExtractorInterface[]
|
||||
*/
|
||||
private $extractors = [];
|
||||
private array $extractors = [];
|
||||
|
||||
/**
|
||||
* Adds a loader to the translation extractor.
|
||||
@@ -48,7 +48,7 @@ class ChainExtractor implements ExtractorInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extract($directory, MessageCatalogue $catalogue)
|
||||
public function extract(string|iterable $directory, MessageCatalogue $catalogue)
|
||||
{
|
||||
foreach ($this->extractors as $extractor) {
|
||||
$extractor->extract($directory, $catalogue);
|
||||
|
@@ -26,7 +26,7 @@ interface ExtractorInterface
|
||||
*
|
||||
* @param string|iterable<string> $resource Files, a file or a directory
|
||||
*/
|
||||
public function extract($resource, MessageCatalogue $catalogue);
|
||||
public function extract(string|iterable $resource, MessageCatalogue $catalogue);
|
||||
|
||||
/**
|
||||
* Sets the prefix that should be used for new found messages.
|
||||
|
@@ -27,15 +27,11 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
|
||||
/**
|
||||
* Prefix for new found message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $prefix = '';
|
||||
private string $prefix = '';
|
||||
|
||||
/**
|
||||
* The sequence that captures translation messages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $sequences = [
|
||||
[
|
||||
@@ -135,7 +131,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extract($resource, MessageCatalogue $catalog)
|
||||
public function extract(string|iterable $resource, MessageCatalogue $catalog)
|
||||
{
|
||||
$files = $this->extractFiles($resource);
|
||||
foreach ($files as $file) {
|
||||
@@ -155,12 +151,8 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
|
||||
/**
|
||||
* Normalizes a token.
|
||||
*
|
||||
* @param mixed $token
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function normalizeToken($token)
|
||||
protected function normalizeToken(mixed $token): ?string
|
||||
{
|
||||
if (isset($token[1]) && 'b"' !== $token) {
|
||||
return $token[1];
|
||||
@@ -315,11 +307,9 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function canBeExtracted(string $file)
|
||||
protected function canBeExtracted(string $file): bool
|
||||
{
|
||||
return $this->isFile($file) && 'php' === pathinfo($file, \PATHINFO_EXTENSION);
|
||||
}
|
||||
@@ -327,8 +317,12 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function extractFromDirectory($directory)
|
||||
protected function extractFromDirectory(string|array $directory): iterable
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
$finder = new Finder();
|
||||
|
||||
return $finder->files()->name('*.php')->in($directory);
|
||||
|
@@ -64,10 +64,8 @@ class PhpStringTokenParser
|
||||
* Parses a string token.
|
||||
*
|
||||
* @param string $str String token content
|
||||
*
|
||||
* @return string The parsed string
|
||||
*/
|
||||
public static function parse(string $str)
|
||||
public static function parse(string $str): string
|
||||
{
|
||||
$bLength = 0;
|
||||
if ('b' === $str[0]) {
|
||||
@@ -90,10 +88,8 @@ class PhpStringTokenParser
|
||||
*
|
||||
* @param string $str String without quotes
|
||||
* @param string|null $quote Quote type
|
||||
*
|
||||
* @return string String with escape sequences parsed
|
||||
*/
|
||||
public static function parseEscapeSequences(string $str, string $quote = null)
|
||||
public static function parseEscapeSequences(string $str, string $quote = null): string
|
||||
{
|
||||
if (null !== $quote) {
|
||||
$str = str_replace('\\'.$quote, $quote, $str);
|
||||
@@ -124,10 +120,8 @@ class PhpStringTokenParser
|
||||
*
|
||||
* @param string $startToken Doc string start token content (<<<SMTHG)
|
||||
* @param string $str String token content
|
||||
*
|
||||
* @return string Parsed string
|
||||
*/
|
||||
public static function parseDocString(string $startToken, string $str)
|
||||
public static function parseDocString(string $startToken, string $str): string
|
||||
{
|
||||
// strip last newline (thanks tokenizer for sticking it into the string!)
|
||||
$str = preg_replace('~(\r\n|\n|\r)$~', '', $str);
|
||||
|
@@ -37,7 +37,7 @@ class MessageFormatter implements MessageFormatterInterface, IntlFormatterInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(string $message, string $locale, array $parameters = [])
|
||||
public function format(string $message, string $locale, array $parameters = []): string
|
||||
{
|
||||
if ($this->translator instanceof TranslatorInterface) {
|
||||
return $this->translator->trans($message, $parameters, null, $locale);
|
||||
|
@@ -23,8 +23,6 @@ interface MessageFormatterInterface
|
||||
* @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
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function format(string $message, string $locale, array $parameters = []);
|
||||
public function format(string $message, string $locale, array $parameters = []): string;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2021 Fabien Potencier
|
||||
Copyright (c) 2004-2022 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
|
||||
|
@@ -23,7 +23,7 @@ class ArrayLoader implements LoaderInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, string $locale, string $domain = 'messages')
|
||||
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
|
||||
{
|
||||
$resource = $this->flatten($resource);
|
||||
$catalogue = new MessageCatalogue($locale);
|
||||
|
@@ -20,14 +20,14 @@ use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
*/
|
||||
class CsvFileLoader extends FileLoader
|
||||
{
|
||||
private $delimiter = ';';
|
||||
private $enclosure = '"';
|
||||
private $escape = '\\';
|
||||
private string $delimiter = ';';
|
||||
private string $enclosure = '"';
|
||||
private string $escape = '\\';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource)
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
$messages = [];
|
||||
|
||||
|
@@ -14,6 +14,7 @@ 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>
|
||||
@@ -23,7 +24,7 @@ abstract class FileLoader extends ArrayLoader
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, string $locale, string $domain = 'messages')
|
||||
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));
|
||||
@@ -55,9 +56,7 @@ abstract class FileLoader extends ArrayLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws InvalidResourceException if stream content has an invalid format
|
||||
*/
|
||||
abstract protected function loadResource(string $resource);
|
||||
abstract protected function loadResource(string $resource): array;
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ class IcuDatFileLoader extends IcuResFileLoader
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, string $locale, string $domain = 'messages')
|
||||
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));
|
||||
|
@@ -26,7 +26,7 @@ class IcuResFileLoader implements LoaderInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, string $locale, string $domain = 'messages')
|
||||
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));
|
||||
@@ -72,10 +72,8 @@ class IcuResFileLoader implements LoaderInterface
|
||||
* @param \ResourceBundle $rb The ResourceBundle that will be flattened
|
||||
* @param array $messages Used internally for recursive calls
|
||||
* @param string $path Current path being parsed, used internally for recursive calls
|
||||
*
|
||||
* @return array the flattened ResourceBundle
|
||||
*/
|
||||
protected function flatten(\ResourceBundle $rb, array &$messages = [], string $path = null)
|
||||
protected function flatten(\ResourceBundle $rb, array &$messages = [], string $path = null): array
|
||||
{
|
||||
foreach ($rb as $key => $value) {
|
||||
$nodePath = $path ? $path.'.'.$key : $key;
|
||||
|
@@ -21,7 +21,7 @@ class IniFileLoader extends FileLoader
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource)
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
return parse_ini_file($resource, true);
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ class JsonFileLoader extends FileLoader
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource)
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
$messages = [];
|
||||
if ($data = file_get_contents($resource)) {
|
||||
|
@@ -25,14 +25,8 @@ interface LoaderInterface
|
||||
/**
|
||||
* Loads a locale.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $locale A locale
|
||||
* @param string $domain The domain
|
||||
*
|
||||
* @return MessageCatalogue A MessageCatalogue instance
|
||||
*
|
||||
* @throws NotFoundResourceException when the resource cannot be found
|
||||
* @throws InvalidResourceException when the resource cannot be loaded
|
||||
*/
|
||||
public function load($resource, string $locale, string $domain = 'messages');
|
||||
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue;
|
||||
}
|
||||
|
@@ -22,13 +22,13 @@ 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;
|
||||
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;
|
||||
public const MO_BIG_ENDIAN_MAGIC = 0xDE120495;
|
||||
|
||||
/**
|
||||
* The size of the header of an MO file in bytes.
|
||||
@@ -41,7 +41,7 @@ class MoFileLoader extends FileLoader
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource)
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
$stream = fopen($resource, 'r');
|
||||
|
||||
|
@@ -18,12 +18,12 @@ namespace Symfony\Component\Translation\Loader;
|
||||
*/
|
||||
class PhpFileLoader extends FileLoader
|
||||
{
|
||||
private static $cache = [];
|
||||
private static ?array $cache = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource)
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
if ([] === self::$cache && \function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) && (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) || filter_var(ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) {
|
||||
self::$cache = null;
|
||||
|
@@ -60,7 +60,7 @@ class PoFileLoader extends FileLoader
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource)
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
$stream = fopen($resource, 'r');
|
||||
|
||||
|
@@ -28,7 +28,7 @@ class QtFileLoader implements LoaderInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, string $locale, string $domain = 'messages')
|
||||
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.');
|
||||
|
@@ -31,7 +31,7 @@ class XliffFileLoader implements LoaderInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, string $locale, string $domain = 'messages')
|
||||
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.');
|
||||
@@ -57,7 +57,7 @@ class XliffFileLoader implements LoaderInterface
|
||||
} else {
|
||||
$dom = XmlUtils::loadFile($resource);
|
||||
}
|
||||
} catch (\InvalidArgumentException | XmlParsingException | InvalidXmlException $e) {
|
||||
} catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) {
|
||||
throw new InvalidResourceException(sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
|
@@ -29,7 +29,7 @@ class YamlFileLoader extends FileLoader
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource)
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
if (null === $this->yamlParser) {
|
||||
if (!class_exists(\Symfony\Component\Yaml\Parser::class)) {
|
||||
|
@@ -21,15 +21,11 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
*/
|
||||
class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface
|
||||
{
|
||||
/**
|
||||
* @var TranslatorInterface|TranslatorBagInterface
|
||||
*/
|
||||
private $translator;
|
||||
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
|
||||
* @param TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator The translator must implement TranslatorBagInterface
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator, LoggerInterface $logger)
|
||||
{
|
||||
@@ -44,7 +40,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null)
|
||||
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->log($id, $domain, $locale);
|
||||
@@ -69,7 +65,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocale()
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->translator->getLocale();
|
||||
}
|
||||
@@ -77,7 +73,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue(string $locale = null)
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface
|
||||
{
|
||||
return $this->translator->getCatalogue($locale);
|
||||
}
|
||||
@@ -92,10 +88,8 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
|
||||
/**
|
||||
* Gets the fallback locales.
|
||||
*
|
||||
* @return array The fallback locales
|
||||
*/
|
||||
public function getFallbackLocales()
|
||||
public function getFallbackLocales(): array
|
||||
{
|
||||
if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) {
|
||||
return $this->translator->getFallbackLocales();
|
||||
|
@@ -19,12 +19,12 @@ use Symfony\Component\Translation\Exception\LogicException;
|
||||
*/
|
||||
class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface
|
||||
{
|
||||
private $messages = [];
|
||||
private $metadata = [];
|
||||
private $resources = [];
|
||||
private $locale;
|
||||
private $fallbackCatalogue;
|
||||
private $parent;
|
||||
private array $messages = [];
|
||||
private array $metadata = [];
|
||||
private array $resources = [];
|
||||
private string $locale;
|
||||
private $fallbackCatalogue = null;
|
||||
private ?self $parent = null;
|
||||
|
||||
/**
|
||||
* @param array $messages An array of messages classified by domain
|
||||
@@ -38,7 +38,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocale()
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->locale;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDomains()
|
||||
public function getDomains(): array
|
||||
{
|
||||
$domains = [];
|
||||
|
||||
@@ -63,7 +63,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function all(string $domain = null)
|
||||
public function all(string $domain = null): array
|
||||
{
|
||||
if (null !== $domain) {
|
||||
// skip messages merge if intl-icu requested explicitly
|
||||
@@ -99,7 +99,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has(string $id, string $domain = 'messages')
|
||||
public function has(string $id, string $domain = 'messages'): bool
|
||||
{
|
||||
if (isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {
|
||||
return true;
|
||||
@@ -115,7 +115,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defines(string $id, string $domain = 'messages')
|
||||
public function defines(string $id, string $domain = 'messages'): bool
|
||||
{
|
||||
return isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id]);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $id, string $domain = 'messages')
|
||||
public function get(string $id, string $domain = 'messages'): string
|
||||
{
|
||||
if (isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {
|
||||
return $this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id];
|
||||
@@ -233,7 +233,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFallbackCatalogue()
|
||||
public function getFallbackCatalogue(): ?MessageCatalogueInterface
|
||||
{
|
||||
return $this->fallbackCatalogue;
|
||||
}
|
||||
@@ -241,7 +241,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResources()
|
||||
public function getResources(): array
|
||||
{
|
||||
return array_values($this->resources);
|
||||
}
|
||||
@@ -257,7 +257,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata(string $key = '', string $domain = 'messages')
|
||||
public function getMetadata(string $key = '', string $domain = 'messages'): mixed
|
||||
{
|
||||
if ('' == $domain) {
|
||||
return $this->metadata;
|
||||
@@ -279,7 +279,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMetadata(string $key, $value, string $domain = 'messages')
|
||||
public function setMetadata(string $key, mixed $value, string $domain = 'messages')
|
||||
{
|
||||
$this->metadata[$domain][$key] = $value;
|
||||
}
|
||||
|
@@ -24,17 +24,13 @@ interface MessageCatalogueInterface
|
||||
|
||||
/**
|
||||
* Gets the catalogue locale.
|
||||
*
|
||||
* @return string The locale
|
||||
*/
|
||||
public function getLocale();
|
||||
public function getLocale(): string;
|
||||
|
||||
/**
|
||||
* Gets the domains.
|
||||
*
|
||||
* @return array An array of domains
|
||||
*/
|
||||
public function getDomains();
|
||||
public function getDomains(): array;
|
||||
|
||||
/**
|
||||
* Gets the messages within a given domain.
|
||||
@@ -42,10 +38,8 @@ interface MessageCatalogueInterface
|
||||
* If $domain is null, it returns all messages.
|
||||
*
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return array An array of messages
|
||||
*/
|
||||
public function all(string $domain = null);
|
||||
public function all(string $domain = null): array;
|
||||
|
||||
/**
|
||||
* Sets a message translation.
|
||||
@@ -61,30 +55,24 @@ interface MessageCatalogueInterface
|
||||
*
|
||||
* @param string $id The message id
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return bool true if the message has a translation, false otherwise
|
||||
*/
|
||||
public function has(string $id, string $domain = 'messages');
|
||||
public function has(string $id, string $domain = 'messages'): bool;
|
||||
|
||||
/**
|
||||
* Checks if a message has a translation (it does not take into account the fallback mechanism).
|
||||
*
|
||||
* @param string $id The message id
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return bool true if the message has a translation, false otherwise
|
||||
*/
|
||||
public function defines(string $id, string $domain = 'messages');
|
||||
public function defines(string $id, string $domain = 'messages'): bool;
|
||||
|
||||
/**
|
||||
* Gets a message translation.
|
||||
*
|
||||
* @param string $id The message id
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return string The message translation
|
||||
*/
|
||||
public function get(string $id, string $domain = 'messages');
|
||||
public function get(string $id, string $domain = 'messages'): string;
|
||||
|
||||
/**
|
||||
* Sets translations for a given domain.
|
||||
@@ -119,17 +107,15 @@ interface MessageCatalogueInterface
|
||||
|
||||
/**
|
||||
* Gets the fallback catalogue.
|
||||
*
|
||||
* @return self|null A MessageCatalogueInterface instance or null when no fallback has been set
|
||||
*/
|
||||
public function getFallbackCatalogue();
|
||||
public function getFallbackCatalogue(): ?self;
|
||||
|
||||
/**
|
||||
* Returns an array of resources loaded to build this collection.
|
||||
*
|
||||
* @return ResourceInterface[] An array of resources
|
||||
* @return ResourceInterface[]
|
||||
*/
|
||||
public function getResources();
|
||||
public function getResources(): array;
|
||||
|
||||
/**
|
||||
* Adds a resource for this collection.
|
||||
|
@@ -27,14 +27,12 @@ interface MetadataAwareInterface
|
||||
*
|
||||
* @return mixed The value that was set or an array with the domains/keys or null
|
||||
*/
|
||||
public function getMetadata(string $key = '', string $domain = 'messages');
|
||||
public function getMetadata(string $key = '', string $domain = 'messages'): mixed;
|
||||
|
||||
/**
|
||||
* Adds metadata to a message domain.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setMetadata(string $key, $value, string $domain = 'messages');
|
||||
public function setMetadata(string $key, mixed $value, string $domain = 'messages');
|
||||
|
||||
/**
|
||||
* Deletes metadata for the given key and domain.
|
||||
|
@@ -20,14 +20,14 @@ use Symfony\Component\Translation\Exception\MissingRequiredOptionException;
|
||||
*/
|
||||
final class Dsn
|
||||
{
|
||||
private $scheme;
|
||||
private $host;
|
||||
private $user;
|
||||
private $password;
|
||||
private $port;
|
||||
private $path;
|
||||
private $options;
|
||||
private $originalDsn;
|
||||
private ?string $scheme;
|
||||
private ?string $host;
|
||||
private ?string $user;
|
||||
private ?string $password;
|
||||
private ?int $port;
|
||||
private ?string $path;
|
||||
private array $options = [];
|
||||
private string $originalDsn;
|
||||
|
||||
public function __construct(string $dsn)
|
||||
{
|
||||
@@ -79,7 +79,7 @@ final class Dsn
|
||||
return $this->port ?? $default;
|
||||
}
|
||||
|
||||
public function getOption(string $key, $default = null)
|
||||
public function getOption(string $key, mixed $default = null)
|
||||
{
|
||||
return $this->options[$key] ?? $default;
|
||||
}
|
||||
|
@@ -18,14 +18,12 @@ use Symfony\Component\Translation\TranslatorBagInterface;
|
||||
* Filters domains and locales between the Translator config values and those specific to each provider.
|
||||
*
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
class FilteringProvider implements ProviderInterface
|
||||
{
|
||||
private $provider;
|
||||
private $locales;
|
||||
private $domains;
|
||||
private array $locales;
|
||||
private array $domains;
|
||||
|
||||
public function __construct(ProviderInterface $provider, array $locales, array $domains = [])
|
||||
{
|
||||
|
@@ -16,8 +16,6 @@ use Symfony\Component\Translation\TranslatorBagInterface;
|
||||
|
||||
/**
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
class NullProvider implements ProviderInterface
|
||||
{
|
||||
|
@@ -15,8 +15,6 @@ use Symfony\Component\Translation\Exception\UnsupportedSchemeException;
|
||||
|
||||
/**
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
final class NullProviderFactory extends AbstractProviderFactory
|
||||
{
|
||||
|
@@ -15,11 +15,12 @@ use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
final class TranslationProviderCollection
|
||||
{
|
||||
/**
|
||||
* @var array<string, ProviderInterface>
|
||||
*/
|
||||
private $providers;
|
||||
|
||||
/**
|
||||
@@ -27,10 +28,7 @@ final class TranslationProviderCollection
|
||||
*/
|
||||
public function __construct(iterable $providers)
|
||||
{
|
||||
$this->providers = [];
|
||||
foreach ($providers as $name => $provider) {
|
||||
$this->providers[$name] = $provider;
|
||||
}
|
||||
$this->providers = \is_array($providers) ? $providers : iterator_to_array($providers);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
|
@@ -15,16 +15,14 @@ use Symfony\Component\Translation\Exception\UnsupportedSchemeException;
|
||||
|
||||
/**
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @experimental in 5.3
|
||||
*/
|
||||
class TranslationProviderCollectionFactory
|
||||
{
|
||||
private $factories;
|
||||
private $enabledLocales;
|
||||
private iterable $factories;
|
||||
private array $enabledLocales;
|
||||
|
||||
/**
|
||||
* @param ProviderFactoryInterface[] $factories
|
||||
* @param iterable<mixed, ProviderFactoryInterface> $factories
|
||||
*/
|
||||
public function __construct(iterable $factories, array $enabledLocales)
|
||||
{
|
||||
|
@@ -21,11 +21,15 @@ final class PseudoLocalizationTranslator implements TranslatorInterface
|
||||
private const EXPANSION_CHARACTER = '~';
|
||||
|
||||
private $translator;
|
||||
private $accents;
|
||||
private $expansionFactor;
|
||||
private $brackets;
|
||||
private $parseHTML;
|
||||
private $localizableHTMLAttributes;
|
||||
private bool $accents;
|
||||
private float $expansionFactor;
|
||||
private bool $brackets;
|
||||
private bool $parseHTML;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private array $localizableHTMLAttributes;
|
||||
|
||||
/**
|
||||
* Available options:
|
||||
@@ -82,7 +86,7 @@ final class PseudoLocalizationTranslator implements TranslatorInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null)
|
||||
public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string
|
||||
{
|
||||
$trans = '';
|
||||
$visibleText = '';
|
||||
|
@@ -23,6 +23,16 @@ $translator->addResource('array', [
|
||||
echo $translator->trans('Hello World!'); // outputs « Bonjour ! »
|
||||
```
|
||||
|
||||
Sponsor
|
||||
-------
|
||||
|
||||
The Translation component for Symfony 5.4/6.0 is [backed][1] by:
|
||||
|
||||
* [Crowdin][2], a cloud-based localization management software helping teams to go global and stay agile.
|
||||
* [Lokalise][3], a continuous localization and translation management platform that integrates into your development workflow so you can ship localized products, faster.
|
||||
|
||||
Help Symfony by [sponsoring][4] its development!
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
@@ -31,3 +41,8 @@ Resources
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||
|
||||
[1]: https://symfony.com/backers
|
||||
[2]: https://crowdin.com
|
||||
[3]: https://lokalise.com
|
||||
[4]: https://symfony.com/sponsor
|
||||
|
@@ -25,9 +25,9 @@ class TranslationReader implements TranslationReaderInterface
|
||||
/**
|
||||
* Loaders used for import.
|
||||
*
|
||||
* @var array
|
||||
* @var array<string, LoaderInterface>
|
||||
*/
|
||||
private $loaders = [];
|
||||
private array $loaders = [];
|
||||
|
||||
/**
|
||||
* Adds a loader to the translation extractor.
|
||||
|
@@ -19,13 +19,16 @@ $usageInstructions = <<<END
|
||||
# show the translation status of all locales
|
||||
$ php translation-status.php
|
||||
|
||||
# show the translation status of all locales and all their missing translations
|
||||
# only show the translation status of incomplete or erroneous locales
|
||||
$ php translation-status.php --incomplete
|
||||
|
||||
# show the translation status of all locales, all their missing translations and mismatches between trans-unit id and source
|
||||
$ php translation-status.php -v
|
||||
|
||||
# show the status of a single locale
|
||||
$ php translation-status.php fr
|
||||
|
||||
# show the status of a single locale and all its missing translations
|
||||
# show the status of a single locale, missing translations and mismatches between trans-unit id and source
|
||||
$ php translation-status.php fr -v
|
||||
|
||||
END;
|
||||
@@ -35,6 +38,8 @@ $config = [
|
||||
'verbose_output' => false,
|
||||
// NULL = analyze all locales
|
||||
'locale_to_analyze' => null,
|
||||
// append --incomplete to only show incomplete languages
|
||||
'include_completed_languages' => true,
|
||||
// the reference files all the other translations are compared to
|
||||
'original_files' => [
|
||||
'src/Symfony/Component/Form/Resources/translations/validators.en.xlf',
|
||||
@@ -46,12 +51,17 @@ $config = [
|
||||
$argc = $_SERVER['argc'];
|
||||
$argv = $_SERVER['argv'];
|
||||
|
||||
if ($argc > 3) {
|
||||
if ($argc > 4) {
|
||||
echo str_replace('translation-status.php', $argv[0], $usageInstructions);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
foreach (array_slice($argv, 1) as $argumentOrOption) {
|
||||
if ('--incomplete' === $argumentOrOption) {
|
||||
$config['include_completed_languages'] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_starts_with($argumentOrOption, '-')) {
|
||||
$config['verbose_output'] = true;
|
||||
} else {
|
||||
@@ -67,6 +77,7 @@ foreach ($config['original_files'] as $originalFilePath) {
|
||||
}
|
||||
|
||||
$totalMissingTranslations = 0;
|
||||
$totalTranslationMismatches = 0;
|
||||
|
||||
foreach ($config['original_files'] as $originalFilePath) {
|
||||
$translationFilePaths = findTranslationFiles($originalFilePath, $config['locale_to_analyze']);
|
||||
@@ -75,11 +86,14 @@ foreach ($config['original_files'] as $originalFilePath) {
|
||||
$totalMissingTranslations += array_sum(array_map(function ($translation) {
|
||||
return count($translation['missingKeys']);
|
||||
}, array_values($translationStatus)));
|
||||
$totalTranslationMismatches += array_sum(array_map(function ($translation) {
|
||||
return count($translation['mismatches']);
|
||||
}, array_values($translationStatus)));
|
||||
|
||||
printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output']);
|
||||
printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output'], $config['include_completed_languages']);
|
||||
}
|
||||
|
||||
exit($totalMissingTranslations > 0 ? 1 : 0);
|
||||
exit($totalTranslationMismatches > 0 ? 1 : 0);
|
||||
|
||||
function findTranslationFiles($originalFilePath, $localeToAnalyze)
|
||||
{
|
||||
@@ -112,21 +126,29 @@ function calculateTranslationStatus($originalFilePath, $translationFilePaths)
|
||||
foreach ($translationFilePaths as $locale => $translationPath) {
|
||||
$translatedKeys = extractTranslationKeys($translationPath);
|
||||
$missingKeys = array_diff_key($allTranslationKeys, $translatedKeys);
|
||||
$mismatches = findTransUnitMismatches($allTranslationKeys, $translatedKeys);
|
||||
|
||||
$translationStatus[$locale] = [
|
||||
'total' => count($allTranslationKeys),
|
||||
'translated' => count($translatedKeys),
|
||||
'missingKeys' => $missingKeys,
|
||||
'mismatches' => $mismatches,
|
||||
];
|
||||
$translationStatus[$locale]['is_completed'] = isTranslationCompleted($translationStatus[$locale]);
|
||||
}
|
||||
|
||||
return $translationStatus;
|
||||
}
|
||||
|
||||
function printTranslationStatus($originalFilePath, $translationStatus, $verboseOutput)
|
||||
function isTranslationCompleted(array $translationStatus): bool
|
||||
{
|
||||
return $translationStatus['total'] === $translationStatus['translated'] && 0 === count($translationStatus['mismatches']);
|
||||
}
|
||||
|
||||
function printTranslationStatus($originalFilePath, $translationStatus, $verboseOutput, $includeCompletedLanguages)
|
||||
{
|
||||
printTitle($originalFilePath);
|
||||
printTable($translationStatus, $verboseOutput);
|
||||
printTable($translationStatus, $verboseOutput, $includeCompletedLanguages);
|
||||
echo \PHP_EOL.\PHP_EOL;
|
||||
}
|
||||
|
||||
@@ -152,13 +174,35 @@ function extractTranslationKeys($filePath)
|
||||
return $translationKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the trans-unit id and source match with the base translation.
|
||||
*/
|
||||
function findTransUnitMismatches(array $baseTranslationKeys, array $translatedKeys): array
|
||||
{
|
||||
$mismatches = [];
|
||||
|
||||
foreach ($baseTranslationKeys as $translationId => $translationKey) {
|
||||
if (!isset($translatedKeys[$translationId])) {
|
||||
continue;
|
||||
}
|
||||
if ($translatedKeys[$translationId] !== $translationKey) {
|
||||
$mismatches[$translationId] = [
|
||||
'found' => $translatedKeys[$translationId],
|
||||
'expected' => $translationKey,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $mismatches;
|
||||
}
|
||||
|
||||
function printTitle($title)
|
||||
{
|
||||
echo $title.\PHP_EOL;
|
||||
echo str_repeat('=', strlen($title)).\PHP_EOL.\PHP_EOL;
|
||||
}
|
||||
|
||||
function printTable($translations, $verboseOutput)
|
||||
function printTable($translations, $verboseOutput, bool $includeCompletedLanguages)
|
||||
{
|
||||
if (0 === count($translations)) {
|
||||
echo 'No translations found';
|
||||
@@ -168,24 +212,47 @@ function printTable($translations, $verboseOutput)
|
||||
$longestLocaleNameLength = max(array_map('strlen', array_keys($translations)));
|
||||
|
||||
foreach ($translations as $locale => $translation) {
|
||||
if (!$includeCompletedLanguages && $translation['is_completed']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($translation['translated'] > $translation['total']) {
|
||||
textColorRed();
|
||||
} elseif ($translation['translated'] === $translation['total']) {
|
||||
} elseif (count($translation['mismatches']) > 0) {
|
||||
textColorRed();
|
||||
} elseif ($translation['is_completed']) {
|
||||
textColorGreen();
|
||||
}
|
||||
|
||||
echo sprintf('| Locale: %-'.$longestLocaleNameLength.'s | Translated: %d/%d', $locale, $translation['translated'], $translation['total']).\PHP_EOL;
|
||||
echo sprintf(
|
||||
'| Locale: %-'.$longestLocaleNameLength.'s | Translated: %2d/%2d | Mismatches: %d |',
|
||||
$locale,
|
||||
$translation['translated'],
|
||||
$translation['total'],
|
||||
count($translation['mismatches'])
|
||||
).\PHP_EOL;
|
||||
|
||||
textColorNormal();
|
||||
|
||||
$shouldBeClosed = false;
|
||||
if (true === $verboseOutput && count($translation['missingKeys']) > 0) {
|
||||
echo str_repeat('-', 80).\PHP_EOL;
|
||||
echo '| Missing Translations:'.\PHP_EOL;
|
||||
echo '| Missing Translations:'.\PHP_EOL;
|
||||
|
||||
foreach ($translation['missingKeys'] as $id => $content) {
|
||||
echo sprintf('| (id=%s) %s', $id, $content).\PHP_EOL;
|
||||
echo sprintf('| (id=%s) %s', $id, $content).\PHP_EOL;
|
||||
}
|
||||
$shouldBeClosed = true;
|
||||
}
|
||||
if (true === $verboseOutput && count($translation['mismatches']) > 0) {
|
||||
echo '| Mismatches between trans-unit id and source:'.\PHP_EOL;
|
||||
|
||||
foreach ($translation['mismatches'] as $id => $content) {
|
||||
echo sprintf('| (id=%s) Expected: %s', $id, $content['expected']).\PHP_EOL;
|
||||
echo sprintf('| Found: %s', $content['found']).\PHP_EOL;
|
||||
}
|
||||
$shouldBeClosed = true;
|
||||
}
|
||||
if ($shouldBeClosed) {
|
||||
echo str_repeat('-', 80).\PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@
|
||||
"en_BS": "en_001",
|
||||
"en_BW": "en_001",
|
||||
"en_BZ": "en_001",
|
||||
"en_CA": "en_001",
|
||||
"en_CC": "en_001",
|
||||
"en_CH": "en_150",
|
||||
"en_CK": "en_001",
|
||||
@@ -65,7 +64,6 @@
|
||||
"en_NU": "en_001",
|
||||
"en_NZ": "en_001",
|
||||
"en_PG": "en_001",
|
||||
"en_PH": "en_001",
|
||||
"en_PK": "en_001",
|
||||
"en_PN": "en_001",
|
||||
"en_PW": "en_001",
|
||||
|
@@ -33,7 +33,7 @@ abstract class ProviderFactoryTestCase extends TestCase
|
||||
{
|
||||
protected $client;
|
||||
protected $logger;
|
||||
protected $defaultLocale;
|
||||
protected string $defaultLocale;
|
||||
protected $loader;
|
||||
protected $xliffFileDumper;
|
||||
|
||||
@@ -122,26 +122,26 @@ abstract class ProviderFactoryTestCase extends TestCase
|
||||
|
||||
protected function getClient(): HttpClientInterface
|
||||
{
|
||||
return $this->client ?? $this->client = new MockHttpClient();
|
||||
return $this->client ??= new MockHttpClient();
|
||||
}
|
||||
|
||||
protected function getLogger(): LoggerInterface
|
||||
{
|
||||
return $this->logger ?? $this->logger = $this->createMock(LoggerInterface::class);
|
||||
return $this->logger ??= $this->createMock(LoggerInterface::class);
|
||||
}
|
||||
|
||||
protected function getDefaultLocale(): string
|
||||
{
|
||||
return $this->defaultLocale ?? $this->defaultLocale = 'en';
|
||||
return $this->defaultLocale ??= 'en';
|
||||
}
|
||||
|
||||
protected function getLoader(): LoaderInterface
|
||||
{
|
||||
return $this->loader ?? $this->loader = $this->createMock(LoaderInterface::class);
|
||||
return $this->loader ??= $this->createMock(LoaderInterface::class);
|
||||
}
|
||||
|
||||
protected function getXliffFileDumper(): XliffFileDumper
|
||||
{
|
||||
return $this->xliffFileDumper ?? $this->xliffFileDumper = $this->createMock(XliffFileDumper::class);
|
||||
return $this->xliffFileDumper ??= $this->createMock(XliffFileDumper::class);
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace Symfony\Component\Translation\Test;
|
||||
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\MockHttpClient;
|
||||
@@ -31,7 +30,7 @@ abstract class ProviderTestCase extends TestCase
|
||||
{
|
||||
protected $client;
|
||||
protected $logger;
|
||||
protected $defaultLocale;
|
||||
protected string $defaultLocale;
|
||||
protected $loader;
|
||||
protected $xliffFileDumper;
|
||||
|
||||
@@ -52,35 +51,26 @@ abstract class ProviderTestCase extends TestCase
|
||||
|
||||
protected function getClient(): MockHttpClient
|
||||
{
|
||||
return $this->client ?? $this->client = new MockHttpClient();
|
||||
return $this->client ??= new MockHttpClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LoaderInterface&MockObject
|
||||
*/
|
||||
protected function getLoader(): LoaderInterface
|
||||
{
|
||||
return $this->loader ?? $this->loader = $this->createMock(LoaderInterface::class);
|
||||
return $this->loader ??= $this->createMock(LoaderInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LoaderInterface&MockObject
|
||||
*/
|
||||
protected function getLogger(): LoggerInterface
|
||||
{
|
||||
return $this->logger ?? $this->logger = $this->createMock(LoggerInterface::class);
|
||||
return $this->logger ??= $this->createMock(LoggerInterface::class);
|
||||
}
|
||||
|
||||
protected function getDefaultLocale(): string
|
||||
{
|
||||
return $this->defaultLocale ?? $this->defaultLocale = 'en';
|
||||
return $this->defaultLocale ??= 'en';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LoaderInterface&MockObject
|
||||
*/
|
||||
protected function getXliffFileDumper(): XliffFileDumper
|
||||
{
|
||||
return $this->xliffFileDumper ?? $this->xliffFileDumper = $this->createMock(XliffFileDumper::class);
|
||||
return $this->xliffFileDumper ??= $this->createMock(XliffFileDumper::class);
|
||||
}
|
||||
}
|
||||
|
@@ -19,9 +19,9 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
*/
|
||||
class TranslatableMessage implements TranslatableInterface
|
||||
{
|
||||
private $message;
|
||||
private $parameters;
|
||||
private $domain;
|
||||
private string $message;
|
||||
private array $parameters;
|
||||
private ?string $domain;
|
||||
|
||||
public function __construct(string $message, array $parameters = [], string $domain = null)
|
||||
{
|
||||
@@ -52,6 +52,11 @@ class TranslatableMessage implements TranslatableInterface
|
||||
|
||||
public function trans(TranslatorInterface $translator, string $locale = null): string
|
||||
{
|
||||
return $translator->trans($this->getMessage(), $this->getParameters(), $this->getDomain(), $locale);
|
||||
return $translator->trans($this->getMessage(), array_map(
|
||||
static function ($parameter) use ($translator, $locale) {
|
||||
return $parameter instanceof TranslatableInterface ? $parameter->trans($translator, $locale) : $parameter;
|
||||
},
|
||||
$this->getParameters()
|
||||
), $this->getDomain(), $locale);
|
||||
}
|
||||
}
|
||||
|
@@ -37,54 +37,33 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
*/
|
||||
protected $catalogues = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $locale;
|
||||
private string $locale;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var string[]
|
||||
*/
|
||||
private $fallbackLocales = [];
|
||||
private array $fallbackLocales = [];
|
||||
|
||||
/**
|
||||
* @var LoaderInterface[]
|
||||
*/
|
||||
private $loaders = [];
|
||||
private array $loaders = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $resources = [];
|
||||
private array $resources = [];
|
||||
|
||||
/**
|
||||
* @var MessageFormatterInterface
|
||||
*/
|
||||
private $formatter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $cacheDir;
|
||||
private ?string $cacheDir;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $debug;
|
||||
private bool $debug;
|
||||
|
||||
private $cacheVary;
|
||||
private array $cacheVary;
|
||||
|
||||
/**
|
||||
* @var ConfigCacheFactoryInterface|null
|
||||
*/
|
||||
private $configCacheFactory;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $parentLocales;
|
||||
private array $parentLocales;
|
||||
|
||||
private $hasIntlFormatter;
|
||||
private bool $hasIntlFormatter;
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException If a locale contains invalid characters
|
||||
@@ -127,7 +106,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
*
|
||||
* @throws InvalidArgumentException If the locale contains invalid characters
|
||||
*/
|
||||
public function addResource(string $format, $resource, string $locale, string $domain = null)
|
||||
public function addResource(string $format, mixed $resource, string $locale, string $domain = null)
|
||||
{
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
@@ -157,7 +136,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocale()
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->locale ?: (class_exists(\Locale::class) ? \Locale::getDefault() : 'en');
|
||||
}
|
||||
@@ -165,6 +144,8 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
/**
|
||||
* Sets the fallback locales.
|
||||
*
|
||||
* @param string[] $locales
|
||||
*
|
||||
* @throws InvalidArgumentException If a locale contains invalid characters
|
||||
*/
|
||||
public function setFallbackLocales(array $locales)
|
||||
@@ -192,7 +173,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null)
|
||||
public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string
|
||||
{
|
||||
if (null === $id || '' === $id) {
|
||||
return '';
|
||||
@@ -227,7 +208,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue(string $locale = null)
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface
|
||||
{
|
||||
if (!$locale) {
|
||||
$locale = $this->getLocale();
|
||||
@@ -253,9 +234,9 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
/**
|
||||
* Gets the loaders.
|
||||
*
|
||||
* @return array LoaderInterface[]
|
||||
* @return LoaderInterface[]
|
||||
*/
|
||||
protected function getLoaders()
|
||||
protected function getLoaders(): array
|
||||
{
|
||||
return $this->loaders;
|
||||
}
|
||||
@@ -407,18 +388,10 @@ EOF
|
||||
|
||||
protected function computeFallbackLocales(string $locale)
|
||||
{
|
||||
if (null === $this->parentLocales) {
|
||||
$this->parentLocales = json_decode(file_get_contents(__DIR__.'/Resources/data/parents.json'), true);
|
||||
}
|
||||
$this->parentLocales ??= json_decode(file_get_contents(__DIR__.'/Resources/data/parents.json'), true);
|
||||
|
||||
$originLocale = $locale;
|
||||
$locales = [];
|
||||
foreach ($this->fallbackLocales as $fallback) {
|
||||
if ($fallback === $locale) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$locales[] = $fallback;
|
||||
}
|
||||
|
||||
while ($locale) {
|
||||
$parent = $this->parentLocales[$locale] ?? null;
|
||||
@@ -439,10 +412,18 @@ EOF
|
||||
}
|
||||
|
||||
if (null !== $locale) {
|
||||
array_unshift($locales, $locale);
|
||||
$locales[] = $locale;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->fallbackLocales as $fallback) {
|
||||
if ($fallback === $originLocale) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$locales[] = $fallback;
|
||||
}
|
||||
|
||||
return array_unique($locales);
|
||||
}
|
||||
|
||||
@@ -453,7 +434,7 @@ EOF
|
||||
*/
|
||||
protected function assertValidLocale(string $locale)
|
||||
{
|
||||
if (!preg_match('/^[a-z0-9@_\\.\\-]*$/i', (string) $locale)) {
|
||||
if (!preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid "%s" locale.', $locale));
|
||||
}
|
||||
}
|
||||
@@ -464,9 +445,7 @@ EOF
|
||||
*/
|
||||
private function getConfigCacheFactory(): ConfigCacheFactoryInterface
|
||||
{
|
||||
if (!$this->configCacheFactory) {
|
||||
$this->configCacheFactory = new ConfigCacheFactory($this->debug);
|
||||
}
|
||||
$this->configCacheFactory ??= new ConfigCacheFactory($this->debug);
|
||||
|
||||
return $this->configCacheFactory;
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ use Symfony\Component\Translation\Catalogue\TargetOperation;
|
||||
final class TranslatorBag implements TranslatorBagInterface
|
||||
{
|
||||
/** @var MessageCatalogue[] */
|
||||
private $catalogues = [];
|
||||
private array $catalogues = [];
|
||||
|
||||
public function addCatalogue(MessageCatalogue $catalogue): void
|
||||
{
|
||||
@@ -38,7 +38,7 @@ final class TranslatorBag implements TranslatorBagInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue(string $locale = null)
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface
|
||||
{
|
||||
if (null === $locale || !isset($this->catalogues[$locale])) {
|
||||
$this->catalogues[$locale] = new MessageCatalogue($locale);
|
||||
|
@@ -14,10 +14,6 @@ namespace Symfony\Component\Translation;
|
||||
use Symfony\Component\Translation\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* TranslatorBagInterface.
|
||||
*
|
||||
* @method MessageCatalogueInterface[] getCatalogues() Returns all catalogues of the instance
|
||||
*
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
*/
|
||||
interface TranslatorBagInterface
|
||||
@@ -27,9 +23,14 @@ interface TranslatorBagInterface
|
||||
*
|
||||
* @param string|null $locale The locale or null to use the default
|
||||
*
|
||||
* @return MessageCatalogueInterface
|
||||
*
|
||||
* @throws InvalidArgumentException If the locale contains invalid characters
|
||||
*/
|
||||
public function getCatalogue(string $locale = null);
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface;
|
||||
|
||||
/**
|
||||
* Returns all catalogues of the instance.
|
||||
*
|
||||
* @return MessageCatalogueInterface[]
|
||||
*/
|
||||
public function getCatalogues(): array;
|
||||
}
|
||||
|
@@ -30,10 +30,8 @@ class ArrayConverter
|
||||
* For example this array('foo.bar' => 'value') will be converted to ['foo' => ['bar' => 'value']].
|
||||
*
|
||||
* @param array $messages Linear messages array
|
||||
*
|
||||
* @return array Tree-like messages array
|
||||
*/
|
||||
public static function expandToTree(array $messages)
|
||||
public static function expandToTree(array $messages): array
|
||||
{
|
||||
$tree = [];
|
||||
|
||||
|
@@ -85,11 +85,6 @@ class XliffUtils
|
||||
|
||||
private static function shouldEnableEntityLoader(): bool
|
||||
{
|
||||
// Version prior to 8.0 can be enabled without deprecation
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static $dom, $schema;
|
||||
if (null === $dom) {
|
||||
$dom = new \DOMDocument();
|
||||
|
@@ -23,7 +23,10 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class TranslationWriter implements TranslationWriterInterface
|
||||
{
|
||||
private $dumpers = [];
|
||||
/**
|
||||
* @var array<string, DumperInterface>
|
||||
*/
|
||||
private array $dumpers = [];
|
||||
|
||||
/**
|
||||
* Adds a dumper to the writer.
|
||||
@@ -35,10 +38,8 @@ class TranslationWriter implements TranslationWriterInterface
|
||||
|
||||
/**
|
||||
* Obtains the list of supported formats.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFormats()
|
||||
public function getFormats(): array
|
||||
{
|
||||
return array_keys($this->dumpers);
|
||||
}
|
||||
|
@@ -16,33 +16,33 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"symfony/deprecation-contracts": "^2.1",
|
||||
"php": ">=8.0.2",
|
||||
"symfony/polyfill-mbstring": "~1.0",
|
||||
"symfony/polyfill-php80": "^1.16",
|
||||
"symfony/translation-contracts": "^2.3"
|
||||
"symfony/translation-contracts": "^2.3|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/config": "^4.4|^5.0",
|
||||
"symfony/console": "^4.4|^5.0",
|
||||
"symfony/dependency-injection": "^5.0",
|
||||
"symfony/http-kernel": "^5.0",
|
||||
"symfony/intl": "^4.4|^5.0",
|
||||
"symfony/config": "^5.4|^6.0",
|
||||
"symfony/console": "^5.4|^6.0",
|
||||
"symfony/dependency-injection": "^5.4|^6.0",
|
||||
"symfony/http-client-contracts": "^1.1|^2.0|^3.0",
|
||||
"symfony/http-kernel": "^5.4|^6.0",
|
||||
"symfony/intl": "^5.4|^6.0",
|
||||
"symfony/polyfill-intl-icu": "^1.21",
|
||||
"symfony/service-contracts": "^1.1.2|^2",
|
||||
"symfony/yaml": "^4.4|^5.0",
|
||||
"symfony/finder": "^4.4|^5.0",
|
||||
"symfony/service-contracts": "^1.1.2|^2|^3",
|
||||
"symfony/yaml": "^5.4|^6.0",
|
||||
"symfony/finder": "^5.4|^6.0",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<4.4",
|
||||
"symfony/dependency-injection": "<5.0",
|
||||
"symfony/http-kernel": "<5.0",
|
||||
"symfony/twig-bundle": "<5.0",
|
||||
"symfony/yaml": "<4.4"
|
||||
"symfony/config": "<5.4",
|
||||
"symfony/dependency-injection": "<5.4",
|
||||
"symfony/http-kernel": "<5.4",
|
||||
"symfony/twig-bundle": "<5.4",
|
||||
"symfony/yaml": "<5.4",
|
||||
"symfony/console": "<5.4"
|
||||
},
|
||||
"provide": {
|
||||
"symfony/translation-implementation": "2.3"
|
||||
"symfony/translation-implementation": "2.3|3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/config": "",
|
||||
|
Reference in New Issue
Block a user