Commaaa2
This commit is contained in:
29
vendor/symfony/translation/CHANGELOG.md
vendored
29
vendor/symfony/translation/CHANGELOG.md
vendored
@@ -1,6 +1,35 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
6.4
|
||||
---
|
||||
|
||||
* Give current locale to `LocaleSwitcher::runWithLocale()`'s callback
|
||||
* Add `--as-tree` option to `translation:pull` command to write YAML messages as a tree-like structure
|
||||
* [BC BREAK] Add argument `$buildDir` to `DataCollectorTranslator::warmUp()`
|
||||
* Add `DataCollectorTranslatorPass` and `LoggingTranslatorPass` (moved from `FrameworkBundle`)
|
||||
* Add `PhraseTranslationProvider`
|
||||
|
||||
6.2.7
|
||||
-----
|
||||
|
||||
* [BC BREAK] The following data providers for `ProviderFactoryTestCase` are now static:
|
||||
`supportsProvider()`, `createProvider()`, `unsupportedSchemeProvider()`and `incompleteDsnProvider()`
|
||||
* [BC BREAK] `ProviderTestCase::toStringProvider()` is now static
|
||||
|
||||
6.2
|
||||
---
|
||||
|
||||
* Deprecate `PhpStringTokenParser`
|
||||
* Deprecate `PhpExtractor` in favor of `PhpAstExtractor`
|
||||
* Add `PhpAstExtractor` (requires [nikic/php-parser](https://github.com/nikic/php-parser) to be installed)
|
||||
|
||||
6.1
|
||||
---
|
||||
|
||||
* Parameters implementing `TranslatableInterface` are processed
|
||||
* Add the file extension to the `XliffFileDumper` constructor
|
||||
|
||||
5.4
|
||||
---
|
||||
|
||||
|
||||
@@ -34,11 +34,6 @@ abstract class AbstractOperation implements OperationInterface
|
||||
protected $target;
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* @var array|null The domains affected by this operation
|
||||
*/
|
||||
private $domains;
|
||||
|
||||
/**
|
||||
* This array stores 'all', 'new' and 'obsolete' messages for all valid domains.
|
||||
*
|
||||
@@ -62,6 +57,8 @@ abstract class AbstractOperation implements OperationInterface
|
||||
*/
|
||||
protected $messages;
|
||||
|
||||
private array $domains;
|
||||
|
||||
/**
|
||||
* @throws LogicException
|
||||
*/
|
||||
@@ -77,12 +74,9 @@ abstract class AbstractOperation implements OperationInterface
|
||||
$this->messages = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDomains(): array
|
||||
{
|
||||
if (null === $this->domains) {
|
||||
if (!isset($this->domains)) {
|
||||
$domains = [];
|
||||
foreach ([$this->source, $this->target] as $catalogue) {
|
||||
foreach ($catalogue->getDomains() as $domain) {
|
||||
@@ -100,9 +94,6 @@ abstract class AbstractOperation implements OperationInterface
|
||||
return $this->domains;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessages(string $domain): array
|
||||
{
|
||||
if (!\in_array($domain, $this->getDomains())) {
|
||||
@@ -116,9 +107,6 @@ abstract class AbstractOperation implements OperationInterface
|
||||
return $this->messages[$domain][self::ALL_BATCH];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewMessages(string $domain): array
|
||||
{
|
||||
if (!\in_array($domain, $this->getDomains())) {
|
||||
@@ -132,9 +120,6 @@ abstract class AbstractOperation implements OperationInterface
|
||||
return $this->messages[$domain][self::NEW_BATCH];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getObsoleteMessages(string $domain): array
|
||||
{
|
||||
if (!\in_array($domain, $this->getDomains())) {
|
||||
@@ -148,9 +133,6 @@ abstract class AbstractOperation implements OperationInterface
|
||||
return $this->messages[$domain][self::OBSOLETE_BATCH];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResult(): MessageCatalogueInterface
|
||||
{
|
||||
foreach ($this->getDomains() as $domain) {
|
||||
@@ -174,12 +156,12 @@ abstract class AbstractOperation implements OperationInterface
|
||||
|
||||
foreach ($this->getDomains() as $domain) {
|
||||
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||
switch ($batch) {
|
||||
case self::OBSOLETE_BATCH: $messages = $this->getObsoleteMessages($domain); break;
|
||||
case self::NEW_BATCH: $messages = $this->getNewMessages($domain); break;
|
||||
case self::ALL_BATCH: $messages = $this->getMessages($domain); break;
|
||||
default: throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH));
|
||||
}
|
||||
$messages = match ($batch) {
|
||||
self::OBSOLETE_BATCH => $this->getObsoleteMessages($domain),
|
||||
self::NEW_BATCH => $this->getNewMessages($domain),
|
||||
self::ALL_BATCH => $this->getMessages($domain),
|
||||
default => throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)),
|
||||
};
|
||||
|
||||
if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) {
|
||||
continue;
|
||||
@@ -198,6 +180,8 @@ abstract class AbstractOperation implements OperationInterface
|
||||
* stores the results.
|
||||
*
|
||||
* @param string $domain The domain which the operation will be performed for
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function processDomain(string $domain);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
class MergeOperation extends AbstractOperation
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
protected function processDomain(string $domain)
|
||||
{
|
||||
@@ -36,6 +36,18 @@ class MergeOperation extends AbstractOperation
|
||||
];
|
||||
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||
|
||||
foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {
|
||||
if (null === $this->result->getCatalogueMetadata($key, $domain)) {
|
||||
$this->result->setCatalogueMetadata($key, $value, $domain);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {
|
||||
if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {
|
||||
$this->result->setCatalogueMetadata($key, $value, $intlDomain);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->source->all($domain) as $id => $message) {
|
||||
$this->messages[$domain]['all'][$id] = $message;
|
||||
$d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;
|
||||
|
||||
@@ -26,7 +26,7 @@ use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
class TargetOperation extends AbstractOperation
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
protected function processDomain(string $domain)
|
||||
{
|
||||
@@ -37,6 +37,18 @@ class TargetOperation extends AbstractOperation
|
||||
];
|
||||
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||
|
||||
foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {
|
||||
if (null === $this->result->getCatalogueMetadata($key, $domain)) {
|
||||
$this->result->setCatalogueMetadata($key, $value, $domain);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {
|
||||
if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {
|
||||
$this->result->setCatalogueMetadata($key, $value, $intlDomain);
|
||||
}
|
||||
}
|
||||
|
||||
// For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``,
|
||||
// because doing so will drop messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}
|
||||
//
|
||||
|
||||
@@ -34,9 +34,9 @@ final class TranslationPullCommand extends Command
|
||||
{
|
||||
use TranslationTrait;
|
||||
|
||||
private $providerCollection;
|
||||
private $writer;
|
||||
private $reader;
|
||||
private TranslationProviderCollection $providerCollection;
|
||||
private TranslationWriterInterface $writer;
|
||||
private TranslationReaderInterface $reader;
|
||||
private string $defaultLocale;
|
||||
private array $transPaths;
|
||||
private array $enabledLocales;
|
||||
@@ -64,9 +64,8 @@ final class TranslationPullCommand extends Command
|
||||
if ($input->mustSuggestOptionValuesFor('domains')) {
|
||||
$provider = $this->providerCollection->get($input->getArgument('provider'));
|
||||
|
||||
if ($provider && method_exists($provider, 'getDomains')) {
|
||||
$domains = $provider->getDomains();
|
||||
$suggestions->suggestValues($domains);
|
||||
if (method_exists($provider, 'getDomains')) {
|
||||
$suggestions->suggestValues($provider->getDomains());
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -83,10 +82,7 @@ final class TranslationPullCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$keys = $this->providerCollection->keys();
|
||||
$defaultProvider = 1 === \count($keys) ? $keys[0] : null;
|
||||
@@ -99,6 +95,7 @@ final class TranslationPullCommand extends Command
|
||||
new InputOption('domains', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'),
|
||||
new InputOption('locales', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'),
|
||||
new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format.', 'xlf12'),
|
||||
new InputOption('as-tree', null, InputOption::VALUE_OPTIONAL, 'Write messages as a tree-like structure. Needs --format=yaml. The given value defines the level where to switch to inline YAML'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</> command pulls translations from the given provider. Only
|
||||
@@ -120,9 +117,6 @@ EOF
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
@@ -133,6 +127,7 @@ EOF
|
||||
$locales = $input->getOption('locales') ?: $this->enabledLocales;
|
||||
$domains = $input->getOption('domains');
|
||||
$format = $input->getOption('format');
|
||||
$asTree = (int) $input->getOption('as-tree');
|
||||
$xliffVersion = '1.2';
|
||||
|
||||
if ($intlIcu && !$force) {
|
||||
@@ -149,6 +144,8 @@ EOF
|
||||
'path' => end($this->transPaths),
|
||||
'xliff_version' => $xliffVersion,
|
||||
'default_locale' => $this->defaultLocale,
|
||||
'as_tree' => (bool) $asTree,
|
||||
'inline' => $asTree,
|
||||
];
|
||||
|
||||
if (!$domains) {
|
||||
|
||||
@@ -34,8 +34,8 @@ final class TranslationPushCommand extends Command
|
||||
{
|
||||
use TranslationTrait;
|
||||
|
||||
private $providers;
|
||||
private $reader;
|
||||
private TranslationProviderCollection $providers;
|
||||
private TranslationReaderInterface $reader;
|
||||
private array $transPaths;
|
||||
private array $enabledLocales;
|
||||
|
||||
@@ -73,10 +73,7 @@ final class TranslationPushCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$keys = $this->providers->keys();
|
||||
$defaultProvider = 1 === \count($keys) ? $keys[0] : null;
|
||||
@@ -113,15 +110,12 @@ EOF
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$provider = $this->providers->get($input->getArgument('provider'));
|
||||
|
||||
if (!$this->enabledLocales) {
|
||||
throw new InvalidArgumentException(sprintf('You must define "framework.translator.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.', parse_url($provider, \PHP_URL_SCHEME)));
|
||||
throw new InvalidArgumentException(sprintf('You must define "framework.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.', parse_url($provider, \PHP_URL_SCHEME)));
|
||||
}
|
||||
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
@@ -41,23 +41,23 @@ class XliffLintCommand extends Command
|
||||
private ?\Closure $isReadableProvider;
|
||||
private bool $requireStrictFileNames;
|
||||
|
||||
public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null, bool $requireStrictFileNames = true)
|
||||
public function __construct(?string $name = null, ?callable $directoryIteratorProvider = null, ?callable $isReadableProvider = null, bool $requireStrictFileNames = true)
|
||||
{
|
||||
parent::__construct($name);
|
||||
|
||||
$this->directoryIteratorProvider = null === $directoryIteratorProvider || $directoryIteratorProvider instanceof \Closure ? $directoryIteratorProvider : \Closure::fromCallable($directoryIteratorProvider);
|
||||
$this->isReadableProvider = null === $isReadableProvider || $isReadableProvider instanceof \Closure ? $isReadableProvider : \Closure::fromCallable($isReadableProvider);
|
||||
$this->directoryIteratorProvider = null === $directoryIteratorProvider ? null : $directoryIteratorProvider(...);
|
||||
$this->isReadableProvider = null === $isReadableProvider ? null : $isReadableProvider(...);
|
||||
$this->requireStrictFileNames = $requireStrictFileNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
|
||||
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format')
|
||||
->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())))
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command lints an XLIFF file and outputs to STDOUT
|
||||
the first encountered syntax error.
|
||||
@@ -109,7 +109,7 @@ EOF
|
||||
return $this->display($io, $filesInfo);
|
||||
}
|
||||
|
||||
private function validate(string $content, string $file = null): array
|
||||
private function validate(string $content, ?string $file = null): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
@@ -154,21 +154,17 @@ EOF
|
||||
return ['file' => $file, 'valid' => 0 === \count($errors), 'messages' => $errors];
|
||||
}
|
||||
|
||||
private function display(SymfonyStyle $io, array $files)
|
||||
private function display(SymfonyStyle $io, array $files): int
|
||||
{
|
||||
switch ($this->format) {
|
||||
case 'txt':
|
||||
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));
|
||||
}
|
||||
return match ($this->format) {
|
||||
'txt' => $this->displayTxt($io, $files),
|
||||
'json' => $this->displayJson($io, $files),
|
||||
'github' => $this->displayTxt($io, $files, true),
|
||||
default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
|
||||
};
|
||||
}
|
||||
|
||||
private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false)
|
||||
private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false): int
|
||||
{
|
||||
$countFiles = \count($filesInfo);
|
||||
$erroredFiles = 0;
|
||||
@@ -184,9 +180,7 @@ EOF
|
||||
// general document errors have a '-1' line number
|
||||
$line = -1 === $error['line'] ? null : $error['line'];
|
||||
|
||||
if ($githubReporter) {
|
||||
$githubReporter->error($error['message'], $info['file'], $line, null !== $line ? $error['column'] : null);
|
||||
}
|
||||
$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']));
|
||||
@@ -202,7 +196,7 @@ EOF
|
||||
return min($erroredFiles, 1);
|
||||
}
|
||||
|
||||
private function displayJson(SymfonyStyle $io, array $filesInfo)
|
||||
private function displayJson(SymfonyStyle $io, array $filesInfo): int
|
||||
{
|
||||
$errors = 0;
|
||||
|
||||
@@ -218,7 +212,10 @@ EOF
|
||||
return min($errors, 1);
|
||||
}
|
||||
|
||||
private function getFiles(string $fileOrDirectory)
|
||||
/**
|
||||
* @return iterable<\SplFileInfo>
|
||||
*/
|
||||
private function getFiles(string $fileOrDirectory): iterable
|
||||
{
|
||||
if (is_file($fileOrDirectory)) {
|
||||
yield new \SplFileInfo($fileOrDirectory);
|
||||
@@ -235,14 +232,15 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
private function getDirectoryIterator(string $directory)
|
||||
/**
|
||||
* @return iterable<\SplFileInfo>
|
||||
*/
|
||||
private function getDirectoryIterator(string $directory): iterable
|
||||
{
|
||||
$default = function ($directory) {
|
||||
return new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
};
|
||||
$default = fn ($directory) => new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
if (null !== $this->directoryIteratorProvider) {
|
||||
return ($this->directoryIteratorProvider)($directory, $default);
|
||||
@@ -251,11 +249,9 @@ EOF
|
||||
return $default($directory);
|
||||
}
|
||||
|
||||
private function isReadable(string $fileOrDirectory)
|
||||
private function isReadable(string $fileOrDirectory): bool
|
||||
{
|
||||
$default = function ($fileOrDirectory) {
|
||||
return is_readable($fileOrDirectory);
|
||||
};
|
||||
$default = fn ($fileOrDirectory) => is_readable($fileOrDirectory);
|
||||
|
||||
if (null !== $this->isReadableProvider) {
|
||||
return ($this->isReadableProvider)($fileOrDirectory, $default);
|
||||
@@ -278,7 +274,12 @@ EOF
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues(['txt', 'json', 'github']);
|
||||
$suggestions->suggestValues($this->getAvailableFormatOptions());
|
||||
}
|
||||
}
|
||||
|
||||
private function getAvailableFormatOptions(): array
|
||||
{
|
||||
return ['txt', 'json', 'github'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,17 +25,14 @@ use Symfony\Component\VarDumper\Cloner\Data;
|
||||
*/
|
||||
class TranslationDataCollector extends DataCollector implements LateDataCollectorInterface
|
||||
{
|
||||
private $translator;
|
||||
private DataCollectorTranslator $translator;
|
||||
|
||||
public function __construct(DataCollectorTranslator $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lateCollect()
|
||||
public function lateCollect(): void
|
||||
{
|
||||
$messages = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages());
|
||||
|
||||
@@ -45,19 +42,13 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
||||
$this->data = $this->cloneVar($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function collect(Request $request, Response $response, \Throwable $exception = null)
|
||||
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
|
||||
{
|
||||
$this->data['locale'] = $this->translator->getLocale();
|
||||
$this->data['fallback_locales'] = $this->translator->getFallbackLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function reset()
|
||||
public function reset(): void
|
||||
{
|
||||
$this->data = [];
|
||||
}
|
||||
@@ -82,7 +73,7 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
||||
return $this->data[DataCollectorTranslator::MESSAGE_DEFINED] ?? 0;
|
||||
}
|
||||
|
||||
public function getLocale()
|
||||
public function getLocale(): ?string
|
||||
{
|
||||
return !empty($this->data['locale']) ? $this->data['locale'] : null;
|
||||
}
|
||||
@@ -90,20 +81,17 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getFallbackLocales()
|
||||
public function getFallbackLocales(): Data|array
|
||||
{
|
||||
return (isset($this->data['fallback_locales']) && \count($this->data['fallback_locales']) > 0) ? $this->data['fallback_locales'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'translation';
|
||||
}
|
||||
|
||||
private function sanitizeCollectedMessages(array $messages)
|
||||
private function sanitizeCollectedMessages(array $messages): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($messages as $key => $message) {
|
||||
@@ -128,7 +116,7 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function computeCount(array $messages)
|
||||
private function computeCount(array $messages): array
|
||||
{
|
||||
$count = [
|
||||
DataCollectorTranslator::MESSAGE_DEFINED => 0,
|
||||
@@ -143,7 +131,7 @@ class TranslationDataCollector extends DataCollector implements LateDataCollecto
|
||||
return $count;
|
||||
}
|
||||
|
||||
private function sanitizeString(string $string, int $length = 80)
|
||||
private function sanitizeString(string $string, int $length = 80): string
|
||||
{
|
||||
$string = trim(preg_replace('/\s+/', ' ', $string));
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
public const MESSAGE_MISSING = 1;
|
||||
public const MESSAGE_EQUALS_FALLBACK = 2;
|
||||
|
||||
private $translator;
|
||||
private TranslatorInterface $translator;
|
||||
private array $messages = [];
|
||||
|
||||
/**
|
||||
@@ -40,10 +40,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string
|
||||
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);
|
||||
@@ -52,46 +49,32 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function setLocale(string $locale)
|
||||
{
|
||||
$this->translator->setLocale($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->translator->getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface
|
||||
public function getCatalogue(?string $locale = null): MessageCatalogueInterface
|
||||
{
|
||||
return $this->translator->getCatalogue($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogues(): array
|
||||
{
|
||||
return $this->translator->getCatalogues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function warmUp(string $cacheDir): array
|
||||
public function warmUp(string $cacheDir, ?string $buildDir = null): array
|
||||
{
|
||||
if ($this->translator instanceof WarmableInterface) {
|
||||
return (array) $this->translator->warmUp($cacheDir);
|
||||
return (array) $this->translator->warmUp($cacheDir, $buildDir);
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -110,7 +93,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes through all unknown calls onto the translator object.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $method, array $args)
|
||||
{
|
||||
@@ -122,11 +105,9 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
private function collectMessage(?string $locale, ?string $domain, string $id, string $translation, ?array $parameters = [])
|
||||
private function collectMessage(?string $locale, ?string $domain, string $id, string $translation, ?array $parameters = []): void
|
||||
{
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
}
|
||||
$domain ??= 'messages';
|
||||
|
||||
$catalogue = $this->translator->getCatalogue($locale);
|
||||
$locale = $catalogue->getLocale();
|
||||
|
||||
@@ -20,6 +20,9 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
*/
|
||||
class TranslationDumperPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('translation.writer')) {
|
||||
|
||||
@@ -21,6 +21,9 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
*/
|
||||
class TranslationExtractorPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('translation.extractor')) {
|
||||
|
||||
@@ -18,6 +18,9 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class TranslatorPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('translator.default')) {
|
||||
@@ -49,6 +52,23 @@ class TranslatorPass implements CompilerPassInterface
|
||||
->replaceArgument(3, $loaders)
|
||||
;
|
||||
|
||||
if ($container->hasDefinition('validator') && $container->hasDefinition('translation.extractor.visitor.constraint')) {
|
||||
$constraintVisitorDefinition = $container->getDefinition('translation.extractor.visitor.constraint');
|
||||
$constraintClassNames = [];
|
||||
|
||||
foreach ($container->getDefinitions() as $definition) {
|
||||
if (!$definition->hasTag('validator.constraint_validator')) {
|
||||
continue;
|
||||
}
|
||||
// Resolve constraint validator FQCN even if defined as %foo.validator.class% parameter
|
||||
$className = $container->getParameterBag()->resolveValue($definition->getClass());
|
||||
// Extraction of the constraint class name from the Constraint Validator FQCN
|
||||
$constraintClassNames[] = str_replace('Validator', '', substr(strrchr($className, '\\'), 1));
|
||||
}
|
||||
|
||||
$constraintVisitorDefinition->setArgument(0, $constraintClassNames);
|
||||
}
|
||||
|
||||
if (!$container->hasParameter('twig.default_path')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,12 +16,15 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver;
|
||||
|
||||
/**
|
||||
* @author Yonel Ceruto <yonelceruto@gmail.com>
|
||||
*/
|
||||
class TranslatorPathsPass extends AbstractRecursivePass
|
||||
{
|
||||
protected bool $skipScalars = true;
|
||||
|
||||
private int $level = 0;
|
||||
|
||||
/**
|
||||
@@ -39,6 +42,9 @@ class TranslatorPathsPass extends AbstractRecursivePass
|
||||
*/
|
||||
private array $controllers = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('translator')) {
|
||||
@@ -120,28 +126,20 @@ class TranslatorPathsPass extends AbstractRecursivePass
|
||||
|
||||
private function findControllerArguments(ContainerBuilder $container): array
|
||||
{
|
||||
if ($container->hasDefinition('argument_resolver.service')) {
|
||||
$argument = $container->getDefinition('argument_resolver.service')->getArgument(0);
|
||||
if ($argument instanceof Reference) {
|
||||
$argument = $container->getDefinition($argument);
|
||||
}
|
||||
if (!$container->has('argument_resolver.service')) {
|
||||
return [];
|
||||
}
|
||||
$resolverDef = $container->findDefinition('argument_resolver.service');
|
||||
|
||||
return $argument->getArgument(0);
|
||||
if (TraceableValueResolver::class === $resolverDef->getClass()) {
|
||||
$resolverDef = $container->getDefinition($resolverDef->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);
|
||||
}
|
||||
$argument = $argument->getArgument(0);
|
||||
if ($argument instanceof Reference) {
|
||||
$argument = $container->getDefinition($argument);
|
||||
}
|
||||
|
||||
return $argument->getArgument(0);
|
||||
$argument = $resolverDef->getArgument(0);
|
||||
if ($argument instanceof Reference) {
|
||||
$argument = $container->getDefinition($argument);
|
||||
}
|
||||
|
||||
return [];
|
||||
return $argument->getArgument(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,6 @@ class CsvFileDumper extends FileDumper
|
||||
private string $delimiter = ';';
|
||||
private string $enclosure = '"';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$handle = fopen('php://memory', 'r+');
|
||||
@@ -43,6 +40,8 @@ class CsvFileDumper extends FileDumper
|
||||
|
||||
/**
|
||||
* Sets the delimiter and escape character for CSV.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCsvControl(string $delimiter = ';', string $enclosure = '"')
|
||||
{
|
||||
@@ -50,9 +49,6 @@ class CsvFileDumper extends FileDumper
|
||||
$this->enclosure = $enclosure;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'csv';
|
||||
|
||||
@@ -25,6 +25,8 @@ interface DumperInterface
|
||||
* Dumps the message catalogue.
|
||||
*
|
||||
* @param array $options Options that are used by the dumper
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dump(MessageCatalogue $messages, array $options = []);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ abstract class FileDumper implements DumperInterface
|
||||
/**
|
||||
* Sets the template for the relative paths to files.
|
||||
*
|
||||
* @param string $relativePathTemplate A template for the relative paths to files
|
||||
* @return void
|
||||
*/
|
||||
public function setRelativePathTemplate(string $relativePathTemplate)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ abstract class FileDumper implements DumperInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function dump(MessageCatalogue $messages, array $options = [])
|
||||
{
|
||||
|
||||
@@ -20,14 +20,8 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class IcuResFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $relativePathTemplate = '%domain%/%locale%.%extension%';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$data = $indexes = $resources = '';
|
||||
@@ -89,14 +83,11 @@ class IcuResFileDumper extends FileDumper
|
||||
return $padding ? str_repeat("\xAA", 4 - $padding) : null;
|
||||
}
|
||||
|
||||
private function getPosition(string $data)
|
||||
private function getPosition(string $data): float|int
|
||||
{
|
||||
return (\strlen($data) + 28) / 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'res';
|
||||
|
||||
@@ -20,9 +20,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class IniFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$output = '';
|
||||
@@ -35,9 +32,6 @@ class IniFileDumper extends FileDumper
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'ini';
|
||||
|
||||
@@ -20,9 +20,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class JsonFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$flags = $options['json_encoding'] ?? \JSON_PRETTY_PRINT;
|
||||
@@ -30,9 +27,6 @@ class JsonFileDumper extends FileDumper
|
||||
return json_encode($messages->all($domain), $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'json';
|
||||
|
||||
@@ -21,9 +21,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class MoFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$sources = $targets = $sourceOffsets = $targetOffsets = '';
|
||||
@@ -57,7 +54,7 @@ class MoFileDumper extends FileDumper
|
||||
.$this->writeLong($offset[2] + $sourcesStart + $sourcesSize);
|
||||
}
|
||||
|
||||
$output = implode('', array_map([$this, 'writeLong'], $header))
|
||||
$output = implode('', array_map($this->writeLong(...), $header))
|
||||
.$sourceOffsets
|
||||
.$targetOffsets
|
||||
.$sources
|
||||
@@ -67,9 +64,6 @@ class MoFileDumper extends FileDumper
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'mo';
|
||||
|
||||
@@ -20,17 +20,11 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class PhpFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
return "<?php\n\nreturn ".var_export($messages->all($domain), true).";\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'php';
|
||||
|
||||
@@ -20,9 +20,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class PoFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$output = 'msgid ""'."\n";
|
||||
@@ -68,7 +65,7 @@ class PoFileDumper extends FileDumper
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function getStandardRules(string $id)
|
||||
private function getStandardRules(string $id): array
|
||||
{
|
||||
// Partly copied from TranslatorTrait::trans.
|
||||
$parts = [];
|
||||
@@ -111,9 +108,6 @@ EOF;
|
||||
return $standardRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'po';
|
||||
|
||||
@@ -20,9 +20,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class QtFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||
@@ -51,9 +48,6 @@ class QtFileDumper extends FileDumper
|
||||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'ts';
|
||||
|
||||
@@ -21,9 +21,11 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class XliffFileDumper extends FileDumper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(
|
||||
private string $extension = 'xlf',
|
||||
) {
|
||||
}
|
||||
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
$xliffVersion = '1.2';
|
||||
@@ -47,15 +49,12 @@ class XliffFileDumper extends FileDumper
|
||||
throw new InvalidArgumentException(sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return 'xlf';
|
||||
return $this->extension;
|
||||
}
|
||||
|
||||
private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = [])
|
||||
private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = []): string
|
||||
{
|
||||
$toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony'];
|
||||
if (\array_key_exists('tool_info', $options)) {
|
||||
@@ -81,6 +80,15 @@ class XliffFileDumper extends FileDumper
|
||||
$xliffTool->setAttribute($id, $value);
|
||||
}
|
||||
|
||||
if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) {
|
||||
$xliffPropGroup = $xliffHead->appendChild($dom->createElement('prop-group'));
|
||||
foreach ($catalogueMetadata as $key => $value) {
|
||||
$xliffProp = $xliffPropGroup->appendChild($dom->createElement('prop'));
|
||||
$xliffProp->setAttribute('prop-type', $key);
|
||||
$xliffProp->appendChild($dom->createTextNode($value));
|
||||
}
|
||||
}
|
||||
|
||||
$xliffBody = $xliffFile->appendChild($dom->createElement('body'));
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$translation = $dom->createElement('trans-unit');
|
||||
@@ -129,7 +137,7 @@ class XliffFileDumper extends FileDumper
|
||||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain)
|
||||
private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain): string
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||
$dom->formatOutput = true;
|
||||
@@ -147,6 +155,16 @@ class XliffFileDumper extends FileDumper
|
||||
$xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale());
|
||||
}
|
||||
|
||||
if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) {
|
||||
$xliff->setAttribute('xmlns:m', 'urn:oasis:names:tc:xliff:metadata:2.0');
|
||||
$xliffMetadata = $xliffFile->appendChild($dom->createElement('m:metadata'));
|
||||
foreach ($catalogueMetadata as $key => $value) {
|
||||
$xliffMeta = $xliffMetadata->appendChild($dom->createElement('prop'));
|
||||
$xliffMeta->setAttribute('type', $key);
|
||||
$xliffMeta->appendChild($dom->createTextNode($value));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($messages->all($domain) as $source => $target) {
|
||||
$translation = $dom->createElement('unit');
|
||||
$translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._'));
|
||||
@@ -196,7 +214,7 @@ class XliffFileDumper extends FileDumper
|
||||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
private function hasMetadataArrayInfo(string $key, array $metadata = null): bool
|
||||
private function hasMetadataArrayInfo(string $key, ?array $metadata = null): bool
|
||||
{
|
||||
return is_iterable($metadata[$key] ?? null);
|
||||
}
|
||||
|
||||
@@ -30,9 +30,6 @@ class YamlFileDumper extends FileDumper
|
||||
$this->extension = $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string
|
||||
{
|
||||
if (!class_exists(Yaml::class)) {
|
||||
@@ -52,9 +49,6 @@ class YamlFileDumper extends FileDumper
|
||||
return Yaml::dump($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtension(): string
|
||||
{
|
||||
return $this->extension;
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Symfony\Component\Translation\Exception;
|
||||
|
||||
class IncompleteDsnException extends InvalidArgumentException
|
||||
{
|
||||
public function __construct(string $message, string $dsn = null, \Throwable $previous = null)
|
||||
public function __construct(string $message, ?string $dsn = null, ?\Throwable $previous = null)
|
||||
{
|
||||
if ($dsn) {
|
||||
$message = sprintf('Invalid "%s" provider DSN: ', $dsn).$message;
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Symfony\Component\Translation\Exception;
|
||||
*/
|
||||
class MissingRequiredOptionException extends IncompleteDsnException
|
||||
{
|
||||
public function __construct(string $option, string $dsn = null, \Throwable $previous = null)
|
||||
public function __construct(string $option, ?string $dsn = null, ?\Throwable $previous = null)
|
||||
{
|
||||
$message = sprintf('The option "%s" is required but missing.', $option);
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
*/
|
||||
class ProviderException extends RuntimeException implements ProviderExceptionInterface
|
||||
{
|
||||
private $response;
|
||||
private ResponseInterface $response;
|
||||
private string $debug;
|
||||
|
||||
public function __construct(string $message, ResponseInterface $response, int $code = 0, \Exception $previous = null)
|
||||
public function __construct(string $message, ResponseInterface $response, int $code = 0, ?\Exception $previous = null)
|
||||
{
|
||||
$this->response = $response;
|
||||
$this->debug = $response->getInfo('debug') ?? '';
|
||||
|
||||
@@ -29,9 +29,13 @@ class UnsupportedSchemeException extends LogicException
|
||||
'class' => Bridge\Lokalise\LokaliseProviderFactory::class,
|
||||
'package' => 'symfony/lokalise-translation-provider',
|
||||
],
|
||||
'phrase' => [
|
||||
'class' => Bridge\Phrase\PhraseProviderFactory::class,
|
||||
'package' => 'symfony/phrase-translation-provider',
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct(Dsn $dsn, string $name = null, array $supported = [])
|
||||
public function __construct(Dsn $dsn, ?string $name = null, array $supported = [])
|
||||
{
|
||||
$provider = $dsn->getScheme();
|
||||
if (false !== $pos = strpos($provider, '+')) {
|
||||
@@ -39,7 +43,7 @@ class UnsupportedSchemeException extends LogicException
|
||||
}
|
||||
$package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null;
|
||||
if ($package && !class_exists($package['class'])) {
|
||||
parent::__construct(sprintf('Unable to synchronize translations via "%s" as the provider is not installed; try running "composer require %s".', $provider, $package['package']));
|
||||
parent::__construct(sprintf('Unable to synchronize translations via "%s" as the provider is not installed. Try running "composer require %s".', $provider, $package['package']));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ class ChainExtractor implements ExtractorInterface
|
||||
|
||||
/**
|
||||
* Adds a loader to the translation extractor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addExtractor(string $format, ExtractorInterface $extractor)
|
||||
{
|
||||
@@ -36,7 +38,7 @@ class ChainExtractor implements ExtractorInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function setPrefix(string $prefix)
|
||||
{
|
||||
@@ -46,7 +48,7 @@ class ChainExtractor implements ExtractorInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function extract(string|iterable $directory, MessageCatalogue $catalogue)
|
||||
{
|
||||
|
||||
@@ -25,11 +25,15 @@ interface ExtractorInterface
|
||||
* Extracts translation messages from files, a file or a directory to the catalogue.
|
||||
*
|
||||
* @param string|iterable<string> $resource Files, a file or a directory
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function extract(string|iterable $resource, MessageCatalogue $catalogue);
|
||||
|
||||
/**
|
||||
* Sets the prefix that should be used for new found messages.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPrefix(string $prefix);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\Translation\Extractor;
|
||||
|
||||
trigger_deprecation('symfony/translation', '6.2', '"%s" is deprecated, use "%s" instead.', PhpExtractor::class, PhpAstExtractor::class);
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
|
||||
@@ -18,6 +20,8 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
* PhpExtractor extracts translation messages from a PHP template.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*
|
||||
* @deprecated since Symfony 6.2, use the PhpAstExtractor instead
|
||||
*/
|
||||
class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
{
|
||||
@@ -129,7 +133,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function extract(string|iterable $resource, MessageCatalogue $catalog)
|
||||
{
|
||||
@@ -142,7 +146,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function setPrefix(string $prefix)
|
||||
{
|
||||
@@ -164,7 +168,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
/**
|
||||
* Seeks to a non-whitespace token.
|
||||
*/
|
||||
private function seekToNextRelevantToken(\Iterator $tokenIterator)
|
||||
private function seekToNextRelevantToken(\Iterator $tokenIterator): void
|
||||
{
|
||||
for (; $tokenIterator->valid(); $tokenIterator->next()) {
|
||||
$t = $tokenIterator->current();
|
||||
@@ -174,7 +178,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function skipMethodArgument(\Iterator $tokenIterator)
|
||||
private function skipMethodArgument(\Iterator $tokenIterator): void
|
||||
{
|
||||
$openBraces = 0;
|
||||
|
||||
@@ -199,7 +203,7 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
* Extracts the message from the iterator while the tokens
|
||||
* match allowed message tokens.
|
||||
*/
|
||||
private function getValue(\Iterator $tokenIterator)
|
||||
private function getValue(\Iterator $tokenIterator): string
|
||||
{
|
||||
$message = '';
|
||||
$docToken = '';
|
||||
@@ -257,6 +261,8 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
|
||||
/**
|
||||
* Extracts trans message from PHP tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function parseTokens(array $tokens, MessageCatalogue $catalog, string $filename)
|
||||
{
|
||||
@@ -314,9 +320,6 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||
return $this->isFile($file) && 'php' === pathinfo($file, \PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function extractFromDirectory(string|array $directory): iterable
|
||||
{
|
||||
if (!class_exists(Finder::class)) {
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\Translation\Extractor;
|
||||
|
||||
trigger_deprecation('symfony/translation', '6.2', '"%s" is deprecated.', PhpStringTokenParser::class);
|
||||
|
||||
/*
|
||||
* The following is derived from code at http://github.com/nikic/PHP-Parser
|
||||
*
|
||||
@@ -47,6 +49,9 @@ namespace Symfony\Component\Translation\Extractor;
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 6.2
|
||||
*/
|
||||
class PhpStringTokenParser
|
||||
{
|
||||
protected static $replacements = [
|
||||
@@ -89,7 +94,7 @@ class PhpStringTokenParser
|
||||
* @param string $str String without quotes
|
||||
* @param string|null $quote Quote type
|
||||
*/
|
||||
public static function parseEscapeSequences(string $str, string $quote = null): string
|
||||
public static function parseEscapeSequences(string $str, ?string $quote = null): string
|
||||
{
|
||||
if (null !== $quote) {
|
||||
$str = str_replace('\\'.$quote, $quote, $str);
|
||||
|
||||
@@ -20,12 +20,9 @@ use Symfony\Component\Translation\Exception\LogicException;
|
||||
*/
|
||||
class IntlFormatter implements IntlFormatterInterface
|
||||
{
|
||||
private $hasMessageFormatter;
|
||||
private $cache = [];
|
||||
private bool $hasMessageFormatter;
|
||||
private array $cache = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatIntl(string $message, string $locale, array $parameters = []): string
|
||||
{
|
||||
// MessageFormatter constructor throws an exception if the message is empty
|
||||
@@ -34,7 +31,7 @@ class IntlFormatter implements IntlFormatterInterface
|
||||
}
|
||||
|
||||
if (!$formatter = $this->cache[$locale][$message] ?? null) {
|
||||
if (!($this->hasMessageFormatter ?? $this->hasMessageFormatter = class_exists(\MessageFormatter::class))) {
|
||||
if (!$this->hasMessageFormatter ??= class_exists(\MessageFormatter::class)) {
|
||||
throw new LogicException('Cannot parse message translation: please install the "intl" PHP extension or the "symfony/polyfill-intl-messageformatter" package.');
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -22,33 +22,23 @@ class_exists(IntlFormatter::class);
|
||||
*/
|
||||
class MessageFormatter implements MessageFormatterInterface, IntlFormatterInterface
|
||||
{
|
||||
private $translator;
|
||||
private $intlFormatter;
|
||||
private TranslatorInterface $translator;
|
||||
private IntlFormatterInterface $intlFormatter;
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface|null $translator An identity translator to use as selector for pluralization
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator = null, IntlFormatterInterface $intlFormatter = null)
|
||||
public function __construct(?TranslatorInterface $translator = null, ?IntlFormatterInterface $intlFormatter = null)
|
||||
{
|
||||
$this->translator = $translator ?? new IdentityTranslator();
|
||||
$this->intlFormatter = $intlFormatter ?? new IntlFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(string $message, string $locale, array $parameters = []): string
|
||||
{
|
||||
if ($this->translator instanceof TranslatorInterface) {
|
||||
return $this->translator->trans($message, $parameters, null, $locale);
|
||||
}
|
||||
|
||||
return strtr($message, $parameters);
|
||||
return $this->translator->trans($message, $parameters, null, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatIntl(string $message, string $locale, array $parameters = []): string
|
||||
{
|
||||
return $this->intlFormatter->formatIntl($message, $locale, $parameters);
|
||||
|
||||
2
vendor/symfony/translation/LICENSE
vendored
2
vendor/symfony/translation/LICENSE
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2023 Fabien Potencier
|
||||
Copyright (c) 2004-present Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -20,9 +20,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class ArrayLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
|
||||
{
|
||||
$resource = $this->flatten($resource);
|
||||
@@ -46,9 +43,11 @@ class ArrayLoader implements LoaderInterface
|
||||
foreach ($messages as $key => $value) {
|
||||
if (\is_array($value)) {
|
||||
foreach ($this->flatten($value) as $k => $v) {
|
||||
$result[$key.'.'.$k] = $v;
|
||||
if (null !== $v) {
|
||||
$result[$key.'.'.$k] = $v;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} elseif (null !== $value) {
|
||||
$result[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,8 @@ class CsvFileLoader extends FileLoader
|
||||
{
|
||||
private string $delimiter = ';';
|
||||
private string $enclosure = '"';
|
||||
private string $escape = '\\';
|
||||
private string $escape = '';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
$messages = [];
|
||||
@@ -45,7 +42,7 @@ class CsvFileLoader extends FileLoader
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('#' !== substr($data[0], 0, 1) && isset($data[1]) && 2 === \count($data)) {
|
||||
if (!str_starts_with($data[0], '#') && isset($data[1]) && 2 === \count($data)) {
|
||||
$messages[$data[0]] = $data[1];
|
||||
}
|
||||
}
|
||||
@@ -55,8 +52,10 @@ class CsvFileLoader extends FileLoader
|
||||
|
||||
/**
|
||||
* Sets the delimiter, enclosure, and escape character for CSV.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCsvControl(string $delimiter = ';', string $enclosure = '"', string $escape = '\\')
|
||||
public function setCsvControl(string $delimiter = ';', string $enclosure = '"', string $escape = '')
|
||||
{
|
||||
$this->delimiter = $delimiter;
|
||||
$this->enclosure = $enclosure;
|
||||
|
||||
@@ -21,9 +21,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
abstract class FileLoader extends ArrayLoader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
@@ -37,9 +34,7 @@ abstract class FileLoader extends ArrayLoader
|
||||
$messages = $this->loadResource($resource);
|
||||
|
||||
// empty resource
|
||||
if (null === $messages) {
|
||||
$messages = [];
|
||||
}
|
||||
$messages ??= [];
|
||||
|
||||
// not an array
|
||||
if (!\is_array($messages)) {
|
||||
|
||||
@@ -23,9 +23,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class IcuDatFileLoader extends IcuResFileLoader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
|
||||
{
|
||||
if (!stream_is_local($resource.'.dat')) {
|
||||
@@ -38,7 +35,7 @@ class IcuDatFileLoader extends IcuResFileLoader
|
||||
|
||||
try {
|
||||
$rb = new \ResourceBundle($locale, $resource);
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Exception) {
|
||||
$rb = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class IcuResFileLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
|
||||
{
|
||||
if (!stream_is_local($resource)) {
|
||||
@@ -38,7 +35,7 @@ class IcuResFileLoader implements LoaderInterface
|
||||
|
||||
try {
|
||||
$rb = new \ResourceBundle($locale, $resource);
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Exception) {
|
||||
$rb = null;
|
||||
}
|
||||
|
||||
@@ -71,9 +68,9 @@ 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
|
||||
* @param string|null $path Current path being parsed, used internally for recursive calls
|
||||
*/
|
||||
protected function flatten(\ResourceBundle $rb, array &$messages = [], string $path = null): array
|
||||
protected function flatten(\ResourceBundle $rb, array &$messages = [], ?string $path = null): array
|
||||
{
|
||||
foreach ($rb as $key => $value) {
|
||||
$nodePath = $path ? $path.'.'.$key : $key;
|
||||
|
||||
@@ -18,9 +18,6 @@ namespace Symfony\Component\Translation\Loader;
|
||||
*/
|
||||
class IniFileLoader extends FileLoader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
return parse_ini_file($resource, true);
|
||||
|
||||
@@ -20,9 +20,6 @@ use Symfony\Component\Translation\Exception\InvalidResourceException;
|
||||
*/
|
||||
class JsonFileLoader extends FileLoader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
$messages = [];
|
||||
@@ -42,19 +39,13 @@ class JsonFileLoader extends FileLoader
|
||||
*/
|
||||
private function getJSONErrorMessage(int $errorCode): string
|
||||
{
|
||||
switch ($errorCode) {
|
||||
case \JSON_ERROR_DEPTH:
|
||||
return 'Maximum stack depth exceeded';
|
||||
case \JSON_ERROR_STATE_MISMATCH:
|
||||
return 'Underflow or the modes mismatch';
|
||||
case \JSON_ERROR_CTRL_CHAR:
|
||||
return 'Unexpected control character found';
|
||||
case \JSON_ERROR_SYNTAX:
|
||||
return 'Syntax error, malformed JSON';
|
||||
case \JSON_ERROR_UTF8:
|
||||
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||
default:
|
||||
return 'Unknown error';
|
||||
}
|
||||
return match ($errorCode) {
|
||||
\JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
|
||||
\JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
|
||||
\JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
|
||||
\JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
|
||||
\JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded',
|
||||
default => 'Unknown error',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,6 @@ class MoFileLoader extends FileLoader
|
||||
/**
|
||||
* Parses machine object (MO) format, independent of the machine's endian it
|
||||
* was created on. Both 32bit and 64bit systems are supported.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
|
||||
@@ -20,12 +20,9 @@ class PhpFileLoader extends FileLoader
|
||||
{
|
||||
private static ?array $cache = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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))) {
|
||||
if ([] === self::$cache && \function_exists('opcache_invalidate') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOL) && (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) || filter_var(\ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOL))) {
|
||||
self::$cache = null;
|
||||
}
|
||||
|
||||
@@ -33,10 +30,6 @@ class PhpFileLoader extends FileLoader
|
||||
return require $resource;
|
||||
}
|
||||
|
||||
if (isset(self::$cache[$resource])) {
|
||||
return self::$cache[$resource];
|
||||
}
|
||||
|
||||
return self::$cache[$resource] = require $resource;
|
||||
return self::$cache[$resource] ??= require $resource;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,6 @@ class PoFileLoader extends FileLoader
|
||||
* - Message IDs are allowed to have other encodings as just US-ASCII.
|
||||
*
|
||||
* Items with an empty id are ignored.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
@@ -83,15 +81,15 @@ class PoFileLoader extends FileLoader
|
||||
}
|
||||
$item = $defaults;
|
||||
$flags = [];
|
||||
} elseif ('#,' === substr($line, 0, 2)) {
|
||||
} elseif (str_starts_with($line, '#,')) {
|
||||
$flags = array_map('trim', explode(',', substr($line, 2)));
|
||||
} elseif ('msgid "' === substr($line, 0, 7)) {
|
||||
} elseif (str_starts_with($line, 'msgid "')) {
|
||||
// We start a new msg so save previous
|
||||
// TODO: this fails when comments or contexts are added
|
||||
$this->addMessage($messages, $item);
|
||||
$item = $defaults;
|
||||
$item['ids']['singular'] = substr($line, 7, -1);
|
||||
} elseif ('msgstr "' === substr($line, 0, 8)) {
|
||||
} elseif (str_starts_with($line, 'msgstr "')) {
|
||||
$item['translated'] = substr($line, 8, -1);
|
||||
} elseif ('"' === $line[0]) {
|
||||
$continues = isset($item['translated']) ? 'translated' : 'ids';
|
||||
@@ -102,9 +100,9 @@ class PoFileLoader extends FileLoader
|
||||
} else {
|
||||
$item[$continues] .= substr($line, 1, -1);
|
||||
}
|
||||
} elseif ('msgid_plural "' === substr($line, 0, 14)) {
|
||||
} elseif (str_starts_with($line, 'msgid_plural "')) {
|
||||
$item['ids']['plural'] = substr($line, 14, -1);
|
||||
} elseif ('msgstr[' === substr($line, 0, 7)) {
|
||||
} elseif (str_starts_with($line, 'msgstr[')) {
|
||||
$size = strpos($line, ']');
|
||||
$item['translated'][(int) substr($line, 7, 1)] = substr($line, $size + 3, -1);
|
||||
}
|
||||
@@ -124,7 +122,7 @@ class PoFileLoader extends FileLoader
|
||||
* A .po file could contain by error missing plural indexes. We need to
|
||||
* fix these before saving them.
|
||||
*/
|
||||
private function addMessage(array &$messages, array $item)
|
||||
private function addMessage(array &$messages, array $item): void
|
||||
{
|
||||
if (!empty($item['ids']['singular'])) {
|
||||
$id = stripcslashes($item['ids']['singular']);
|
||||
|
||||
@@ -25,9 +25,6 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||
*/
|
||||
class QtFileLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
|
||||
{
|
||||
if (!class_exists(XmlUtils::class)) {
|
||||
@@ -67,7 +64,6 @@ class QtFileLoader implements LoaderInterface
|
||||
$domain
|
||||
);
|
||||
}
|
||||
$translation = $translation->nextSibling;
|
||||
}
|
||||
|
||||
if (class_exists(FileResource::class)) {
|
||||
|
||||
@@ -28,9 +28,6 @@ use Symfony\Component\Translation\Util\XliffUtils;
|
||||
*/
|
||||
class XliffFileLoader implements LoaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
|
||||
{
|
||||
if (!class_exists(XmlUtils::class)) {
|
||||
@@ -75,7 +72,7 @@ class XliffFileLoader implements LoaderInterface
|
||||
return $catalogue;
|
||||
}
|
||||
|
||||
private function extract(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
|
||||
private function extract(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void
|
||||
{
|
||||
$xliffVersion = XliffUtils::getVersionNumber($dom);
|
||||
|
||||
@@ -91,7 +88,7 @@ class XliffFileLoader implements LoaderInterface
|
||||
/**
|
||||
* Extract messages and metadata from DOMDocument into a MessageCatalogue.
|
||||
*/
|
||||
private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
|
||||
private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void
|
||||
{
|
||||
$xml = simplexml_import_dom($dom);
|
||||
$encoding = $dom->encoding ? strtoupper($dom->encoding) : null;
|
||||
@@ -104,6 +101,10 @@ class XliffFileLoader implements LoaderInterface
|
||||
|
||||
$file->registerXPathNamespace('xliff', $namespace);
|
||||
|
||||
foreach ($file->xpath('.//xliff:prop') as $prop) {
|
||||
$catalogue->setCatalogueMetadata($prop->attributes()['prop-type'], (string) $prop, $domain);
|
||||
}
|
||||
|
||||
foreach ($file->xpath('.//xliff:trans-unit') as $translation) {
|
||||
$attributes = $translation->attributes();
|
||||
|
||||
@@ -111,12 +112,20 @@ class XliffFileLoader implements LoaderInterface
|
||||
continue;
|
||||
}
|
||||
|
||||
$source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;
|
||||
$source = (string) (isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source);
|
||||
|
||||
if (isset($translation->target)
|
||||
&& 'needs-translation' === (string) $translation->target->attributes()['state']
|
||||
&& \in_array((string) $translation->target, [$source, (string) $translation->source], true)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the xlf file has another encoding specified, try to convert it because
|
||||
// simple_xml will always return utf-8 encoded values
|
||||
$target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding);
|
||||
|
||||
$catalogue->set((string) $source, $target, $domain);
|
||||
$catalogue->set($source, $target, $domain);
|
||||
|
||||
$metadata = [
|
||||
'source' => (string) $translation->source,
|
||||
@@ -139,12 +148,12 @@ class XliffFileLoader implements LoaderInterface
|
||||
$metadata['id'] = (string) $attributes['id'];
|
||||
}
|
||||
|
||||
$catalogue->setMetadata((string) $source, $metadata, $domain);
|
||||
$catalogue->setMetadata($source, $metadata, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain)
|
||||
private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void
|
||||
{
|
||||
$xml = simplexml_import_dom($dom);
|
||||
$encoding = $dom->encoding ? strtoupper($dom->encoding) : null;
|
||||
@@ -190,7 +199,7 @@ class XliffFileLoader implements LoaderInterface
|
||||
/**
|
||||
* Convert a UTF8 string to the specified encoding.
|
||||
*/
|
||||
private function utf8ToCharset(string $content, string $encoding = null): string
|
||||
private function utf8ToCharset(string $content, ?string $encoding = null): string
|
||||
{
|
||||
if ('UTF-8' !== $encoding && !empty($encoding)) {
|
||||
return mb_convert_encoding($content, $encoding, 'UTF-8');
|
||||
@@ -199,7 +208,7 @@ class XliffFileLoader implements LoaderInterface
|
||||
return $content;
|
||||
}
|
||||
|
||||
private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, string $encoding = null): array
|
||||
private function parseNotesMetadata(?\SimpleXMLElement $noteElement = null, ?string $encoding = null): array
|
||||
{
|
||||
$notes = [];
|
||||
|
||||
@@ -227,6 +236,6 @@ class XliffFileLoader implements LoaderInterface
|
||||
|
||||
private function isXmlString(string $resource): bool
|
||||
{
|
||||
return 0 === strpos($resource, '<?xml');
|
||||
return str_starts_with($resource, '<?xml');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,11 @@ use Symfony\Component\Yaml\Yaml;
|
||||
*/
|
||||
class YamlFileLoader extends FileLoader
|
||||
{
|
||||
private $yamlParser;
|
||||
private YamlParser $yamlParser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadResource(string $resource): array
|
||||
{
|
||||
if (null === $this->yamlParser) {
|
||||
if (!isset($this->yamlParser)) {
|
||||
if (!class_exists(\Symfony\Component\Yaml\Parser::class)) {
|
||||
throw new LogicException('Loading translations from the YAML format requires the Symfony Yaml component.');
|
||||
}
|
||||
|
||||
30
vendor/symfony/translation/LoggingTranslator.php
vendored
30
vendor/symfony/translation/LoggingTranslator.php
vendored
@@ -21,8 +21,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
*/
|
||||
class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface
|
||||
{
|
||||
private $translator;
|
||||
private $logger;
|
||||
private TranslatorInterface $translator;
|
||||
private LoggerInterface $logger;
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator The translator must implement TranslatorBagInterface
|
||||
@@ -37,10 +37,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string
|
||||
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);
|
||||
@@ -49,7 +46,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function setLocale(string $locale)
|
||||
{
|
||||
@@ -62,25 +59,16 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
$this->logger->debug(sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->translator->getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface
|
||||
public function getCatalogue(?string $locale = null): MessageCatalogueInterface
|
||||
{
|
||||
return $this->translator->getCatalogue($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogues(): array
|
||||
{
|
||||
return $this->translator->getCatalogues();
|
||||
@@ -99,7 +87,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes through all unknown calls onto the translator object.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $method, array $args)
|
||||
{
|
||||
@@ -109,11 +97,9 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface,
|
||||
/**
|
||||
* Logs for missing translations.
|
||||
*/
|
||||
private function log(string $id, ?string $domain, ?string $locale)
|
||||
private function log(string $id, ?string $domain, ?string $locale): void
|
||||
{
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
}
|
||||
$domain ??= 'messages';
|
||||
|
||||
$catalogue = $this->translator->getCatalogue($locale);
|
||||
if ($catalogue->defines($id, $domain)) {
|
||||
|
||||
107
vendor/symfony/translation/MessageCatalogue.php
vendored
107
vendor/symfony/translation/MessageCatalogue.php
vendored
@@ -17,13 +17,14 @@ use Symfony\Component\Translation\Exception\LogicException;
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface
|
||||
class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface, CatalogueMetadataAwareInterface
|
||||
{
|
||||
private array $messages = [];
|
||||
private array $metadata = [];
|
||||
private array $catalogueMetadata = [];
|
||||
private array $resources = [];
|
||||
private string $locale;
|
||||
private $fallbackCatalogue = null;
|
||||
private ?MessageCatalogueInterface $fallbackCatalogue = null;
|
||||
private ?self $parent = null;
|
||||
|
||||
/**
|
||||
@@ -35,17 +36,11 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
$this->messages = $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDomains(): array
|
||||
{
|
||||
$domains = [];
|
||||
@@ -60,10 +55,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
return array_values($domains);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function all(string $domain = null): array
|
||||
public function all(?string $domain = null): array
|
||||
{
|
||||
if (null !== $domain) {
|
||||
// skip messages merge if intl-icu requested explicitly
|
||||
@@ -89,16 +81,13 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $id, string $translation, string $domain = 'messages')
|
||||
{
|
||||
$this->add([$id => $translation], $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has(string $id, string $domain = 'messages'): bool
|
||||
{
|
||||
if (isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {
|
||||
@@ -112,17 +101,11 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defines(string $id, string $domain = 'messages'): bool
|
||||
{
|
||||
return isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(string $id, string $domain = 'messages'): string
|
||||
{
|
||||
if (isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) {
|
||||
@@ -141,7 +124,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function replace(array $messages, string $domain = 'messages')
|
||||
{
|
||||
@@ -151,7 +134,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function add(array $messages, string $domain = 'messages')
|
||||
{
|
||||
@@ -167,7 +150,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function addCatalogue(MessageCatalogueInterface $catalogue)
|
||||
{
|
||||
@@ -191,10 +174,15 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
$metadata = $catalogue->getMetadata('', '');
|
||||
$this->addMetadata($metadata);
|
||||
}
|
||||
|
||||
if ($catalogue instanceof CatalogueMetadataAwareInterface) {
|
||||
$catalogueMetadata = $catalogue->getCatalogueMetadata('', '');
|
||||
$this->addCatalogueMetadata($catalogueMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function addFallbackCatalogue(MessageCatalogueInterface $catalogue)
|
||||
{
|
||||
@@ -225,33 +213,24 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFallbackCatalogue(): ?MessageCatalogueInterface
|
||||
{
|
||||
return $this->fallbackCatalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResources(): array
|
||||
{
|
||||
return array_values($this->resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function addResource(ResourceInterface $resource)
|
||||
{
|
||||
$this->resources[$resource->__toString()] = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata(string $key = '', string $domain = 'messages'): mixed
|
||||
{
|
||||
if ('' == $domain) {
|
||||
@@ -272,7 +251,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function setMetadata(string $key, mixed $value, string $domain = 'messages')
|
||||
{
|
||||
@@ -280,7 +259,7 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function deleteMetadata(string $key = '', string $domain = 'messages')
|
||||
{
|
||||
@@ -293,12 +272,53 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
}
|
||||
|
||||
public function getCatalogueMetadata(string $key = '', string $domain = 'messages'): mixed
|
||||
{
|
||||
if (!$domain) {
|
||||
return $this->catalogueMetadata;
|
||||
}
|
||||
|
||||
if (isset($this->catalogueMetadata[$domain])) {
|
||||
if (!$key) {
|
||||
return $this->catalogueMetadata[$domain];
|
||||
}
|
||||
|
||||
if (isset($this->catalogueMetadata[$domain][$key])) {
|
||||
return $this->catalogueMetadata[$domain][$key];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setCatalogueMetadata(string $key, mixed $value, string $domain = 'messages')
|
||||
{
|
||||
$this->catalogueMetadata[$domain][$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCatalogueMetadata(string $key = '', string $domain = 'messages')
|
||||
{
|
||||
if (!$domain) {
|
||||
$this->catalogueMetadata = [];
|
||||
} elseif (!$key) {
|
||||
unset($this->catalogueMetadata[$domain]);
|
||||
} else {
|
||||
unset($this->catalogueMetadata[$domain][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds current values with the new values.
|
||||
*
|
||||
* @param array $values Values to add
|
||||
*/
|
||||
private function addMetadata(array $values)
|
||||
private function addMetadata(array $values): void
|
||||
{
|
||||
foreach ($values as $domain => $keys) {
|
||||
foreach ($keys as $key => $value) {
|
||||
@@ -306,4 +326,13 @@ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function addCatalogueMetadata(array $values): void
|
||||
{
|
||||
foreach ($values as $domain => $keys) {
|
||||
foreach ($keys as $key => $value) {
|
||||
$this->setCatalogueMetadata($key, $value, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +36,8 @@ interface MessageCatalogueInterface
|
||||
* Gets the messages within a given domain.
|
||||
*
|
||||
* If $domain is null, it returns all messages.
|
||||
*
|
||||
* @param string $domain The domain name
|
||||
*/
|
||||
public function all(string $domain = null): array;
|
||||
public function all(?string $domain = null): array;
|
||||
|
||||
/**
|
||||
* Sets a message translation.
|
||||
@@ -47,6 +45,8 @@ interface MessageCatalogueInterface
|
||||
* @param string $id The message id
|
||||
* @param string $translation The messages translation
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $id, string $translation, string $domain = 'messages');
|
||||
|
||||
@@ -79,6 +79,8 @@ interface MessageCatalogueInterface
|
||||
*
|
||||
* @param array $messages An array of translations
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function replace(array $messages, string $domain = 'messages');
|
||||
|
||||
@@ -87,6 +89,8 @@ interface MessageCatalogueInterface
|
||||
*
|
||||
* @param array $messages An array of translations
|
||||
* @param string $domain The domain name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add(array $messages, string $domain = 'messages');
|
||||
|
||||
@@ -94,6 +98,8 @@ interface MessageCatalogueInterface
|
||||
* Merges translations from the given Catalogue into the current one.
|
||||
*
|
||||
* The two catalogues must have the same locale.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addCatalogue(self $catalogue);
|
||||
|
||||
@@ -102,6 +108,8 @@ interface MessageCatalogueInterface
|
||||
* only when the translation does not exist.
|
||||
*
|
||||
* This is used to provide default translations when they do not exist for the current locale.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addFallbackCatalogue(self $catalogue);
|
||||
|
||||
@@ -119,6 +127,8 @@ interface MessageCatalogueInterface
|
||||
|
||||
/**
|
||||
* Adds a resource for this collection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addResource(ResourceInterface $resource);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace Symfony\Component\Translation;
|
||||
|
||||
/**
|
||||
* MetadataAwareInterface.
|
||||
* This interface is used to get, set, and delete metadata about the translation messages.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
@@ -31,6 +31,8 @@ interface MetadataAwareInterface
|
||||
|
||||
/**
|
||||
* Adds metadata to a message domain.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setMetadata(string $key, mixed $value, string $domain = 'messages');
|
||||
|
||||
@@ -39,6 +41,8 @@ interface MetadataAwareInterface
|
||||
*
|
||||
* Passing an empty domain will delete all metadata. Passing an empty key will
|
||||
* delete all metadata for the given domain.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteMetadata(string $key = '', string $domain = 'messages');
|
||||
}
|
||||
|
||||
@@ -27,19 +27,11 @@ abstract class AbstractProviderFactory implements ProviderFactoryInterface
|
||||
|
||||
protected function getUser(Dsn $dsn): string
|
||||
{
|
||||
if (null === $user = $dsn->getUser()) {
|
||||
throw new IncompleteDsnException('User is not set.', $dsn->getOriginalDsn());
|
||||
}
|
||||
|
||||
return $user;
|
||||
return $dsn->getUser() ?? throw new IncompleteDsnException('User is not set.', $dsn->getScheme().'://'.$dsn->getHost());
|
||||
}
|
||||
|
||||
protected function getPassword(Dsn $dsn): string
|
||||
{
|
||||
if (null === $password = $dsn->getPassword()) {
|
||||
throw new IncompleteDsnException('Password is not set.', $dsn->getOriginalDsn());
|
||||
}
|
||||
|
||||
return $password;
|
||||
return $dsn->getPassword() ?? throw new IncompleteDsnException('Password is not set.', $dsn->getOriginalDsn());
|
||||
}
|
||||
}
|
||||
|
||||
34
vendor/symfony/translation/Provider/Dsn.php
vendored
34
vendor/symfony/translation/Provider/Dsn.php
vendored
@@ -29,29 +29,29 @@ final class Dsn
|
||||
private array $options = [];
|
||||
private string $originalDsn;
|
||||
|
||||
public function __construct(string $dsn)
|
||||
public function __construct(#[\SensitiveParameter] string $dsn)
|
||||
{
|
||||
$this->originalDsn = $dsn;
|
||||
|
||||
if (false === $parsedDsn = parse_url($dsn)) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" translation provider DSN is invalid.', $dsn));
|
||||
if (false === $params = parse_url($dsn)) {
|
||||
throw new InvalidArgumentException('The translation provider DSN is invalid.');
|
||||
}
|
||||
|
||||
if (!isset($parsedDsn['scheme'])) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" translation provider DSN must contain a scheme.', $dsn));
|
||||
if (!isset($params['scheme'])) {
|
||||
throw new InvalidArgumentException('The translation provider DSN must contain a scheme.');
|
||||
}
|
||||
$this->scheme = $parsedDsn['scheme'];
|
||||
$this->scheme = $params['scheme'];
|
||||
|
||||
if (!isset($parsedDsn['host'])) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" translation provider DSN must contain a host (use "default" by default).', $dsn));
|
||||
if (!isset($params['host'])) {
|
||||
throw new InvalidArgumentException('The translation provider DSN must contain a host (use "default" by default).');
|
||||
}
|
||||
$this->host = $parsedDsn['host'];
|
||||
$this->host = $params['host'];
|
||||
|
||||
$this->user = '' !== ($parsedDsn['user'] ?? '') ? urldecode($parsedDsn['user']) : null;
|
||||
$this->password = '' !== ($parsedDsn['pass'] ?? '') ? urldecode($parsedDsn['pass']) : null;
|
||||
$this->port = $parsedDsn['port'] ?? null;
|
||||
$this->path = $parsedDsn['path'] ?? null;
|
||||
parse_str($parsedDsn['query'] ?? '', $this->options);
|
||||
$this->user = '' !== ($params['user'] ?? '') ? rawurldecode($params['user']) : null;
|
||||
$this->password = '' !== ($params['pass'] ?? '') ? rawurldecode($params['pass']) : null;
|
||||
$this->port = $params['port'] ?? null;
|
||||
$this->path = $params['path'] ?? null;
|
||||
parse_str($params['query'] ?? '', $this->options);
|
||||
}
|
||||
|
||||
public function getScheme(): string
|
||||
@@ -74,17 +74,17 @@ final class Dsn
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function getPort(int $default = null): ?int
|
||||
public function getPort(?int $default = null): ?int
|
||||
{
|
||||
return $this->port ?? $default;
|
||||
}
|
||||
|
||||
public function getOption(string $key, mixed $default = null)
|
||||
public function getOption(string $key, mixed $default = null): mixed
|
||||
{
|
||||
return $this->options[$key] ?? $default;
|
||||
}
|
||||
|
||||
public function getRequiredOption(string $key)
|
||||
public function getRequiredOption(string $key): mixed
|
||||
{
|
||||
if (!\array_key_exists($key, $this->options) || '' === trim($this->options[$key])) {
|
||||
throw new MissingRequiredOptionException($key);
|
||||
|
||||
@@ -21,7 +21,7 @@ use Symfony\Component\Translation\TranslatorBagInterface;
|
||||
*/
|
||||
class FilteringProvider implements ProviderInterface
|
||||
{
|
||||
private $provider;
|
||||
private ProviderInterface $provider;
|
||||
private array $locales;
|
||||
private array $domains;
|
||||
|
||||
@@ -37,9 +37,6 @@ class FilteringProvider implements ProviderInterface
|
||||
return (string) $this->provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write(TranslatorBagInterface $translatorBag): void
|
||||
{
|
||||
$this->provider->write($translatorBag);
|
||||
|
||||
@@ -14,10 +14,8 @@ namespace Symfony\Component\Translation\Provider;
|
||||
use Symfony\Component\Translation\TranslatorBag;
|
||||
use Symfony\Component\Translation\TranslatorBagInterface;
|
||||
|
||||
interface ProviderInterface
|
||||
interface ProviderInterface extends \Stringable
|
||||
{
|
||||
public function __toString(): string;
|
||||
|
||||
/**
|
||||
* Translations available in the TranslatorBag only must be created.
|
||||
* Translations available in both the TranslatorBag and on the provider
|
||||
|
||||
@@ -21,7 +21,7 @@ final class TranslationProviderCollection
|
||||
/**
|
||||
* @var array<string, ProviderInterface>
|
||||
*/
|
||||
private $providers;
|
||||
private array $providers;
|
||||
|
||||
/**
|
||||
* @param array<string, ProviderInterface> $providers
|
||||
|
||||
@@ -20,7 +20,7 @@ final class PseudoLocalizationTranslator implements TranslatorInterface
|
||||
{
|
||||
private const EXPANSION_CHARACTER = '~';
|
||||
|
||||
private $translator;
|
||||
private TranslatorInterface $translator;
|
||||
private bool $accents;
|
||||
private float $expansionFactor;
|
||||
private bool $brackets;
|
||||
@@ -83,10 +83,7 @@ final class PseudoLocalizationTranslator implements TranslatorInterface
|
||||
$this->localizableHTMLAttributes = $options['localizable_html_attributes'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string
|
||||
public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
|
||||
{
|
||||
$trans = '';
|
||||
$visibleText = '';
|
||||
@@ -123,7 +120,7 @@ final class PseudoLocalizationTranslator implements TranslatorInterface
|
||||
return [[true, true, $originalTrans]];
|
||||
}
|
||||
|
||||
$html = mb_encode_numericentity($originalTrans, [0x80, 0xFFFF, 0, 0xFFFF], mb_detect_encoding($originalTrans, null, true) ?: 'UTF-8');
|
||||
$html = mb_encode_numericentity($originalTrans, [0x80, 0x10FFFF, 0, 0x1FFFFF], mb_detect_encoding($originalTrans, null, true) ?: 'UTF-8');
|
||||
|
||||
$useInternalErrors = libxml_use_internal_errors(true);
|
||||
|
||||
|
||||
12
vendor/symfony/translation/README.md
vendored
12
vendor/symfony/translation/README.md
vendored
@@ -26,12 +26,7 @@ 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!
|
||||
Help Symfony by [sponsoring][1] its development!
|
||||
|
||||
Resources
|
||||
---------
|
||||
@@ -42,7 +37,4 @@ Resources
|
||||
[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
|
||||
[1]: https://symfony.com/sponsor
|
||||
|
||||
@@ -33,6 +33,8 @@ class TranslationReader implements TranslationReaderInterface
|
||||
* Adds a loader to the translation extractor.
|
||||
*
|
||||
* @param string $format The format of the loader
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addLoader(string $format, LoaderInterface $loader)
|
||||
{
|
||||
@@ -40,7 +42,7 @@ class TranslationReader implements TranslationReaderInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function read(string $directory, MessageCatalogue $catalogue)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,8 @@ interface TranslationReaderInterface
|
||||
{
|
||||
/**
|
||||
* Reads translation messages from a directory to the catalogue.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function read(string $directory, MessageCatalogue $catalogue);
|
||||
}
|
||||
|
||||
@@ -87,19 +87,15 @@ foreach ($config['original_files'] as $originalFilePath) {
|
||||
$translationFilePaths = findTranslationFiles($originalFilePath, $config['locale_to_analyze']);
|
||||
$translationStatus = calculateTranslationStatus($originalFilePath, $translationFilePaths);
|
||||
|
||||
$totalMissingTranslations += array_sum(array_map(function ($translation) {
|
||||
return count($translation['missingKeys']);
|
||||
}, array_values($translationStatus)));
|
||||
$totalTranslationMismatches += array_sum(array_map(function ($translation) {
|
||||
return count($translation['mismatches']);
|
||||
}, array_values($translationStatus)));
|
||||
$totalMissingTranslations += array_sum(array_map(fn ($translation) => count($translation['missingKeys']), array_values($translationStatus)));
|
||||
$totalTranslationMismatches += array_sum(array_map(fn ($translation) => count($translation['mismatches']), array_values($translationStatus)));
|
||||
|
||||
printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output'], $config['include_completed_languages']);
|
||||
}
|
||||
|
||||
exit($totalTranslationMismatches > 0 ? 1 : 0);
|
||||
|
||||
function findTranslationFiles($originalFilePath, $localeToAnalyze)
|
||||
function findTranslationFiles($originalFilePath, $localeToAnalyze): array
|
||||
{
|
||||
$translations = [];
|
||||
|
||||
@@ -122,7 +118,7 @@ function findTranslationFiles($originalFilePath, $localeToAnalyze)
|
||||
return $translations;
|
||||
}
|
||||
|
||||
function calculateTranslationStatus($originalFilePath, $translationFilePaths)
|
||||
function calculateTranslationStatus($originalFilePath, $translationFilePaths): array
|
||||
{
|
||||
$translationStatus = [];
|
||||
$allTranslationKeys = extractTranslationKeys($originalFilePath);
|
||||
@@ -163,14 +159,14 @@ function extractLocaleFromFilePath($filePath)
|
||||
return $parts[count($parts) - 2];
|
||||
}
|
||||
|
||||
function extractTranslationKeys($filePath)
|
||||
function extractTranslationKeys($filePath): array
|
||||
{
|
||||
$translationKeys = [];
|
||||
$contents = new \SimpleXMLElement(file_get_contents($filePath));
|
||||
$contents = new SimpleXMLElement(file_get_contents($filePath));
|
||||
|
||||
foreach ($contents->file->body->{'trans-unit'} as $translationKey) {
|
||||
$translationId = (string) $translationKey['id'];
|
||||
$translationKey = (string) $translationKey->source;
|
||||
$translationKey = (string) ($translationKey['resname'] ?? $translationKey->source);
|
||||
|
||||
$translationKeys[$translationId] = $translationKey;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"en_GM": "en_001",
|
||||
"en_GY": "en_001",
|
||||
"en_HK": "en_001",
|
||||
"en_ID": "en_001",
|
||||
"en_IE": "en_001",
|
||||
"en_IL": "en_001",
|
||||
"en_IM": "en_001",
|
||||
|
||||
@@ -15,7 +15,7 @@ if (!\function_exists(t::class)) {
|
||||
/**
|
||||
* @author Nate Wiebe <nate@northern.co>
|
||||
*/
|
||||
function t(string $message, array $parameters = [], string $domain = null): TranslatableMessage
|
||||
function t(string $message, array $parameters = [], ?string $domain = null): TranslatableMessage
|
||||
{
|
||||
return new TranslatableMessage($message, $parameters, $domain);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Translation\Test;
|
||||
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\MockHttpClient;
|
||||
@@ -20,39 +21,39 @@ use Symfony\Component\Translation\Exception\UnsupportedSchemeException;
|
||||
use Symfony\Component\Translation\Loader\LoaderInterface;
|
||||
use Symfony\Component\Translation\Provider\Dsn;
|
||||
use Symfony\Component\Translation\Provider\ProviderFactoryInterface;
|
||||
use Symfony\Component\Translation\TranslatorBagInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
/**
|
||||
* A test case to ease testing a translation provider factory.
|
||||
*
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class ProviderFactoryTestCase extends TestCase
|
||||
{
|
||||
protected $client;
|
||||
protected $logger;
|
||||
protected HttpClientInterface $client;
|
||||
protected LoggerInterface|MockObject $logger;
|
||||
protected string $defaultLocale;
|
||||
protected $loader;
|
||||
protected $xliffFileDumper;
|
||||
protected LoaderInterface|MockObject $loader;
|
||||
protected XliffFileDumper|MockObject $xliffFileDumper;
|
||||
protected TranslatorBagInterface|MockObject $translatorBag;
|
||||
|
||||
abstract public function createFactory(): ProviderFactoryInterface;
|
||||
|
||||
/**
|
||||
* @return iterable<array{0: bool, 1: string}>
|
||||
*/
|
||||
abstract public function supportsProvider(): iterable;
|
||||
abstract public static function supportsProvider(): iterable;
|
||||
|
||||
/**
|
||||
* @return iterable<array{0: string, 1: string, 2: TransportInterface}>
|
||||
* @return iterable<array{0: string, 1: string}>
|
||||
*/
|
||||
abstract public function createProvider(): iterable;
|
||||
abstract public static function createProvider(): iterable;
|
||||
|
||||
/**
|
||||
* @return iterable<array{0: string, 1: string|null}>
|
||||
*/
|
||||
public function unsupportedSchemeProvider(): iterable
|
||||
public static function unsupportedSchemeProvider(): iterable
|
||||
{
|
||||
return [];
|
||||
}
|
||||
@@ -60,7 +61,7 @@ abstract class ProviderFactoryTestCase extends TestCase
|
||||
/**
|
||||
* @return iterable<array{0: string, 1: string|null}>
|
||||
*/
|
||||
public function incompleteDsnProvider(): iterable
|
||||
public static function incompleteDsnProvider(): iterable
|
||||
{
|
||||
return [];
|
||||
}
|
||||
@@ -89,7 +90,7 @@ abstract class ProviderFactoryTestCase extends TestCase
|
||||
/**
|
||||
* @dataProvider unsupportedSchemeProvider
|
||||
*/
|
||||
public function testUnsupportedSchemeException(string $dsn, string $message = null)
|
||||
public function testUnsupportedSchemeException(string $dsn, ?string $message = null)
|
||||
{
|
||||
$factory = $this->createFactory();
|
||||
|
||||
@@ -106,7 +107,7 @@ abstract class ProviderFactoryTestCase extends TestCase
|
||||
/**
|
||||
* @dataProvider incompleteDsnProvider
|
||||
*/
|
||||
public function testIncompleteDsnException(string $dsn, string $message = null)
|
||||
public function testIncompleteDsnException(string $dsn, ?string $message = null)
|
||||
{
|
||||
$factory = $this->createFactory();
|
||||
|
||||
@@ -144,4 +145,9 @@ abstract class ProviderFactoryTestCase extends TestCase
|
||||
{
|
||||
return $this->xliffFileDumper ??= $this->createMock(XliffFileDumper::class);
|
||||
}
|
||||
|
||||
protected function getTranslatorBag(): TranslatorBagInterface
|
||||
{
|
||||
return $this->translatorBag ??= $this->createMock(TranslatorBagInterface::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,35 +11,36 @@
|
||||
|
||||
namespace Symfony\Component\Translation\Test;
|
||||
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\MockHttpClient;
|
||||
use Symfony\Component\Translation\Dumper\XliffFileDumper;
|
||||
use Symfony\Component\Translation\Loader\LoaderInterface;
|
||||
use Symfony\Component\Translation\Provider\ProviderInterface;
|
||||
use Symfony\Component\Translation\TranslatorBagInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
/**
|
||||
* A test case to ease testing a translation provider.
|
||||
*
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class ProviderTestCase extends TestCase
|
||||
{
|
||||
protected $client;
|
||||
protected $logger;
|
||||
protected HttpClientInterface $client;
|
||||
protected LoggerInterface|MockObject $logger;
|
||||
protected string $defaultLocale;
|
||||
protected $loader;
|
||||
protected $xliffFileDumper;
|
||||
protected LoaderInterface|MockObject $loader;
|
||||
protected XliffFileDumper|MockObject $xliffFileDumper;
|
||||
protected TranslatorBagInterface|MockObject $translatorBag;
|
||||
|
||||
abstract public function createProvider(HttpClientInterface $client, LoaderInterface $loader, LoggerInterface $logger, string $defaultLocale, string $endpoint): ProviderInterface;
|
||||
abstract public static function createProvider(HttpClientInterface $client, LoaderInterface $loader, LoggerInterface $logger, string $defaultLocale, string $endpoint): ProviderInterface;
|
||||
|
||||
/**
|
||||
* @return iterable<array{0: string, 1: ProviderInterface}>
|
||||
* @return iterable<array{0: ProviderInterface, 1: string}>
|
||||
*/
|
||||
abstract public function toStringProvider(): iterable;
|
||||
abstract public static function toStringProvider(): iterable;
|
||||
|
||||
/**
|
||||
* @dataProvider toStringProvider
|
||||
@@ -73,4 +74,9 @@ abstract class ProviderTestCase extends TestCase
|
||||
{
|
||||
return $this->xliffFileDumper ??= $this->createMock(XliffFileDumper::class);
|
||||
}
|
||||
|
||||
protected function getTranslatorBag(): TranslatorBagInterface
|
||||
{
|
||||
return $this->translatorBag ??= $this->createMock(TranslatorBagInterface::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class TranslatableMessage implements TranslatableInterface
|
||||
private array $parameters;
|
||||
private ?string $domain;
|
||||
|
||||
public function __construct(string $message, array $parameters = [], string $domain = null)
|
||||
public function __construct(string $message, array $parameters = [], ?string $domain = null)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->parameters = $parameters;
|
||||
@@ -50,12 +50,10 @@ class TranslatableMessage implements TranslatableInterface
|
||||
return $this->domain;
|
||||
}
|
||||
|
||||
public function trans(TranslatorInterface $translator, string $locale = null): string
|
||||
public function trans(TranslatorInterface $translator, ?string $locale = null): string
|
||||
{
|
||||
return $translator->trans($this->getMessage(), array_map(
|
||||
static function ($parameter) use ($translator, $locale) {
|
||||
return $parameter instanceof TranslatableInterface ? $parameter->trans($translator, $locale) : $parameter;
|
||||
},
|
||||
static fn ($parameter) => $parameter instanceof TranslatableInterface ? $parameter->trans($translator, $locale) : $parameter,
|
||||
$this->getParameters()
|
||||
), $this->getDomain(), $locale);
|
||||
}
|
||||
|
||||
63
vendor/symfony/translation/Translator.php
vendored
63
vendor/symfony/translation/Translator.php
vendored
@@ -22,6 +22,7 @@ use Symfony\Component\Translation\Formatter\MessageFormatter;
|
||||
use Symfony\Component\Translation\Formatter\MessageFormatterInterface;
|
||||
use Symfony\Component\Translation\Loader\LoaderInterface;
|
||||
use Symfony\Contracts\Translation\LocaleAwareInterface;
|
||||
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
// Help opcache.preload discover always-needed symbols
|
||||
@@ -51,7 +52,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
|
||||
private array $resources = [];
|
||||
|
||||
private $formatter;
|
||||
private MessageFormatterInterface $formatter;
|
||||
|
||||
private ?string $cacheDir;
|
||||
|
||||
@@ -59,7 +60,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
|
||||
private array $cacheVary;
|
||||
|
||||
private $configCacheFactory;
|
||||
private ?ConfigCacheFactoryInterface $configCacheFactory;
|
||||
|
||||
private array $parentLocales;
|
||||
|
||||
@@ -68,21 +69,20 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
/**
|
||||
* @throws InvalidArgumentException If a locale contains invalid characters
|
||||
*/
|
||||
public function __construct(string $locale, MessageFormatterInterface $formatter = null, string $cacheDir = null, bool $debug = false, array $cacheVary = [])
|
||||
public function __construct(string $locale, ?MessageFormatterInterface $formatter = null, ?string $cacheDir = null, bool $debug = false, array $cacheVary = [])
|
||||
{
|
||||
$this->setLocale($locale);
|
||||
|
||||
if (null === $formatter) {
|
||||
$formatter = new MessageFormatter();
|
||||
}
|
||||
|
||||
$this->formatter = $formatter;
|
||||
$this->formatter = $formatter ??= new MessageFormatter();
|
||||
$this->cacheDir = $cacheDir;
|
||||
$this->debug = $debug;
|
||||
$this->cacheVary = $cacheVary;
|
||||
$this->hasIntlFormatter = $formatter instanceof IntlFormatterInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory)
|
||||
{
|
||||
$this->configCacheFactory = $configCacheFactory;
|
||||
@@ -92,6 +92,8 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
* Adds a Loader.
|
||||
*
|
||||
* @param string $format The name of the loader (@see addResource())
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addLoader(string $format, LoaderInterface $loader)
|
||||
{
|
||||
@@ -104,13 +106,13 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
* @param string $format The name of the loader (@see addLoader())
|
||||
* @param mixed $resource The resource name
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidArgumentException If the locale contains invalid characters
|
||||
*/
|
||||
public function addResource(string $format, mixed $resource, string $locale, string $domain = null)
|
||||
public function addResource(string $format, mixed $resource, string $locale, ?string $domain = null)
|
||||
{
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
}
|
||||
$domain ??= 'messages';
|
||||
|
||||
$this->assertValidLocale($locale);
|
||||
$locale ?: $locale = class_exists(\Locale::class) ? \Locale::getDefault() : 'en';
|
||||
@@ -125,7 +127,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
public function setLocale(string $locale)
|
||||
{
|
||||
@@ -133,9 +135,6 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
$this->locale = $locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->locale ?: (class_exists(\Locale::class) ? \Locale::getDefault() : 'en');
|
||||
@@ -146,6 +145,8 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
*
|
||||
* @param string[] $locales
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidArgumentException If a locale contains invalid characters
|
||||
*/
|
||||
public function setFallbackLocales(array $locales)
|
||||
@@ -170,18 +171,13 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
return $this->fallbackLocales;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string
|
||||
public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
|
||||
{
|
||||
if (null === $id || '' === $id) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (null === $domain) {
|
||||
$domain = 'messages';
|
||||
}
|
||||
$domain ??= 'messages';
|
||||
|
||||
$catalogue = $this->getCatalogue($locale);
|
||||
$locale = $catalogue->getLocale();
|
||||
@@ -194,6 +190,8 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
}
|
||||
}
|
||||
|
||||
$parameters = array_map(fn ($parameter) => $parameter instanceof TranslatableInterface ? $parameter->trans($this, $locale) : $parameter, $parameters);
|
||||
|
||||
$len = \strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX);
|
||||
if ($this->hasIntlFormatter
|
||||
&& ($catalogue->defines($id, $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX)
|
||||
@@ -205,10 +203,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
return $this->formatter->format($catalogue->get($id, $domain), $locale, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface
|
||||
public function getCatalogue(?string $locale = null): MessageCatalogueInterface
|
||||
{
|
||||
if (!$locale) {
|
||||
$locale = $this->getLocale();
|
||||
@@ -223,9 +218,6 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
return $this->catalogues[$locale];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogues(): array
|
||||
{
|
||||
return array_values($this->catalogues);
|
||||
@@ -241,6 +233,9 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
return $this->loaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function loadCatalogue(string $locale)
|
||||
{
|
||||
if (null === $this->cacheDir) {
|
||||
@@ -250,6 +245,9 @@ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleA
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function initializeCatalogue(string $locale)
|
||||
{
|
||||
$this->assertValidLocale($locale);
|
||||
@@ -386,6 +384,9 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function computeFallbackLocales(string $locale)
|
||||
{
|
||||
$this->parentLocales ??= json_decode(file_get_contents(__DIR__.'/Resources/data/parents.json'), true);
|
||||
@@ -430,6 +431,8 @@ EOF
|
||||
/**
|
||||
* Asserts that the locale is valid, throws an Exception if not.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidArgumentException If the locale contains invalid characters
|
||||
*/
|
||||
protected function assertValidLocale(string $locale)
|
||||
|
||||
10
vendor/symfony/translation/TranslatorBag.php
vendored
10
vendor/symfony/translation/TranslatorBag.php
vendored
@@ -35,10 +35,7 @@ final class TranslatorBag implements TranslatorBagInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface
|
||||
public function getCatalogue(?string $locale = null): MessageCatalogueInterface
|
||||
{
|
||||
if (null === $locale || !isset($this->catalogues[$locale])) {
|
||||
$this->catalogues[$locale] = new MessageCatalogue($locale);
|
||||
@@ -47,9 +44,6 @@ final class TranslatorBag implements TranslatorBagInterface
|
||||
return $this->catalogues[$locale];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCatalogues(): array
|
||||
{
|
||||
return array_values($this->catalogues);
|
||||
@@ -70,7 +64,7 @@ final class TranslatorBag implements TranslatorBagInterface
|
||||
$operation->moveMessagesToIntlDomainsIfPossible(AbstractOperation::NEW_BATCH);
|
||||
$newCatalogue = new MessageCatalogue($locale);
|
||||
|
||||
foreach ($operation->getDomains() as $domain) {
|
||||
foreach ($catalogue->getDomains() as $domain) {
|
||||
$newCatalogue->add($operation->getNewMessages($domain), $domain);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ interface TranslatorBagInterface
|
||||
*
|
||||
* @throws InvalidArgumentException If the locale contains invalid characters
|
||||
*/
|
||||
public function getCatalogue(string $locale = null): MessageCatalogueInterface;
|
||||
public function getCatalogue(?string $locale = null): MessageCatalogueInterface;
|
||||
|
||||
/**
|
||||
* Returns all catalogues of the instance.
|
||||
|
||||
@@ -36,7 +36,7 @@ class ArrayConverter
|
||||
$tree = [];
|
||||
|
||||
foreach ($messages as $id => $value) {
|
||||
$referenceToElement = &self::getElementByPath($tree, explode('.', $id));
|
||||
$referenceToElement = &self::getElementByPath($tree, self::getKeyParts($id));
|
||||
|
||||
$referenceToElement = $value;
|
||||
|
||||
@@ -46,7 +46,7 @@ class ArrayConverter
|
||||
return $tree;
|
||||
}
|
||||
|
||||
private static function &getElementByPath(array &$tree, array $parts)
|
||||
private static function &getElementByPath(array &$tree, array $parts): mixed
|
||||
{
|
||||
$elem = &$tree;
|
||||
$parentOfElem = null;
|
||||
@@ -63,6 +63,7 @@ class ArrayConverter
|
||||
$elem = &$elem[implode('.', \array_slice($parts, $i))];
|
||||
break;
|
||||
}
|
||||
|
||||
$parentOfElem = &$elem;
|
||||
$elem = &$elem[$part];
|
||||
}
|
||||
@@ -82,7 +83,7 @@ class ArrayConverter
|
||||
return $elem;
|
||||
}
|
||||
|
||||
private static function cancelExpand(array &$tree, string $prefix, array $node)
|
||||
private static function cancelExpand(array &$tree, string $prefix, array $node): void
|
||||
{
|
||||
$prefix .= '.';
|
||||
|
||||
@@ -94,4 +95,48 @@ class ArrayConverter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private static function getKeyParts(string $key): array
|
||||
{
|
||||
$parts = explode('.', $key);
|
||||
$partsCount = \count($parts);
|
||||
|
||||
$result = [];
|
||||
$buffer = '';
|
||||
|
||||
foreach ($parts as $index => $part) {
|
||||
if (0 === $index && '' === $part) {
|
||||
$buffer = '.';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($index === $partsCount - 1 && '' === $part) {
|
||||
$buffer .= '.';
|
||||
$result[] = $buffer;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($parts[$index + 1]) && '' === $parts[$index + 1]) {
|
||||
$buffer .= $part;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($buffer) {
|
||||
$result[] = $buffer.$part;
|
||||
$buffer = '';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[] = $part;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ class XliffUtils
|
||||
private static function getSchema(string $xliffVersion): string
|
||||
{
|
||||
if ('1.2' === $xliffVersion) {
|
||||
$schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-1.2-strict.xsd');
|
||||
$schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-1.2-transitional.xsd');
|
||||
$xmlUri = 'http://www.w3.org/2001/xml.xsd';
|
||||
} elseif ('2.0' === $xliffVersion) {
|
||||
$schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-2.0.xsd');
|
||||
|
||||
@@ -30,6 +30,8 @@ class TranslationWriter implements TranslationWriterInterface
|
||||
|
||||
/**
|
||||
* Adds a dumper to the writer.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addDumper(string $format, DumperInterface $dumper)
|
||||
{
|
||||
@@ -50,6 +52,8 @@ class TranslationWriter implements TranslationWriterInterface
|
||||
* @param string $format The format to use to dump the messages
|
||||
* @param array $options Options that are passed to the dumper
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function write(MessageCatalogue $catalogue, string $format, array $options = [])
|
||||
|
||||
@@ -27,6 +27,8 @@ interface TranslationWriterInterface
|
||||
* @param string $format The format to use to dump the messages
|
||||
* @param array $options Options that are passed to the dumper
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function write(MessageCatalogue $catalogue, string $format, array $options = []);
|
||||
|
||||
32
vendor/symfony/translation/composer.json
vendored
32
vendor/symfony/translation/composer.json
vendored
@@ -16,27 +16,32 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0.2",
|
||||
"php": ">=8.1",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-mbstring": "~1.0",
|
||||
"symfony/translation-contracts": "^2.3|^3.0"
|
||||
"symfony/translation-contracts": "^2.5|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"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",
|
||||
"nikic/php-parser": "^4.18|^5.0",
|
||||
"symfony/config": "^5.4|^6.0|^7.0",
|
||||
"symfony/console": "^5.4|^6.0|^7.0",
|
||||
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
|
||||
"symfony/http-client-contracts": "^2.5|^3.0",
|
||||
"symfony/http-kernel": "^5.4|^6.0|^7.0",
|
||||
"symfony/intl": "^5.4|^6.0|^7.0",
|
||||
"symfony/polyfill-intl-icu": "^1.21",
|
||||
"symfony/service-contracts": "^1.1.2|^2|^3",
|
||||
"symfony/yaml": "^5.4|^6.0",
|
||||
"symfony/finder": "^5.4|^6.0",
|
||||
"symfony/routing": "^5.4|^6.0|^7.0",
|
||||
"symfony/service-contracts": "^2.5|^3",
|
||||
"symfony/yaml": "^5.4|^6.0|^7.0",
|
||||
"symfony/finder": "^5.4|^6.0|^7.0",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<5.4",
|
||||
"symfony/dependency-injection": "<5.4",
|
||||
"symfony/http-client-contracts": "<2.5",
|
||||
"symfony/http-kernel": "<5.4",
|
||||
"symfony/service-contracts": "<2.5",
|
||||
"symfony/twig-bundle": "<5.4",
|
||||
"symfony/yaml": "<5.4",
|
||||
"symfony/console": "<5.4"
|
||||
@@ -44,11 +49,6 @@
|
||||
"provide": {
|
||||
"symfony/translation-implementation": "2.3|3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/config": "",
|
||||
"symfony/yaml": "",
|
||||
"psr/log-implementation": "To use logging capability in translator"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [ "Resources/functions.php" ],
|
||||
"psr-4": { "Symfony\\Component\\Translation\\": "" },
|
||||
|
||||
Reference in New Issue
Block a user