From 52acb367ae71085558105a526795dcb90942585e Mon Sep 17 00:00:00 2001 From: Lukas Divacky Date: Tue, 10 Sep 2024 22:54:45 +0200 Subject: [PATCH 1/3] Added support for translations providers like loco --- composer.json | 3 +- src/DI/TranslationExtension.php | 92 +++++++++++++++++++++++++++++++++ src/Dumpers/NeonFileDumper.php | 56 ++++++++++++++++++++ src/Translator.php | 3 ++ 4 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/Dumpers/NeonFileDumper.php diff --git a/composer.json b/composer.json index 9b147fd..f81a6f8 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "nette/routing": "^3.0", "nette/utils": "^3.2.1|~4.0.0", "symfony/translation": "^6.0|^7.0", - "symfony/config": "^6.0|^7.0" + "symfony/config": "^6.0|^7.0", + "symfony/finder": "^6.0|^7.0" }, "require-dev": { "doctrine/orm": "^2.8", diff --git a/src/DI/TranslationExtension.php b/src/DI/TranslationExtension.php index 4ad0568..a392758 100644 --- a/src/DI/TranslationExtension.php +++ b/src/DI/TranslationExtension.php @@ -34,9 +34,24 @@ use Symfony\Component\Config\ConfigCacheFactory; use Symfony\Component\Config\ConfigCacheFactoryInterface; use Symfony\Component\Translation\Loader\LoaderInterface; +use Symfony\Component\Translation\Loader\XliffFileLoader; use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Component\Translation\Provider\ProviderFactoryInterface; +use Symfony\Component\Translation\Provider\ProviderInterface; +use Symfony\Component\Translation\Provider\TranslationProviderCollection; +use Symfony\Component\Translation\Provider\TranslationProviderCollectionFactory; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Component\Translation\Provider\Dsn; +use Contributte\Translation\Dumpers\NeonFileDumper; +use Symfony\Component\Translation\Writer\TranslationWriter; +use Symfony\Component\Translation\Reader\TranslationReader; +use Symfony\Component\Translation\Command\TranslationPushCommand; +use Symfony\Component\Translation\Command\TranslationPullCommand; +use Symfony\Component\Translation\Command\XliffLintCommand; +use Symfony\Component\HttpClient\CurlHttpClient; use Tracy\IBarPanel; + /** * @property stdClass $config */ @@ -83,6 +98,7 @@ public function getConfigSchema(): Schema 'returnOriginalMessage' => Expect::bool()->default(true), 'autowired' => Expect::type('bool|array')->default(true), 'latteFactory' => Expect::string(ILatteFactory::class)->nullable(), + 'providers' => Expect::array()->default([]), ]); } @@ -187,6 +203,9 @@ public function loadConfiguration(): void $translator->setAutowired($autowired); } + $reader = $builder->addDefinition($this->prefix('providerTranslationReader')) + ->setFactory(TranslationReader::class); + // Loaders foreach ($this->config->loaders as $k1 => $v1) { $reflection = new ReflectionClass(DIHelpers::unwrapEntity($v1)); @@ -199,8 +218,76 @@ public function loadConfiguration(): void ->setFactory($v1); $translator->addSetup('addLoader', [$k1, $loader]); + $reader->addSetup('addLoader', [$k1, $loader]); + } + + $neonFileDumper = $builder->addDefinition($this->prefix('neonFileDumper')) + ->setFactory(NeonFileDumper::class); + + $write = $builder->addDefinition($this->prefix('providerTranslationWriter')) + ->setFactory(TranslationWriter::class) + ->addSetup('addDumper', ['neon', $neonFileDumper]); + + // Symfony providers + + $builder->addDefinition($this->prefix('providerCurlHttpClient')) + ->setFactory(CurlHttpClient::class); + + $xlfLoader = $builder->addDefinition($this->prefix('loaderXLF')) + ->setFactory(XliffFileLoader::class); + + $providers = []; + foreach ($this->config->providers as $k1 => $v1) { + + if (!isset($v1['provider'])) + throw new InvalidArgument('Missing provider parameter in definitions of providers.'); + if (!isset($v1['dsn'])) + throw new InvalidArgument('Missing DSN parameter in definitions of providers.'); + + $reflection = new ReflectionClass(DIHelpers::unwrapEntity($v1['provider'])); + bdump($reflection); + if (!$reflection->implementsInterface(ProviderFactoryInterface::class)) { + throw new InvalidArgument('Provider must implement interface "' . ProviderFactoryInterface::class . '".'); + + } + + $provider = $builder->addDefinition($this->prefix('provider' . Strings::firstUpper($k1))) + ->setFactory($v1['provider'],['defaultLocale' => $this->config->locales->default, 'loader' => $xlfLoader]); + + $providers[$k1] = $provider; + + /*if (!isset($this->config->providers[$k1]['domains']) || empty($this->config->providers[$k1]['domains'])) { + $this->config->providers[$k1]['domains'] = ['common']; + }*/ + + } + + $builder->addDefinition($this->prefix('providerCollectionFatory')) + ->setFactory(TranslationProviderCollectionFactory::class, ["factories" => $providers, 'enabledLocales' => $this->config->locales->whitelist]); + + + $providerCollections = $builder->addDefinition($this->prefix('providerCollection')) + ->setFactory('@'.$this->prefix('providerCollectionFatory').'::fromConfig', ['config' => $this->config->providers]); + + + // Symfony commands + $builder->addDefinition($this->prefix('translationPullCommand')) + ->setFactory(TranslationPullCommand::class, ['providerCollection' => $providerCollections, 'defaultLocale' => $this->config->locales->default, 'enabledLocales' => $this->config->locales->whitelist, 'transPaths' => $this->config->dirs]) + ->setAutowired(false); + + $builder->addDefinition($this->prefix('translationPushCommand')) + ->setFactory(TranslationPushCommand::class, ['providers' => $providerCollections, 'enabledLocales' => $this->config->locales->whitelist, 'transPaths' => $this->config->dirs]) + ->setAutowired(false); + + $builder->addDefinition($this->prefix('translationXliffLintCommand')) + ->setFactory(XliffLintCommand::class) + ->setAutowired(false); + + + + // Tracy\Panel if (!$this->config->debug || !$this->config->debugger) { return; @@ -325,6 +412,10 @@ public function afterCompile( ClassType $class ): void { + $builder = $this->getContainerBuilder(); + $providerCollections = $builder->getDefinition($this->prefix('providerCollection')); + bdump($providerCollections); + if (!$this->config->debug || !$this->config->debugger) { return; } @@ -334,3 +425,4 @@ public function afterCompile( } } +; diff --git a/src/Dumpers/NeonFileDumper.php b/src/Dumpers/NeonFileDumper.php new file mode 100644 index 0000000..f20984e --- /dev/null +++ b/src/Dumpers/NeonFileDumper.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ + +namespace Contributte\Translation\Dumpers; + +use Symfony\Component\Translation\Exception\LogicException; +use Symfony\Component\Translation\MessageCatalogue; +use Symfony\Component\Translation\Util\ArrayConverter; +use Symfony\Component\Translation\Dumper\FileDumper; +use Symfony\Component\Yaml\Yaml; +use Nette\Neon\Neon as NetteNeon; + +/** + * NeonFileDumper generates yaml files from a message catalogue. + * + * @author Lukas Divacky + */ +class NeonFileDumper extends FileDumper +{ + private string $extension; + + public function __construct(string $extension = 'neon') + { + $this->extension = $extension; + } + + public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string + { + if (!class_exists(NetteNeon::class)) { + throw new LogicException('Dumping translations in the neon format requires the Nette neon component.'); + } + + $data = $messages->all($domain); + + $data = ArrayConverter::expandToTree($data); + + $neon = NetteNeon::encode($data, true); + + return $neon; + + } + + protected function getExtension(): string + { + return $this->extension; + } +} diff --git a/src/Translator.php b/src/Translator.php index e865865..9e63b96 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -12,6 +12,9 @@ use Nette\Utils\Validators; use Psr\Log\LoggerInterface; use Symfony\Component\Translation\Translator as SymfonyTranslator; +use Symfony\Component\Translation\Provider\ProviderFactoryInterface; +use Symfony\Component\Translation\Provider\Dsn; + class Translator extends SymfonyTranslator implements ITranslator { From 625d187a0ee155c63483e01e738cfd4f85b544ab Mon Sep 17 00:00:00 2001 From: Lukas Divacky Date: Tue, 10 Sep 2024 23:05:43 +0200 Subject: [PATCH 2/3] remove same debug lines --- src/DI/TranslationExtension.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/DI/TranslationExtension.php b/src/DI/TranslationExtension.php index a392758..5e4daf2 100644 --- a/src/DI/TranslationExtension.php +++ b/src/DI/TranslationExtension.php @@ -412,10 +412,6 @@ public function afterCompile( ClassType $class ): void { - $builder = $this->getContainerBuilder(); - $providerCollections = $builder->getDefinition($this->prefix('providerCollection')); - bdump($providerCollections); - if (!$this->config->debug || !$this->config->debugger) { return; } From 61c94f6cb888a35845f8b26338befe0b77a6d97c Mon Sep 17 00:00:00 2001 From: Lukas Divacky Date: Tue, 10 Sep 2024 23:07:37 +0200 Subject: [PATCH 3/3] remove same debug lines --- src/DI/TranslationExtension.php | 3 --- src/Translator.php | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/DI/TranslationExtension.php b/src/DI/TranslationExtension.php index 5e4daf2..1db3a6b 100644 --- a/src/DI/TranslationExtension.php +++ b/src/DI/TranslationExtension.php @@ -40,8 +40,6 @@ use Symfony\Component\Translation\Provider\ProviderInterface; use Symfony\Component\Translation\Provider\TranslationProviderCollection; use Symfony\Component\Translation\Provider\TranslationProviderCollectionFactory; -use Symfony\Contracts\HttpClient\HttpClientInterface; -use Symfony\Component\Translation\Provider\Dsn; use Contributte\Translation\Dumpers\NeonFileDumper; use Symfony\Component\Translation\Writer\TranslationWriter; use Symfony\Component\Translation\Reader\TranslationReader; @@ -421,4 +419,3 @@ public function afterCompile( } } -; diff --git a/src/Translator.php b/src/Translator.php index 9e63b96..e865865 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -12,9 +12,6 @@ use Nette\Utils\Validators; use Psr\Log\LoggerInterface; use Symfony\Component\Translation\Translator as SymfonyTranslator; -use Symfony\Component\Translation\Provider\ProviderFactoryInterface; -use Symfony\Component\Translation\Provider\Dsn; - class Translator extends SymfonyTranslator implements ITranslator {