mirror of
https://github.com/symfony/ux-translator.git
synced 2026-03-24 00:12:19 +01:00
[Translator] Add option ux_translator.dump_typescript to enable/disable TypeScript types generation
This commit is contained in:
@@ -49,6 +49,10 @@
|
||||
|
||||
**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).
|
||||
|
||||
## 2.30
|
||||
|
||||
- Ensure compatibility with PHP 8.5
|
||||
|
||||
@@ -31,7 +31,8 @@ return static function (ContainerConfigurator $container): void {
|
||||
|
||||
->set('ux.translator.translations_dumper', TranslationsDumper::class)
|
||||
->args([
|
||||
null, // Dump directory
|
||||
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'),
|
||||
|
||||
@@ -106,6 +106,22 @@ including or excluding translation domains in your ``config/packages/ux_translat
|
||||
domains: [foo, bar] # Include only domains 'foo' and 'bar'
|
||||
domains: ['!foo', '!bar'] # Include all domains, except 'foo' and 'bar'
|
||||
|
||||
Disabling TypeScript types dump
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By default, TypeScript types definitions are generated alongside the dumped JavaScript translations.
|
||||
This provides autocompletion and type-safety when using the ``trans()`` function in your assets.
|
||||
|
||||
Even if they are useful when developing, dumping these TypeScript types is useless in production if you use the
|
||||
AssetMapper, because these files will never be used.
|
||||
|
||||
You can disable the TypeScript types dump by adding the following configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
when@prod:
|
||||
ux_translator:
|
||||
dump_typescript: false
|
||||
|
||||
Configuring the default locale
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -28,7 +28,14 @@ class Configuration implements ConfigurationInterface
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
$rootNode
|
||||
->children()
|
||||
->scalarNode('dump_directory')->defaultValue('%kernel.project_dir%/var/translations')->end()
|
||||
->scalarNode('dump_directory')
|
||||
->info('The directory where translations and TypeScript types are dumped.')
|
||||
->defaultValue('%kernel.project_dir%/var/translations')
|
||||
->end()
|
||||
->booleanNode('dump_typescript')
|
||||
->info('Control if TypeScript types should be dumped alongside translations. Can be useful to disable when not using TypeScript (e.g. AssetMapper in production).')
|
||||
->defaultTrue()
|
||||
->end()
|
||||
->arrayNode('domains')
|
||||
->info('List of domains to include/exclude from the generated translations. Prefix with a `!` to exclude a domain.')
|
||||
->children()
|
||||
|
||||
@@ -37,6 +37,7 @@ class UxTranslatorExtension extends Extension implements PrependExtensionInterfa
|
||||
|
||||
$dumperDefinition = $container->getDefinition('ux.translator.translations_dumper');
|
||||
$dumperDefinition->setArgument(0, $config['dump_directory']);
|
||||
$dumperDefinition->setArgument(1, $config['dump_typescript']);
|
||||
|
||||
if (isset($config['domains'])) {
|
||||
$method = 'inclusive' === $config['domains']['type'] ? 'addIncludedDomain' : 'addExcludedDomain';
|
||||
|
||||
@@ -35,6 +35,7 @@ class TranslationsDumper
|
||||
|
||||
public function __construct(
|
||||
private string $dumpDir,
|
||||
private bool $dumpTypeScript,
|
||||
private MessageParametersExtractor $messageParametersExtractor,
|
||||
private IntlMessageParametersExtractor $intlMessageParametersExtractor,
|
||||
private TypeScriptMessageParametersPrinter $typeScriptMessageParametersPrinter,
|
||||
@@ -54,24 +55,26 @@ class TranslationsDumper
|
||||
// This file is auto-generated by the Symfony UX Translator. Do not edit it manually.
|
||||
|
||||
export const localeFallbacks = %s;
|
||||
export const messages = {
|
||||
|
||||
JS,
|
||||
json_encode($this->getLocaleFallbacks(...$catalogues), \JSON_THROW_ON_ERROR)
|
||||
));
|
||||
|
||||
$this->filesystem->appendToFile(
|
||||
$fileIndexDts,
|
||||
<<<'TS'
|
||||
// This file is auto-generated by the Symfony UX Translator. Do not edit it manually.
|
||||
import { Message, NoParametersType, LocaleType } from '@symfony/ux-translator';
|
||||
if ($this->dumpTypeScript) {
|
||||
$this->filesystem->appendToFile(
|
||||
$fileIndexDts,
|
||||
<<<'TS'
|
||||
// This file is auto-generated by the Symfony UX Translator. Do not edit it manually.
|
||||
import { Message, NoParametersType, LocaleType } from '@symfony/ux-translator';
|
||||
|
||||
export declare const localeFallbacks: Record<LocaleType, LocaleType>;
|
||||
export declare const localeFallbacks: Record<LocaleType, LocaleType>;
|
||||
export declare const messages: {
|
||||
|
||||
TS
|
||||
);
|
||||
TS
|
||||
);
|
||||
}
|
||||
|
||||
$this->filesystem->appendToFile($fileIndexJs, 'export const messages = {'."\n");
|
||||
$this->filesystem->appendToFile($fileIndexDts, 'export declare const messages: {'."\n");
|
||||
foreach ($this->getTranslations(...$catalogues) as $translationId => $translationsByDomainAndLocale) {
|
||||
$translationId = str_replace('"', '\\"', $translationId);
|
||||
$this->filesystem->appendToFile($fileIndexJs, \sprintf(
|
||||
@@ -80,15 +83,22 @@ class TranslationsDumper
|
||||
json_encode(['translations' => $translationsByDomainAndLocale], \JSON_THROW_ON_ERROR),
|
||||
"\n"
|
||||
));
|
||||
$this->filesystem->appendToFile($fileIndexDts, \sprintf(
|
||||
' "%s": %s;%s',
|
||||
$translationId,
|
||||
$this->getTranslationsTypeScriptTypeDefinition($translationsByDomainAndLocale),
|
||||
"\n"
|
||||
));
|
||||
|
||||
if ($this->dumpTypeScript) {
|
||||
$this->filesystem->appendToFile($fileIndexDts, \sprintf(
|
||||
' "%s": %s;%s',
|
||||
$translationId,
|
||||
$this->getTranslationsTypeScriptTypeDefinition($translationsByDomainAndLocale),
|
||||
"\n"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$this->filesystem->appendToFile($fileIndexJs, '};'."\n");
|
||||
$this->filesystem->appendToFile($fileIndexDts, '};'."\n");
|
||||
|
||||
if ($this->dumpTypeScript) {
|
||||
$this->filesystem->appendToFile($fileIndexDts, '};'."\n");
|
||||
}
|
||||
}
|
||||
|
||||
public function addExcludedDomain(string $domain): void
|
||||
|
||||
@@ -22,7 +22,6 @@ use Symfony\UX\Translator\TranslationsDumper;
|
||||
class TranslationsDumperTest extends TestCase
|
||||
{
|
||||
protected static $translationsDumpDir;
|
||||
private TranslationsDumper $translationsDumper;
|
||||
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
@@ -34,20 +33,17 @@ class TranslationsDumperTest extends TestCase
|
||||
@rmdir(self::$translationsDumpDir);
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
public function testDump()
|
||||
{
|
||||
$this->translationsDumper = new TranslationsDumper(
|
||||
$translationsDumper = new TranslationsDumper(
|
||||
self::$translationsDumpDir,
|
||||
true,
|
||||
new MessageParametersExtractor(),
|
||||
new IntlMessageParametersExtractor(),
|
||||
new TypeScriptMessageParametersPrinter(),
|
||||
new Filesystem(),
|
||||
);
|
||||
}
|
||||
|
||||
public function testDump()
|
||||
{
|
||||
$this->translationsDumper->dump(...self::getMessageCatalogues());
|
||||
$translationsDumper->dump(...self::getMessageCatalogues());
|
||||
|
||||
$this->assertFileExists(self::$translationsDumpDir.'/index.js');
|
||||
$this->assertFileExists(self::$translationsDumpDir.'/index.d.ts');
|
||||
@@ -114,10 +110,35 @@ class TranslationsDumperTest extends TestCase
|
||||
TS);
|
||||
}
|
||||
|
||||
public function testShouldNotDumpTypeScriptTypes()
|
||||
{
|
||||
$translationsDumper = new TranslationsDumper(
|
||||
self::$translationsDumpDir,
|
||||
false,
|
||||
new MessageParametersExtractor(),
|
||||
new IntlMessageParametersExtractor(),
|
||||
new TypeScriptMessageParametersPrinter(),
|
||||
new Filesystem(),
|
||||
);
|
||||
$translationsDumper->dump(...self::getMessageCatalogues());
|
||||
|
||||
$this->assertFileExists(self::$translationsDumpDir.'/index.js');
|
||||
$this->assertFileDoesNotExist(self::$translationsDumpDir.'/index.d.ts');
|
||||
}
|
||||
|
||||
public function testDumpWithExcludedDomains()
|
||||
{
|
||||
$this->translationsDumper->addExcludedDomain('foobar');
|
||||
$this->translationsDumper->dump(...$this->getMessageCatalogues());
|
||||
$translationsDumper = new TranslationsDumper(
|
||||
self::$translationsDumpDir,
|
||||
true,
|
||||
new MessageParametersExtractor(),
|
||||
new IntlMessageParametersExtractor(),
|
||||
new TypeScriptMessageParametersPrinter(),
|
||||
new Filesystem(),
|
||||
);
|
||||
$translationsDumper->addExcludedDomain('foobar');
|
||||
|
||||
$translationsDumper->dump(...self::getMessageCatalogues());
|
||||
|
||||
$this->assertFileExists(self::$translationsDumpDir.'/index.js');
|
||||
$this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js'));
|
||||
@@ -125,8 +146,17 @@ class TranslationsDumperTest extends TestCase
|
||||
|
||||
public function testDumpIncludedDomains()
|
||||
{
|
||||
$this->translationsDumper->addIncludedDomain('messages');
|
||||
$this->translationsDumper->dump(...$this->getMessageCatalogues());
|
||||
$translationsDumper = new TranslationsDumper(
|
||||
self::$translationsDumpDir,
|
||||
true,
|
||||
new MessageParametersExtractor(),
|
||||
new IntlMessageParametersExtractor(),
|
||||
new TypeScriptMessageParametersPrinter(),
|
||||
new Filesystem(),
|
||||
);
|
||||
$translationsDumper->addIncludedDomain('messages');
|
||||
|
||||
$translationsDumper->dump(...self::getMessageCatalogues());
|
||||
|
||||
$this->assertFileExists(self::$translationsDumpDir.'/index.js');
|
||||
$this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js'));
|
||||
@@ -136,16 +166,35 @@ class TranslationsDumperTest extends TestCase
|
||||
{
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('You cannot set both "excluded_domains" and "included_domains" at the same time.');
|
||||
$this->translationsDumper->addIncludedDomain('foobar');
|
||||
$this->translationsDumper->addExcludedDomain('messages');
|
||||
|
||||
$translationsDumper = new TranslationsDumper(
|
||||
self::$translationsDumpDir,
|
||||
true,
|
||||
new MessageParametersExtractor(),
|
||||
new IntlMessageParametersExtractor(),
|
||||
new TypeScriptMessageParametersPrinter(),
|
||||
new Filesystem(),
|
||||
);
|
||||
|
||||
$translationsDumper->addIncludedDomain('foobar');
|
||||
$translationsDumper->addExcludedDomain('messages');
|
||||
}
|
||||
|
||||
public function testSetBothExcludedAndIncludedDomains()
|
||||
{
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('You cannot set both "excluded_domains" and "included_domains" at the same time.');
|
||||
$this->translationsDumper->addExcludedDomain('foobar');
|
||||
$this->translationsDumper->addIncludedDomain('messages');
|
||||
|
||||
$translationsDumper = new TranslationsDumper(
|
||||
self::$translationsDumpDir,
|
||||
true,
|
||||
new MessageParametersExtractor(),
|
||||
new IntlMessageParametersExtractor(),
|
||||
new TypeScriptMessageParametersPrinter(),
|
||||
new Filesystem(),
|
||||
);
|
||||
$translationsDumper->addExcludedDomain('foobar');
|
||||
$translationsDumper->addIncludedDomain('messages');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user