Skip to content

Commit 7d77142

Browse files
committed
[Translator] Add option ux_translator.dump_typescript to enable/disable TypeScript types generation
1 parent aaa5c9d commit 7d77142

File tree

7 files changed

+124
-35
lines changed

7 files changed

+124
-35
lines changed

src/Translator/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@
4949

5050
**Note:** This is a breaking change, but the UX Translator component is still experimental.
5151

52+
- Add configuration `ux_translator.dump_typescript` to enable/disable TypeScript types dumping,
53+
default to `true`. Generating TypeScript types is useful when developing,
54+
but not in production when using the AssetMapper (which does not use these types).
55+
5256
## 2.30
5357

5458
- Ensure compatibility with PHP 8.5

src/Translator/config/services.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131

3232
->set('ux.translator.translations_dumper', TranslationsDumper::class)
3333
->args([
34-
null, // Dump directory
34+
abstract_arg('dump_directory'),
35+
abstract_arg('dump_typescript'),
3536
service('ux.translator.message_parameters.extractor.message_parameters_extractor'),
3637
service('ux.translator.message_parameters.extractor.intl_message_parameters_extractor'),
3738
service('ux.translator.message_parameters.printer.typescript_message_parameters_printer'),

src/Translator/doc/index.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,22 @@ including or excluding translation domains in your ``config/packages/ux_translat
106106
domains: [foo, bar] # Include only domains 'foo' and 'bar'
107107
domains: ['!foo', '!bar'] # Include all domains, except 'foo' and 'bar'
108108
109+
Disabling TypeScript types dump
110+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
111+
112+
By default, TypeScript types definitions are generated alongside the dumped JavaScript translations.
113+
This provides autocompletion and type-safety when using the ``trans()`` function in your assets.
114+
115+
Even if they are useful when developing, dumping these TypeScript types is useless in production if you use the
116+
AssetMapper, because these files will never be used.
117+
118+
You can disable the TypeScript types dump by adding the following configuration::
119+
120+
.. code-block:: yaml
121+
122+
when@prod:
123+
ux_translator:
124+
dump_typescript: false
109125
110126
Configuring the default locale
111127
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/Translator/src/DependencyInjection/Configuration.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@ public function getConfigTreeBuilder(): TreeBuilder
2828
$rootNode = $treeBuilder->getRootNode();
2929
$rootNode
3030
->children()
31-
->scalarNode('dump_directory')->defaultValue('%kernel.project_dir%/var/translations')->end()
31+
->scalarNode('dump_directory')
32+
->info('The directory where translations and TypeScript types are dumped.')
33+
->defaultValue('%kernel.project_dir%/var/translations')
34+
->end()
35+
->booleanNode('dump_typescript')
36+
->info('Control if TypeScript types should be dumped alongside translations. Could be useful to disable when not using TypeScript (e.g. AssetMapper in production).')
37+
->defaultTrue()
38+
->end()
3239
->arrayNode('domains')
3340
->info('List of domains to include/exclude from the generated translations. Prefix with a `!` to exclude a domain.')
3441
->children()

src/Translator/src/DependencyInjection/UxTranslatorExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public function load(array $configs, ContainerBuilder $container): void
3737

3838
$dumperDefinition = $container->getDefinition('ux.translator.translations_dumper');
3939
$dumperDefinition->setArgument(0, $config['dump_directory']);
40+
$dumperDefinition->setArgument(1, $config['dump_typescript']);
4041

4142
if (isset($config['domains'])) {
4243
$method = 'inclusive' === $config['domains']['type'] ? 'addIncludedDomain' : 'addExcludedDomain';

src/Translator/src/TranslationsDumper.php

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class TranslationsDumper
3535

3636
public function __construct(
3737
private string $dumpDir,
38+
private string $dumpTypeScript,
3839
private MessageParametersExtractor $messageParametersExtractor,
3940
private IntlMessageParametersExtractor $intlMessageParametersExtractor,
4041
private TypeScriptMessageParametersPrinter $typeScriptMessageParametersPrinter,
@@ -54,24 +55,27 @@ public function dump(MessageCatalogueInterface ...$catalogues): void
5455
// This file is auto-generated by the Symfony UX Translator. Do not edit it manually.
5556
5657
export const localeFallbacks = %s;
58+
export const messages = {
5759
60+
}
5861
JS,
5962
json_encode($this->getLocaleFallbacks(...$catalogues), \JSON_THROW_ON_ERROR)
6063
));
6164

62-
$this->filesystem->appendToFile(
63-
$fileIndexDts,
64-
<<<'TS'
65-
// This file is auto-generated by the Symfony UX Translator. Do not edit it manually.
66-
import { Message, NoParametersType, LocaleType } from '@symfony/ux-translator';
65+
if ($this->dumpTypeScript) {
66+
$this->filesystem->appendToFile(
67+
$fileIndexDts,
68+
<<<'TS'
69+
// This file is auto-generated by the Symfony UX Translator. Do not edit it manually.
70+
import { Message, NoParametersType, LocaleType } from '@symfony/ux-translator';
6771
68-
export declare const localeFallbacks: Record<LocaleType, LocaleType>;
72+
export declare const localeFallbacks: Record<LocaleType, LocaleType>;
73+
export declare const messages: {
6974

70-
TS
71-
);
75+
TS
76+
);
77+
}
7278

73-
$this->filesystem->appendToFile($fileIndexJs, 'export const messages = {'."\n");
74-
$this->filesystem->appendToFile($fileIndexDts, 'export declare const messages: {'."\n");
7579
foreach ($this->getTranslations(...$catalogues) as $translationId => $translationsByDomainAndLocale) {
7680
$translationId = str_replace('"', '\\"', $translationId);
7781
$this->filesystem->appendToFile($fileIndexJs, \sprintf(
@@ -80,15 +84,22 @@ public function dump(MessageCatalogueInterface ...$catalogues): void
8084
json_encode(['translations' => $translationsByDomainAndLocale], \JSON_THROW_ON_ERROR),
8185
"\n"
8286
));
83-
$this->filesystem->appendToFile($fileIndexDts, \sprintf(
84-
' "%s": %s;%s',
85-
$translationId,
86-
$this->getTranslationsTypeScriptTypeDefinition($translationsByDomainAndLocale),
87-
"\n"
88-
));
87+
88+
if ($this->dumpTypeScript) {
89+
$this->filesystem->appendToFile($fileIndexDts, \sprintf(
90+
' "%s": %s;%s',
91+
$translationId,
92+
$this->getTranslationsTypeScriptTypeDefinition($translationsByDomainAndLocale),
93+
"\n"
94+
));
95+
}
8996
}
97+
9098
$this->filesystem->appendToFile($fileIndexJs, '};'."\n");
91-
$this->filesystem->appendToFile($fileIndexDts, '};'."\n");
99+
100+
if ($this->dumpTypeScript) {
101+
$this->filesystem->appendToFile($fileIndexDts, '};'."\n");
102+
}
92103
}
93104

94105
public function addExcludedDomain(string $domain): void

src/Translator/tests/TranslationsDumperTest.php

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
class TranslationsDumperTest extends TestCase
2323
{
2424
protected static $translationsDumpDir;
25-
private TranslationsDumper $translationsDumper;
2625

2726
public static function setUpBeforeClass(): void
2827
{
@@ -34,20 +33,17 @@ public static function tearDownAfterClass(): void
3433
@rmdir(self::$translationsDumpDir);
3534
}
3635

37-
protected function setUp(): void
36+
public function testDump()
3837
{
39-
$this->translationsDumper = new TranslationsDumper(
38+
$translationsDumper = new TranslationsDumper(
4039
self::$translationsDumpDir,
40+
true,
4141
new MessageParametersExtractor(),
4242
new IntlMessageParametersExtractor(),
4343
new TypeScriptMessageParametersPrinter(),
4444
new Filesystem(),
4545
);
46-
}
47-
48-
public function testDump()
49-
{
50-
$this->translationsDumper->dump(...self::getMessageCatalogues());
46+
$translationsDumper->dump(...self::getMessageCatalogues());
5147

5248
$this->assertFileExists(self::$translationsDumpDir.'/index.js');
5349
$this->assertFileExists(self::$translationsDumpDir.'/index.d.ts');
@@ -114,19 +110,53 @@ public function testDump()
114110
TS);
115111
}
116112

113+
public function testShouldNotDumpTypeScriptTypes()
114+
{
115+
$translationsDumper = new TranslationsDumper(
116+
self::$translationsDumpDir,
117+
false,
118+
new MessageParametersExtractor(),
119+
new IntlMessageParametersExtractor(),
120+
new TypeScriptMessageParametersPrinter(),
121+
new Filesystem(),
122+
);
123+
$translationsDumper->dump(...$this->getMessageCatalogues());
124+
125+
$this->assertFileExists(self::$translationsDumpDir.'/index.js');
126+
$this->assertFileDoesNotExist(self::$translationsDumpDir.'/index.d.ts');
127+
}
128+
117129
public function testDumpWithExcludedDomains()
118130
{
119-
$this->translationsDumper->addExcludedDomain('foobar');
120-
$this->translationsDumper->dump(...$this->getMessageCatalogues());
131+
$translationsDumper = new TranslationsDumper(
132+
self::$translationsDumpDir,
133+
true,
134+
new MessageParametersExtractor(),
135+
new IntlMessageParametersExtractor(),
136+
new TypeScriptMessageParametersPrinter(),
137+
new Filesystem(),
138+
);
139+
$translationsDumper->addExcludedDomain('foobar');
140+
141+
$translationsDumper->dump(...$this->getMessageCatalogues());
121142

122143
$this->assertFileExists(self::$translationsDumpDir.'/index.js');
123144
$this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js'));
124145
}
125146

126147
public function testDumpIncludedDomains()
127148
{
128-
$this->translationsDumper->addIncludedDomain('messages');
129-
$this->translationsDumper->dump(...$this->getMessageCatalogues());
149+
$translationsDumper = new TranslationsDumper(
150+
self::$translationsDumpDir,
151+
true,
152+
new MessageParametersExtractor(),
153+
new IntlMessageParametersExtractor(),
154+
new TypeScriptMessageParametersPrinter(),
155+
new Filesystem(),
156+
);
157+
$translationsDumper->addIncludedDomain('messages');
158+
159+
$translationsDumper->dump(...$this->getMessageCatalogues());
130160

131161
$this->assertFileExists(self::$translationsDumpDir.'/index.js');
132162
$this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js'));
@@ -136,16 +166,35 @@ public function testSetBothIncludedAndExcludedDomains()
136166
{
137167
$this->expectException(\LogicException::class);
138168
$this->expectExceptionMessage('You cannot set both "excluded_domains" and "included_domains" at the same time.');
139-
$this->translationsDumper->addIncludedDomain('foobar');
140-
$this->translationsDumper->addExcludedDomain('messages');
169+
170+
$translationsDumper = new TranslationsDumper(
171+
self::$translationsDumpDir,
172+
true,
173+
new MessageParametersExtractor(),
174+
new IntlMessageParametersExtractor(),
175+
new TypeScriptMessageParametersPrinter(),
176+
new Filesystem(),
177+
);
178+
179+
$translationsDumper->addIncludedDomain('foobar');
180+
$translationsDumper->addExcludedDomain('messages');
141181
}
142182

143183
public function testSetBothExcludedAndIncludedDomains()
144184
{
145185
$this->expectException(\LogicException::class);
146186
$this->expectExceptionMessage('You cannot set both "excluded_domains" and "included_domains" at the same time.');
147-
$this->translationsDumper->addExcludedDomain('foobar');
148-
$this->translationsDumper->addIncludedDomain('messages');
187+
188+
$translationsDumper = new TranslationsDumper(
189+
self::$translationsDumpDir,
190+
true,
191+
new MessageParametersExtractor(),
192+
new IntlMessageParametersExtractor(),
193+
new TypeScriptMessageParametersPrinter(),
194+
new Filesystem(),
195+
);
196+
$translationsDumper->addExcludedDomain('foobar');
197+
$translationsDumper->addIncludedDomain('messages');
149198
}
150199

151200
/**

0 commit comments

Comments
 (0)