diff --git a/src/Translator/CHANGELOG.md b/src/Translator/CHANGELOG.md index fc11ccfe36f..0ec296f82e3 100644 --- a/src/Translator/CHANGELOG.md +++ b/src/Translator/CHANGELOG.md @@ -49,6 +49,12 @@ **Note:** This is a breaking change, but the UX Translator component is still experimental. +- **[BC BREAK]** Refactor `TranslationsDumper` to accept configuration options via `dump()` method parameters, instead of constructor arguments or method calls: + - Removed `$dumpDir` and `$dumpTypeScript` constructor arguments + - Removed `TranslationsDumper::addIncludedDomain()` and `TranslationsDumper::addExcludedDomain()` methods + + **Note:** This is a breaking change, but the UX Translator component is still experimental. + - Add configuration `ux_translator.dump_typescript` to enable/disable TypeScript types dumping, default to `true`. Generating TypeScript types is useful when developing, but not in production when using the AssetMapper (which does not use these types). diff --git a/src/Translator/config/services.php b/src/Translator/config/services.php index 691b586a679..0aedc464d27 100644 --- a/src/Translator/config/services.php +++ b/src/Translator/config/services.php @@ -26,13 +26,15 @@ ->args([ service('translator'), service('ux.translator.translations_dumper'), + abstract_arg('dump_directory'), + abstract_arg('dump_typescript'), + abstract_arg('included_domains'), + abstract_arg('excluded_domains'), ]) ->tag('kernel.cache_warmer') ->set('ux.translator.translations_dumper', TranslationsDumper::class) ->args([ - abstract_arg('dump_directory'), - abstract_arg('dump_typescript'), service('ux.translator.message_parameters.extractor.message_parameters_extractor'), service('ux.translator.message_parameters.extractor.intl_message_parameters_extractor'), service('ux.translator.message_parameters.printer.typescript_message_parameters_printer'), diff --git a/src/Translator/src/CacheWarmer/TranslationsCacheWarmer.php b/src/Translator/src/CacheWarmer/TranslationsCacheWarmer.php index 2411772375c..69f2e68fcb7 100644 --- a/src/Translator/src/CacheWarmer/TranslationsCacheWarmer.php +++ b/src/Translator/src/CacheWarmer/TranslationsCacheWarmer.php @@ -18,13 +18,23 @@ /** * @author Hugo Alliaume * + * @internal + * * @experimental */ class TranslationsCacheWarmer implements CacheWarmerInterface { + /** + * @param list $includedDomains + * @param list $excludedDomains + */ public function __construct( private TranslatorBagInterface $translatorBag, private TranslationsDumper $translationsDumper, + private string $dumpDir, + private bool $dumpTypeScript, + private array $includedDomains, + private array $excludedDomains, ) { } @@ -36,7 +46,11 @@ public function isOptional(): bool public function warmUp(string $cacheDir, ?string $buildDir = null): array { $this->translationsDumper->dump( - ...$this->translatorBag->getCatalogues() + $this->translatorBag->getCatalogues(), + $this->dumpDir, + $this->dumpTypeScript, + $this->includedDomains, + $this->excludedDomains, ); // No need to preload anything diff --git a/src/Translator/src/DependencyInjection/UxTranslatorExtension.php b/src/Translator/src/DependencyInjection/UxTranslatorExtension.php index fea927ed6fb..6286980ae73 100644 --- a/src/Translator/src/DependencyInjection/UxTranslatorExtension.php +++ b/src/Translator/src/DependencyInjection/UxTranslatorExtension.php @@ -35,16 +35,22 @@ public function load(array $configs, ContainerBuilder $container): void $loader = (new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/../config'))); $loader->load('services.php'); - $dumperDefinition = $container->getDefinition('ux.translator.translations_dumper'); - $dumperDefinition->setArgument(0, $config['dump_directory']); - $dumperDefinition->setArgument(1, $config['dump_typescript']); + $includedDomains = []; + $excludedDomains = []; if (isset($config['domains'])) { - $method = 'inclusive' === $config['domains']['type'] ? 'addIncludedDomain' : 'addExcludedDomain'; - foreach ($config['domains']['elements'] as $domainName) { - $dumperDefinition->addMethodCall($method, [$domainName]); + if ('inclusive' === $config['domains']['type']) { + $includedDomains = $config['domains']['elements']; + } else { + $excludedDomains = $config['domains']['elements']; } } + + $cacheWarmerDefinition = $container->getDefinition('ux.translator.cache_warmer.translations_cache_warmer'); + $cacheWarmerDefinition->setArgument(2, $config['dump_directory']); + $cacheWarmerDefinition->setArgument(3, $config['dump_typescript']); + $cacheWarmerDefinition->setArgument(4, $includedDomains); + $cacheWarmerDefinition->setArgument(5, $excludedDomains); } public function prepend(ContainerBuilder $container): void diff --git a/src/Translator/src/TranslationsDumper.php b/src/Translator/src/TranslationsDumper.php index 2b09cbfffe9..8d811ce58a4 100644 --- a/src/Translator/src/TranslationsDumper.php +++ b/src/Translator/src/TranslationsDumper.php @@ -30,12 +30,7 @@ */ class TranslationsDumper { - private array $excludedDomains = []; - private array $includedDomains = []; - public function __construct( - private string $dumpDir, - private bool $dumpTypeScript, private MessageParametersExtractor $messageParametersExtractor, private IntlMessageParametersExtractor $intlMessageParametersExtractor, private TypeScriptMessageParametersPrinter $typeScriptMessageParametersPrinter, @@ -43,11 +38,25 @@ public function __construct( ) { } - public function dump(MessageCatalogueInterface ...$catalogues): void - { - $this->filesystem->mkdir($this->dumpDir); - $this->filesystem->remove($fileIndexJs = $this->dumpDir.'/index.js'); - $this->filesystem->remove($fileIndexDts = $this->dumpDir.'/index.d.ts'); + /** + * @param list $catalogues + * @param list $includedDomains + * @param list $excludedDomains + */ + public function dump( + array $catalogues, + string $dumpDir, + bool $dumpTypeScript = true, + array $includedDomains = [], + array $excludedDomains = [], + ): void { + if ($includedDomains && $excludedDomains) { + throw new \LogicException('You cannot set both "excluded_domains" and "included_domains" at the same time.'); + } + + $this->filesystem->mkdir($dumpDir); + $this->filesystem->remove($fileIndexJs = $dumpDir.'/index.js'); + $this->filesystem->remove($fileIndexDts = $dumpDir.'/index.d.ts'); $this->filesystem->appendToFile( $fileIndexJs, @@ -58,10 +67,10 @@ public function dump(MessageCatalogueInterface ...$catalogues): void export const messages = { JS, - json_encode($this->getLocaleFallbacks(...$catalogues), \JSON_THROW_ON_ERROR) + json_encode($this->getLocaleFallbacks($catalogues), \JSON_THROW_ON_ERROR) )); - if ($this->dumpTypeScript) { + if ($dumpTypeScript) { $this->filesystem->appendToFile( $fileIndexDts, <<<'TS' @@ -75,7 +84,7 @@ public function dump(MessageCatalogueInterface ...$catalogues): void ); } - foreach ($this->getTranslations(...$catalogues) as $translationId => $translationsByDomainAndLocale) { + foreach ($this->getTranslations($catalogues, $excludedDomains, $includedDomains) as $translationId => $translationsByDomainAndLocale) { $translationId = str_replace('"', '\\"', $translationId); $this->filesystem->appendToFile($fileIndexJs, \sprintf( ' "%s": %s,%s', @@ -84,7 +93,7 @@ public function dump(MessageCatalogueInterface ...$catalogues): void "\n" )); - if ($this->dumpTypeScript) { + if ($dumpTypeScript) { $this->filesystem->appendToFile($fileIndexDts, \sprintf( ' "%s": %s;%s', $translationId, @@ -96,41 +105,29 @@ public function dump(MessageCatalogueInterface ...$catalogues): void $this->filesystem->appendToFile($fileIndexJs, '};'."\n"); - if ($this->dumpTypeScript) { + if ($dumpTypeScript) { $this->filesystem->appendToFile($fileIndexDts, '};'."\n"); } } - public function addExcludedDomain(string $domain): void - { - if ($this->includedDomains) { - throw new \LogicException('You cannot set both "excluded_domains" and "included_domains" at the same time.'); - } - $this->excludedDomains[] = $domain; - } - - public function addIncludedDomain(string $domain): void - { - if ($this->excludedDomains) { - throw new \LogicException('You cannot set both "excluded_domains" and "included_domains" at the same time.'); - } - $this->includedDomains[] = $domain; - } - /** + * @param list $catalogues + * @param list $excludedDomains + * @param list $includedDomains + * * @return array>> */ - private function getTranslations(MessageCatalogueInterface ...$catalogues): array + private function getTranslations(array $catalogues, array $excludedDomains, array $includedDomains): array { $translations = []; foreach ($catalogues as $catalogue) { $locale = $catalogue->getLocale(); foreach ($catalogue->getDomains() as $domain) { - if (\in_array($domain, $this->excludedDomains, true)) { + if (\in_array($domain, $excludedDomains, true)) { continue; } - if ($this->includedDomains && !\in_array($domain, $this->includedDomains, true)) { + if ($includedDomains && !\in_array($domain, $includedDomains, true)) { continue; } foreach ($catalogue->all($domain) as $id => $message) { @@ -185,7 +182,10 @@ private function getTranslationsTypeScriptTypeDefinition(array $translationsByDo ); } - private function getLocaleFallbacks(MessageCatalogueInterface ...$catalogues): array + /** + * @param list $catalogues + */ + private function getLocaleFallbacks(array $catalogues): array { $localesFallbacks = []; diff --git a/src/Translator/tests/CacheWarmer/TranslationsCacheWarmerTest.php b/src/Translator/tests/CacheWarmer/TranslationsCacheWarmerTest.php index df83a78ea93..fdca03db832 100644 --- a/src/Translator/tests/CacheWarmer/TranslationsCacheWarmerTest.php +++ b/src/Translator/tests/CacheWarmer/TranslationsCacheWarmerTest.php @@ -42,15 +42,24 @@ public function test() ]) ); + $dumpDir = '/tmp/translations'; + $dumpTypeScript = true; + $includedDomains = []; + $excludedDomains = []; + $translationsDumperMock = $this->createMock(TranslationsDumper::class); $translationsDumperMock ->expects($this->once()) ->method('dump') - ->with(...$translatorBag->getCatalogues()); + ->with($translatorBag->getCatalogues(), $dumpDir, $dumpTypeScript, $includedDomains, $excludedDomains); $translationsCacheWarmer = new TranslationsCacheWarmer( $translatorBag, - $translationsDumperMock + $translationsDumperMock, + $dumpDir, + $dumpTypeScript, + $includedDomains, + $excludedDomains ); $translationsCacheWarmer->warmUp(self::$cacheDir); diff --git a/src/Translator/tests/TranslationsDumperTest.php b/src/Translator/tests/TranslationsDumperTest.php index 9091e672abc..019a1d65157 100644 --- a/src/Translator/tests/TranslationsDumperTest.php +++ b/src/Translator/tests/TranslationsDumperTest.php @@ -36,14 +36,15 @@ public static function tearDownAfterClass(): void public function testDump() { $translationsDumper = new TranslationsDumper( - self::$translationsDumpDir, - true, new MessageParametersExtractor(), new IntlMessageParametersExtractor(), new TypeScriptMessageParametersPrinter(), new Filesystem(), ); - $translationsDumper->dump(...self::getMessageCatalogues()); + $translationsDumper->dump( + catalogues: self::getMessageCatalogues(), + dumpDir: self::$translationsDumpDir, + ); $this->assertFileExists(self::$translationsDumpDir.'/index.js'); $this->assertFileExists(self::$translationsDumpDir.'/index.d.ts'); @@ -113,14 +114,16 @@ public function testDump() public function testShouldNotDumpTypeScriptTypes() { $translationsDumper = new TranslationsDumper( - self::$translationsDumpDir, - false, new MessageParametersExtractor(), new IntlMessageParametersExtractor(), new TypeScriptMessageParametersPrinter(), new Filesystem(), ); - $translationsDumper->dump(...self::getMessageCatalogues()); + $translationsDumper->dump( + catalogues: self::getMessageCatalogues(), + dumpDir: self::$translationsDumpDir, + dumpTypeScript: false, + ); $this->assertFileExists(self::$translationsDumpDir.'/index.js'); $this->assertFileDoesNotExist(self::$translationsDumpDir.'/index.d.ts'); @@ -129,16 +132,17 @@ public function testShouldNotDumpTypeScriptTypes() public function testDumpWithExcludedDomains() { $translationsDumper = new TranslationsDumper( - self::$translationsDumpDir, - true, new MessageParametersExtractor(), new IntlMessageParametersExtractor(), new TypeScriptMessageParametersPrinter(), new Filesystem(), ); - $translationsDumper->addExcludedDomain('foobar'); - $translationsDumper->dump(...self::getMessageCatalogues()); + $translationsDumper->dump( + catalogues: self::getMessageCatalogues(), + dumpDir: self::$translationsDumpDir, + excludedDomains: ['foobar'], + ); $this->assertFileExists(self::$translationsDumpDir.'/index.js'); $this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js')); @@ -147,16 +151,17 @@ public function testDumpWithExcludedDomains() public function testDumpIncludedDomains() { $translationsDumper = new TranslationsDumper( - self::$translationsDumpDir, - true, new MessageParametersExtractor(), new IntlMessageParametersExtractor(), new TypeScriptMessageParametersPrinter(), new Filesystem(), ); - $translationsDumper->addIncludedDomain('messages'); - $translationsDumper->dump(...self::getMessageCatalogues()); + $translationsDumper->dump( + catalogues: self::getMessageCatalogues(), + dumpDir: self::$translationsDumpDir, + includedDomains: ['messages'], + ); $this->assertFileExists(self::$translationsDumpDir.'/index.js'); $this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js')); @@ -168,16 +173,18 @@ public function testSetBothIncludedAndExcludedDomains() $this->expectExceptionMessage('You cannot set both "excluded_domains" and "included_domains" at the same time.'); $translationsDumper = new TranslationsDumper( - self::$translationsDumpDir, - true, new MessageParametersExtractor(), new IntlMessageParametersExtractor(), new TypeScriptMessageParametersPrinter(), new Filesystem(), ); - $translationsDumper->addIncludedDomain('foobar'); - $translationsDumper->addExcludedDomain('messages'); + $translationsDumper->dump( + catalogues: self::getMessageCatalogues(), + dumpDir: self::$translationsDumpDir, + includedDomains: ['foobar'], + excludedDomains: ['messages'], + ); } public function testSetBothExcludedAndIncludedDomains() @@ -186,15 +193,17 @@ public function testSetBothExcludedAndIncludedDomains() $this->expectExceptionMessage('You cannot set both "excluded_domains" and "included_domains" at the same time.'); $translationsDumper = new TranslationsDumper( - self::$translationsDumpDir, - true, new MessageParametersExtractor(), new IntlMessageParametersExtractor(), new TypeScriptMessageParametersPrinter(), new Filesystem(), ); - $translationsDumper->addExcludedDomain('foobar'); - $translationsDumper->addIncludedDomain('messages'); + $translationsDumper->dump( + catalogues: self::getMessageCatalogues(), + dumpDir: self::$translationsDumpDir, + includedDomains: ['messages'], + excludedDomains: ['foobar'], + ); } /**