Skip to content

Commit

Permalink
Added Translation Providers
Browse files Browse the repository at this point in the history
Co-authored-by: Olivier Dolbeau <[email protected]>
  • Loading branch information
welcoMattic and Olivier Dolbeau committed Apr 21, 2021
1 parent be384cf commit 6e55fa8
Show file tree
Hide file tree
Showing 58 changed files with 3,616 additions and 51 deletions.
2 changes: 2 additions & 0 deletions UPGRADE-5.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ FrameworkBundle
* Deprecate the `KernelTestCase::$container` property, use `KernelTestCase::getContainer()` instead
* Rename the container parameter `profiler_listener.only_master_requests` to `profiler_listener.only_main_requests`
* Deprecate registering workflow services as public
* Deprecate option `--xliff-version` of the `translation:update` command, use e.g. `--format=xlf20` instead
* Deprecate option `--output-format` of the `translation:update` command, use e.g. `--format=xlf20` instead

HttpFoundation
--------------
Expand Down
2 changes: 2 additions & 0 deletions UPGRADE-6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ FrameworkBundle
* Removed the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead.
* Remove the `KernelTestCase::$container` property, use `KernelTestCase::getContainer()` instead
* Registered workflow services are now private
* Remove option `--xliff-version` of the `translation:update` command, use e.g. `--output-format=xlf20` instead
* Remove option `--output-format` of the `translation:update` command, use e.g. `--output-format=xlf20` instead

HttpFoundation
--------------
Expand Down
2 changes: 1 addition & 1 deletion link
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ if (!is_dir("$pathToProject/vendor/symfony")) {
$sfPackages = array('symfony/symfony' => __DIR__);

$filesystem = new Filesystem();
$braces = array('Bundle', 'Bridge', 'Component', 'Component/Security', 'Component/Mailer/Bridge', 'Component/Messenger/Bridge', 'Component/Notifier/Bridge', 'Contracts');
$braces = array('Bundle', 'Bridge', 'Component', 'Component/Security', 'Component/Mailer/Bridge', 'Component/Messenger/Bridge', 'Component/Notifier/Bridge', 'Contracts', 'Component/Translation/Bridge');
$directories = array_merge(...array_values(array_map(function ($part) {
return glob(__DIR__.'/src/Symfony/'.$part.'/*', GLOB_ONLYDIR | GLOB_NOSORT);
}, $braces)));
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ CHANGELOG
* Rename the container parameter `profiler_listener.only_master_requests` to `profiler_listener.only_main_requests`
* Add service `fragment.uri_generator` to generate the URI of a fragment
* Deprecate registering workflow services as public
* Deprecate option `--xliff-version` of the `translation:update` command, use e.g. `--format=xlf20` instead
* Deprecate option `--output-format` of the `translation:update` command, use e.g. `--format=xlf20` instead

5.2.0
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ protected function configure()
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages'),
new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'),
new InputOption('output-format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'xlf'),
new InputOption('output-format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format (deprecated)'),
new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'xlf12'),
new InputOption('dump-messages', null, InputOption::VALUE_NONE, 'Should the messages be dumped in the console'),
new InputOption('force', null, InputOption::VALUE_NONE, 'Should the update be done'),
new InputOption('clean', null, InputOption::VALUE_NONE, 'Should clean not found messages'),
new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'Specify the domain to update'),
new InputOption('xliff-version', null, InputOption::VALUE_OPTIONAL, 'Override the default xliff version', '1.2'),
new InputOption('xliff-version', null, InputOption::VALUE_OPTIONAL, 'Override the default xliff version (deprecated)'),
new InputOption('sort', null, InputOption::VALUE_OPTIONAL, 'Return list of messages sorted alphabetically', 'asc'),
new InputOption('as-tree', null, InputOption::VALUE_OPTIONAL, 'Dump the messages as a tree-like structure: The given value defines the level where to switch to inline YAML'),
])
Expand Down Expand Up @@ -112,8 +113,8 @@ protected function configure()
You can dump a tree-like structure using the yaml format with <comment>--as-tree</> flag:
<info>php %command.full_name% --force --output-format=yaml --as-tree=3 en AcmeBundle</info>
<info>php %command.full_name% --force --output-format=yaml --sort=asc --as-tree=3 fr</info>
<info>php %command.full_name% --force --format=yaml --as-tree=3 en AcmeBundle</info>
<info>php %command.full_name% --force --format=yaml --sort=asc --as-tree=3 fr</info>

EOF
)
Expand All @@ -135,13 +136,31 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return 1;
}

$format = $input->getOption('output-format') ?: $input->getOption('format');
$xliffVersion = $input->getOption('xliff-version') ?? '1.2';

if ($input->getOption('xliff-version')) {
trigger_deprecation('symfony/framework-bundle', '5.3', 'The "--xliff-version" option is deprecated, use "--format=xlf%d" instead.', 10 * $xliffVersion);
}

if ($input->getOption('output-format')) {
trigger_deprecation('symfony/framework-bundle', '5.3', 'The "--output-format" option is deprecated, use "--format=xlf%d" instead.', 10 * $xliffVersion);
}

