Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Translator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
6 changes: 4 additions & 2 deletions src/Translator/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
16 changes: 15 additions & 1 deletion src/Translator/src/CacheWarmer/TranslationsCacheWarmer.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,23 @@
/**
* @author Hugo Alliaume <[email protected]>
*
* @internal
*
Comment on lines +21 to +22
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was initially missing

* @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,
) {
}

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 35 additions & 35 deletions src/Translator/src/TranslationsDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,33 @@
*/
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,
private Filesystem $filesystem,
) {
}

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,
Expand All @@ -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'
Expand All @@ -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',
Expand All @@ -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,
Expand All @@ -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<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) {
Expand Down Expand Up @@ -185,7 +182,10 @@ private function getTranslationsTypeScriptTypeDefinition(array $translationsByDo
);
}

private function getLocaleFallbacks(MessageCatalogueInterface ...$catalogues): array
/**
* @param list<MessageCatalogueInterface> $catalogues
*/
private function getLocaleFallbacks(array $catalogues): array
{
$localesFallbacks = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
53 changes: 31 additions & 22 deletions src/Translator/tests/TranslationsDumperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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');
Expand All @@ -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'));
Expand All @@ -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'));
Expand All @@ -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()
Expand All @@ -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'],
);
}

/**
Expand Down
Loading