mirror of
https://github.com/symfony/ux-translator.git
synced 2026-03-24 00:12:19 +01:00
[Translator] Refactor TranslationsDumper options from __constructor and setters, to dump method
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -26,13 +26,15 @@ return static function (ContainerConfigurator $container): void {
|
||||
->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'),
|
||||
|
||||
@@ -18,13 +18,23 @@ use Symfony\UX\Translator\TranslationsDumper;
|
||||
/**
|
||||
* @author Hugo Alliaume <hugo@alliau.me>
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
class TranslationsCacheWarmer implements CacheWarmerInterface
|
||||
{
|
||||
/**
|
||||
* @param list<string> $includedDomains
|
||||
* @param list<string> $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 @@ class TranslationsCacheWarmer implements CacheWarmerInterface
|
||||
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
|
||||
|
||||
@@ -35,16 +35,22 @@ class UxTranslatorExtension extends Extension implements PrependExtensionInterfa
|
||||
$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
|
||||
|
||||
@@ -30,12 +30,7 @@ use Symfony\UX\Translator\MessageParameters\Printer\TypeScriptMessageParametersP
|
||||
*/
|
||||
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 @@ class TranslationsDumper
|
||||
) {
|
||||
}
|
||||
|
||||
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<MessageCatalogueInterface> $catalogues
|
||||
* @param list<Domain> $includedDomains
|
||||
* @param list<Domain> $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 @@ class TranslationsDumper
|
||||
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 @@ class TranslationsDumper
|
||||
);
|
||||
}
|
||||
|
||||
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 @@ class TranslationsDumper
|
||||
"\n"
|
||||
));
|
||||
|
||||
if ($this->dumpTypeScript) {
|
||||
if ($dumpTypeScript) {
|
||||
$this->filesystem->appendToFile($fileIndexDts, \sprintf(
|
||||
' "%s": %s;%s',
|
||||
$translationId,
|
||||
@@ -96,41 +105,29 @@ class TranslationsDumper
|
||||
|
||||
$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<MessageCatalogueInterface> $catalogues
|
||||
* @param list<Domain> $excludedDomains
|
||||
* @param list<Domain> $includedDomains
|
||||
*
|
||||
* @return array<MessageId, array<Domain, array<Locale, string>>>
|
||||
*/
|
||||
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 @@ class TranslationsDumper
|
||||
);
|
||||
}
|
||||
|
||||
private function getLocaleFallbacks(MessageCatalogueInterface ...$catalogues): array
|
||||
/**
|
||||
* @param list<MessageCatalogueInterface> $catalogues
|
||||
*/
|
||||
private function getLocaleFallbacks(array $catalogues): array
|
||||
{
|
||||
$localesFallbacks = [];
|
||||
|
||||
|
||||
@@ -42,15 +42,24 @@ final class TranslationsCacheWarmerTest extends TestCase
|
||||
])
|
||||
);
|
||||
|
||||
$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);
|
||||
|
||||
@@ -36,14 +36,15 @@ class TranslationsDumperTest extends TestCase
|
||||
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 @@ class TranslationsDumperTest extends TestCase
|
||||
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 @@ class TranslationsDumperTest extends TestCase
|
||||
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 @@ class TranslationsDumperTest extends TestCase
|
||||
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 @@ class TranslationsDumperTest extends TestCase
|
||||
$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 @@ class TranslationsDumperTest extends TestCase
|
||||
$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'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user