switch ($format) {
case 'xlf20': $xliffVersion = '2.0';
// no break
case 'xlf12': $format = 'xlf';
}

// check format
$supportedFormats = $this->writer->getFormats();
if (!\in_array($input->getOption('output-format'), $supportedFormats, true)) {
$errorIo->error(['Wrong output format', 'Supported formats are: '.implode(', ', $supportedFormats).'.']);
if (!\in_array($format, $supportedFormats, true)) {
$errorIo->error(['Wrong output format', 'Supported formats are: '.implode(', ', $supportedFormats).', xlf12 and xlf20.']);

return 1;
}

/** @var KernelInterface $kernel */
$kernel = $this->getApplication()->getKernel();

Expand Down Expand Up @@ -225,23 +244,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$resultMessage = 'Translation files were successfully updated';

// move new messages to intl domain when possible
if (class_exists(\MessageFormatter::class)) {
foreach ($operation->getDomains() as $domain) {
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
$newMessages = $operation->getNewMessages($domain);

if ([] === $newMessages || ([] === $currentCatalogue->all($intlDomain) && [] !== $currentCatalogue->all($domain))) {
continue;
}

$result = $operation->getResult();
$allIntlMessages = $result->all($intlDomain);
$currentMessages = array_diff_key($newMessages, $result->all($domain));
$result->replace($currentMessages, $domain);
$result->replace($allIntlMessages + $newMessages, $intlDomain);
}
}
$operation->moveMessagesToIntlDomainsIfPossible('new');

// show compiled list of messages
if (true === $input->getOption('dump-messages')) {
Expand Down Expand Up @@ -284,8 +287,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$extractedMessagesCount += $domainMessagesCount;
}

if ('xlf' === $input->getOption('output-format')) {
$io->comment(sprintf('Xliff output version is <info>%s</info>', $input->getOption('xliff-version')));
if ('xlf' === $format) {
$io->comment(sprintf('Xliff output version is <info>%s</info>', $xliffVersion));
}

$resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was');
Expand All @@ -306,7 +309,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$bundleTransPath = end($transPaths);
}

$this->writer->write($operation->getResult(), $input->getOption('output-format'), ['path' => $bundleTransPath, 'default_locale' => $this->defaultLocale, 'xliff_version' => $input->getOption('xliff-version'), 'as_tree' => $input->getOption('as-tree'), 'inline' => $input->getOption('as-tree') ?? 0]);
$this->writer->write($operation->getResult(), $format, ['path' => $bundleTransPath, 'default_locale' => $this->defaultLocale, 'xliff_version' => $xliffVersion, 'as_tree' => $input->getOption('as-tree'), 'inline' => $input->getOption('as-tree') ?? 0]);

if (true === $input->getOption('dump-messages')) {
$resultMessage .= ' and translation files were updated';
Expand Down Expand Up @@ -335,11 +338,13 @@ private function filterCatalogue(MessageCatalogue $catalogue, string $domain): M
foreach ($catalogue->getResources() as $resource) {
$filteredCatalogue->addResource($resource);
}

if ($metadata = $catalogue->getMetadata('', $intlDomain)) {
foreach ($metadata as $k => $v) {
$filteredCatalogue->setMetadata($k, $v, $intlDomain);
}
}

if ($metadata = $catalogue->getMetadata('', $domain)) {
foreach ($metadata as $k => $v) {
$filteredCatalogue->setMetadata($k, $v, $domain);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class UnusedTagsPass implements CompilerPassInterface
'translation.dumper',
'translation.extractor',
'translation.loader',
'translation.provider_factory',
'twig.extension',
'twig.loader',
'twig.runtime',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode, callable $e
->fixXmlConfig('fallback')
->fixXmlConfig('path')
->fixXmlConfig('enabled_locale')
->fixXmlConfig('provider')
->children()
->arrayNode('fallbacks')
->info('Defaults to the value of "default_locale".')
Expand Down Expand Up @@ -822,6 +823,27 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode, callable $e
->end()
->end()
->end()
->arrayNode('providers')
->info('Translation providers you can read/write your translations from')
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('domain')
->fixXmlConfig('locale')
->children()
->scalarNode('dsn')->end()
->arrayNode('domains')
->prototype('scalar')->end()
->defaultValue([])
->end()
->arrayNode('locales')
->prototype('scalar')->end()
->defaultValue([])
->info('If not set, all locales listed under framework.translator.enabled_locales are used.')
->end()
->end()
->end()
->defaultValue([])
->end()
->end()
->end()
->end()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\String\LazyString;
use Symfony\Component\String\Slugger\SluggerInterface;
use Symfony\Component\Translation\Bridge\Loco\Provider\LocoProviderFactory;
use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand;
use Symfony\Component\Translation\PseudoLocalizationTranslator;
use Symfony\Component\Translation\Translator;
Expand Down Expand Up @@ -1222,11 +1223,14 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
if (!$this->isConfigEnabled($container, $config)) {
$container->removeDefinition('console.command.translation_debug');
$container->removeDefinition('console.command.translation_update');
$container->removeDefinition('console.command.translation_pull');
$container->removeDefinition('console.command.translation_push');

return;
}

$loader->load('translation.php');
$loader->load('translation_providers.php');

// Use the "real" translator instead of the identity default
$container->setAlias('translator', 'translator.default')->setPublic(true);
Expand Down Expand Up @@ -1348,6 +1352,46 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
$options,
]);
}

$classToServices = [
LocoProviderFactory::class => 'translation.provider_factory.loco',
];

$parentPackages = ['symfony/framework-bundle', 'symfony/translation', 'symfony/http-client'];

foreach ($classToServices as $class => $service) {
$package = sprintf('symfony/%s-translation', substr($service, \strlen('translation.provider_factory.')));

if (!$container->hasDefinition('http_client') || !ContainerBuilder::willBeAvailable($package, $class, $parentPackages)) {
$container->removeDefinition($service);
}
}

if (!$config['providers']) {
return;
}

foreach ($config['providers'] as $name => $provider) {
if (!$config['enabled_locales'] && !$provider['locales']) {
throw new LogicException(sprintf('You must specify one of "framework.translator.enabled_locales" or "framework.translator.providers.%s.locales" in order to use translation providers.', $name));
}
}

$container->getDefinition('console.command.translation_pull')
->replaceArgument(4, array_merge($transPaths, [$config['default_path']]))
->replaceArgument(5, $config['enabled_locales'])
;

$container->getDefinition('console.command.translation_push')
->replaceArgument(2, array_merge($transPaths, [$config['default_path']]))
->replaceArgument(3, $config['enabled_locales'])
;

$container->getDefinition('translation.provider_collection_factory')
->replaceArgument(1, $config['enabled_locales'])
;

$container->getDefinition('translation.provider_collection')->setArgument(0, $config['providers']);
}

private function registerValidationConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader, bool $propertyInfoEnabled)
Expand Down
22 changes: 22 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
use Symfony\Component\Messenger\Command\FailedMessagesShowCommand;
use Symfony\Component\Messenger\Command\SetupTransportsCommand;
use Symfony\Component\Messenger\Command\StopWorkersCommand;
use Symfony\Component\Translation\Command\TranslationPullCommand;
use Symfony\Component\Translation\Command\TranslationPushCommand;
use Symfony\Component\Translation\Command\XliffLintCommand;
use Symfony\Component\Validator\Command\DebugCommand as ValidatorDebugCommand;

Expand Down Expand Up @@ -232,6 +234,26 @@
])
->tag('console.command')

->set('console.command.translation_pull', TranslationPullCommand::class)
->args([
service('translation.provider_collection'),
service('translation.writer'),
service('translation.reader'),
param('kernel.default_locale'),
[], // Translator paths
[], // Enabled locales
])
->tag('console.command', ['command' => 'translation:pull'])

->set('console.command.translation_push', TranslationPushCommand::class)
->args([
service('translation.provider_collection'),
service('translation.reader'),
[], // Translator paths
[], // Enabled locales
])
->tag('console.command', ['command' => 'translation:push'])

->set('console.command.workflow_dump', WorkflowDumpCommand::class)
->tag('console.command')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@
<xsd:element name="path" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="enabled-locale" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="pseudo-localization" type="pseudo_localization" minOccurs="0" maxOccurs="1" />
<xsd:element name="provider" type="translation_provider" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="fallback" type="xsd:string" />
Expand All @@ -195,6 +196,15 @@
<xsd:attribute name="parse_html" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="translation_provider">
<xsd:sequence>
<xsd:element name="domain" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="locale" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="dsn" type="xsd:string" />
</xsd:complexType>

<xsd:complexType name="validation">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="static-method" type="xsd:string" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Symfony\Component\Translation\Bridge\Loco\Provider\LocoProviderFactory;
use Symfony\Component\Translation\Provider\NullProviderFactory;
use Symfony\Component\Translation\Provider\TranslationProviderCollection;
use Symfony\Component\Translation\Provider\TranslationProviderCollectionFactory;

return static function (ContainerConfigurator $container) {
$container->services()
->set('translation.provider_collection', TranslationProviderCollection::class)
->factory([service('translation.provider_collection_factory'), 'fromConfig'])
->args([
[], // Providers
])

->set('translation.provider_collection_factory', TranslationProviderCollectionFactory::class)
->args([
tagged_iterator('translation.provider_factory'),
[], // Enabled locales
])

->set('translation.provider_factory.null', NullProviderFactory::class)
->tag('translation.provider_factory')

->set('translation.provider_factory.loco', LocoProviderFactory::class)
->args([
service('http_client'),
service('logger'),
param('kernel.default_locale'),
service('translation.loader.xliff'),
])
->tag('translation.provider_factory')
;
};
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ protected static function getBundleDefaultConfig()
'parse_html' => false,
'localizable_html_attributes' => [],
],
'providers' => [],
],
'validation' => [
'enabled' => !class_exists(FullStack::class),
Expand Down
4 changes: 4 additions & 0 deletions src/Symfony/Component/Translation/Bridge/Loco/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/Tests export-ignore
/phpunit.xml.dist export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
Loading

0 comments on commit 6e55fa8

Please sign in to comment.