From 2b56e4a2b6dea0b5e06c51754f33da5933b4ccc3 Mon Sep 17 00:00:00 2001 From: Maelan LE BORGNE Date: Thu, 20 Jun 2024 10:22:46 +0200 Subject: [PATCH] [Translator] Add configuration to filter dumped translations by domain --- src/Translator/CHANGELOG.md | 4 + src/Translator/doc/index.rst | 20 ++- .../src/DependencyInjection/Configuration.php | 54 ++++++ .../UxTranslatorExtension.php | 10 +- src/Translator/src/TranslationsDumper.php | 25 +++ .../tests/TranslationsDumperTest.php | 162 +++++++++++------- 6 files changed, 215 insertions(+), 60 deletions(-) diff --git a/src/Translator/CHANGELOG.md b/src/Translator/CHANGELOG.md index 62f7ae2614d..b8d13254038 100644 --- a/src/Translator/CHANGELOG.md +++ b/src/Translator/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 2.19.0 + +- Add configuration to filter dumped translations by domain. + ## 2.16.0 - Increase version range of `intl-messageformat` to `^10.5.11`, in order to see diff --git a/src/Translator/doc/index.rst b/src/Translator/doc/index.rst index 011ce6ae068..0b36da695ac 100644 --- a/src/Translator/doc/index.rst +++ b/src/Translator/doc/index.rst @@ -65,7 +65,7 @@ After installing the bundle, the following file should be created, thanks to the Usage ----- -When warming up the Symfony cache, all of your translations will be dumped as JavaScript into the ``var/translations/`` directory. +When warming up the Symfony cache, your translations will be dumped as JavaScript into the ``var/translations/`` directory. For a better developer experience, TypeScript types definitions are also generated aside those JavaScript files. Then, you will be able to import those JavaScript translations in your assets. @@ -75,6 +75,24 @@ Don't worry about your final bundle size, only the translations you use will be This package requires the `translator` to be enabled in your Symfony application. If you don't use the `translator` service, the warmup command will not generate any translations. +Configuring the dumped translations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, all your translations will be exported. You can restrict the dumped messages by either +including or excluding translation domains in your ``config/packages/ux_translator.yaml`` file: + +.. code-block:: yaml + + ux_translator: + domains: ~ # Include all the domains + + domains: foo # Include only domain 'foo' + domains: '!foo' # Include all domains, except 'foo' + + domains: [foo, bar] # Include only domains 'foo' and 'bar' + domains: ['!foo', '!bar'] # Include all domains, except 'foo' and 'bar' + + Configuring the default locale ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/Translator/src/DependencyInjection/Configuration.php b/src/Translator/src/DependencyInjection/Configuration.php index 485c1bdcb2a..5f2e31a3a82 100644 --- a/src/Translator/src/DependencyInjection/Configuration.php +++ b/src/Translator/src/DependencyInjection/Configuration.php @@ -13,6 +13,7 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; /** * @author Hugo Alliaume @@ -28,6 +29,59 @@ public function getConfigTreeBuilder(): TreeBuilder $rootNode ->children() ->scalarNode('dump_directory')->defaultValue('%kernel.project_dir%/var/translations')->end() + ->arrayNode('domains') + ->info('List of domains to include/exclude from the generated translations. Prefix with a `!` to exclude a domain.') + ->children() + ->scalarNode('type') + ->validate() + ->ifNotInArray(['inclusive', 'exclusive']) + ->thenInvalid('The type of domains has to be inclusive or exclusive') + ->end() + ->end() + ->arrayNode('elements') + ->scalarPrototype()->end() + ->end() + ->end() + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(fn ($v) => ['elements' => [$v]]) + ->end() + ->beforeNormalization() + ->ifTrue(function ($v) { return \is_array($v) && is_numeric(key($v)); }) + ->then(function ($v) { return ['elements' => $v]; }) + ->end() + ->validate() + ->always(function ($v) { + $isExclusive = null; + $elements = []; + if (isset($v['type'])) { + $isExclusive = 'exclusive' === $v['type']; + } + foreach ($v['elements'] as $domain) { + if (str_starts_with($domain, '!')) { + if (false === $isExclusive) { + throw new InvalidConfigurationException('You cannot mix included and excluded domains.'); + } + $isExclusive = true; + $elements[] = substr($domain, 1); + } else { + if (true === $isExclusive) { + throw new InvalidConfigurationException('You cannot mix included and excluded domains.'); + } + $isExclusive = false; + $elements[] = $domain; + } + } + + if (!\count($elements)) { + return null; + } + + return ['type' => $isExclusive ? 'exclusive' : 'inclusive', 'elements' => array_unique($elements)]; + }) + ->end() + ->end() ->end() ; diff --git a/src/Translator/src/DependencyInjection/UxTranslatorExtension.php b/src/Translator/src/DependencyInjection/UxTranslatorExtension.php index 65a154840ed..9ba3a02926c 100644 --- a/src/Translator/src/DependencyInjection/UxTranslatorExtension.php +++ b/src/Translator/src/DependencyInjection/UxTranslatorExtension.php @@ -35,7 +35,15 @@ public function load(array $configs, ContainerBuilder $container) $loader = (new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/../config'))); $loader->load('services.php'); - $container->getDefinition('ux.translator.translations_dumper')->setArgument(0, $config['dump_directory']); + $dumperDefinition = $container->getDefinition('ux.translator.translations_dumper'); + $dumperDefinition->setArgument(0, $config['dump_directory']); + + if (isset($config['domains'])) { + $method = 'inclusive' === $config['domains']['type'] ? 'addIncludedDomain' : 'addExcludedDomain'; + foreach ($config['domains']['elements'] as $domainName) { + $dumperDefinition->addMethodCall($method, [$domainName]); + } + } } public function prepend(ContainerBuilder $container) diff --git a/src/Translator/src/TranslationsDumper.php b/src/Translator/src/TranslationsDumper.php index 751f4203da0..cba611171be 100644 --- a/src/Translator/src/TranslationsDumper.php +++ b/src/Translator/src/TranslationsDumper.php @@ -32,6 +32,9 @@ */ class TranslationsDumper { + private array $excludedDomains = []; + private array $includedDomains = []; + public function __construct( private string $dumpDir, private MessageParametersExtractor $messageParametersExtractor, @@ -84,6 +87,22 @@ public function dump(MessageCatalogueInterface ...$catalogues): void ); } + 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; + } + /** * @return array>> */ @@ -94,6 +113,12 @@ private function getTranslations(MessageCatalogueInterface ...$catalogues): arra foreach ($catalogues as $catalogue) { $locale = $catalogue->getLocale(); foreach ($catalogue->getDomains() as $domain) { + if (\in_array($domain, $this->excludedDomains, true)) { + continue; + } + if ($this->includedDomains && !\in_array($domain, $this->includedDomains, true)) { + continue; + } foreach ($catalogue->all($domain) as $id => $message) { $realDomain = $catalogue->has($id, $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX) ? $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX diff --git a/src/Translator/tests/TranslationsDumperTest.php b/src/Translator/tests/TranslationsDumperTest.php index c21c3a8ccd5..c68a9fef794 100644 --- a/src/Translator/tests/TranslationsDumperTest.php +++ b/src/Translator/tests/TranslationsDumperTest.php @@ -22,6 +22,7 @@ class TranslationsDumperTest extends TestCase { protected static $translationsDumpDir; + private TranslationsDumper $translationsDumper; public static function setUpBeforeClass(): void { @@ -33,17 +34,115 @@ public static function tearDownAfterClass(): void @rmdir(self::$translationsDumpDir); } - public function testDump(): void + protected function setUp(): void { - $translationsDumper = new TranslationsDumper( + $this->translationsDumper = new TranslationsDumper( self::$translationsDumpDir, new MessageParametersExtractor(), new IntlMessageParametersExtractor(), new TypeScriptMessageParametersPrinter(), new Filesystem(), ); + } + + public function testDump(): void + { + $this->translationsDumper->dump(...self::getMessageCatalogues()); + + $this->assertFileExists(self::$translationsDumpDir.'/index.js'); + $this->assertFileExists(self::$translationsDumpDir.'/index.d.ts'); + + $this->assertStringEqualsFile(self::$translationsDumpDir.'/index.js', <<<'JAVASCRIPT' +export const NOTIFICATION_COMMENT_CREATED = {"id":"notification.comment_created","translations":{"messages+intl-icu":{"en":"Your post received a comment!","fr":"Votre article a re\u00e7u un commentaire !"}}}; +export const NOTIFICATION_COMMENT_CREATED_DESCRIPTION = {"id":"notification.comment_created.description","translations":{"messages+intl-icu":{"en":"Your post \"{title}\" has received a new comment. You can read the comment by following this link<\/a>","fr":"Votre article \"{title}\" a re\u00e7u un nouveau commentaire. Vous pouvez lire le commentaire en suivant ce lien<\/a>"}}}; +export const POST_NUM_COMMENTS = {"id":"post.num_comments","translations":{"messages+intl-icu":{"en":"{count, plural, one {# comment} other {# comments}}","fr":"{count, plural, one {# commentaire} other {# commentaires}}"},"foobar":{"en":"There is 1 comment|There are %count% comments","fr":"Il y a 1 comment|Il y a %count% comments"}}}; +export const POST_NUM_COMMENTS_1 = {"id":"post.num_comments.","translations":{"messages+intl-icu":{"en":"{count, plural, one {# comment} other {# comments}} (should not conflict with the previous one.)","fr":"{count, plural, one {# commentaire} other {# commentaires}} (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}}; +export const SYMFONY_GREAT = {"id":"symfony.great","translations":{"messages":{"en":"Symfony is awesome!","fr":"Symfony est g\u00e9nial !"}}}; +export const SYMFONY_WHAT = {"id":"symfony.what","translations":{"messages":{"en":"Symfony is %what%!","fr":"Symfony est %what%!"}}}; +export const SYMFONY_WHAT_1 = {"id":"symfony.what!","translations":{"messages":{"en":"Symfony is %what%! (should not conflict with the previous one.)","fr":"Symfony est %what%! (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}}; +export const SYMFONY_WHAT_2 = {"id":"symfony.what.","translations":{"messages":{"en":"Symfony is %what%. (should also not conflict with the previous one.)","fr":"Symfony est %what%. (ne doit pas non plus rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}}; +export const APPLES_COUNT0 = {"id":"apples.count.0","translations":{"messages":{"en":"There is 1 apple|There are %count% apples","fr":"Il y a 1 pomme|Il y a %count% pommes"}}}; +export const APPLES_COUNT1 = {"id":"apples.count.1","translations":{"messages":{"en":"{1} There is one apple|]1,Inf] There are %count% apples","fr":"{1} Il y a une pomme|]1,Inf] Il y a %count% pommes"}}}; +export const APPLES_COUNT2 = {"id":"apples.count.2","translations":{"messages":{"en":"{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples","fr":"{0} Il n'y a pas de pommes|{1} Il y a une pomme|]1,Inf] Il y a %count% pommes"}}}; +export const APPLES_COUNT3 = {"id":"apples.count.3","translations":{"messages":{"en":"one: There is one apple|more: There are %count% apples","fr":"one: Il y a une pomme|more: Il y a %count% pommes"}}}; +export const APPLES_COUNT4 = {"id":"apples.count.4","translations":{"messages":{"en":"one: There is one apple|more: There are more than one apple","fr":"one: Il y a une pomme|more: Il y a plus d'une pomme"}}}; +export const WHAT_COUNT1 = {"id":"what.count.1","translations":{"messages":{"en":"{1} There is one %what%|]1,Inf] There are %count% %what%","fr":"{1} Il y a une %what%|]1,Inf] Il y a %count% %what%"}}}; +export const WHAT_COUNT2 = {"id":"what.count.2","translations":{"messages":{"en":"{0} There are no %what%|{1} There is one %what%|]1,Inf] There are %count% %what%","fr":"{0} Il n'y a pas de %what%|{1} Il y a une %what%|]1,Inf] Il y a %count% %what%"}}}; +export const WHAT_COUNT3 = {"id":"what.count.3","translations":{"messages":{"en":"one: There is one %what%|more: There are %count% %what%","fr":"one: Il y a une %what%|more: Il y a %count% %what%"}}}; +export const WHAT_COUNT4 = {"id":"what.count.4","translations":{"messages":{"en":"one: There is one %what%|more: There are more than one %what%","fr":"one: Il y a une %what%|more: Il y a more than one %what%"}}}; +export const ANIMAL_DOG_CAT = {"id":"animal.dog-cat","translations":{"messages":{"en":"Dog and cat","fr":"Chien et chat"}}}; +export const ANIMAL_DOG_CAT_1 = {"id":"animal.dog_cat","translations":{"messages":{"en":"Dog and cat (should not conflict with the previous one)","fr":"Chien et chat (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}}; +export const _0STARTS_WITH_NUMERIC = {"id":"0starts.with.numeric","translations":{"messages":{"en":"Key starts with numeric char","fr":"La touche commence par un caract\u00e8re num\u00e9rique"}}}; + +JAVASCRIPT); + + $this->assertStringEqualsFile(self::$translationsDumpDir.'/index.d.ts', <<<'TYPESCRIPT' +import { Message, NoParametersType } from '@symfony/ux-translator'; + +export declare const NOTIFICATION_COMMENT_CREATED: Message<{ 'messages+intl-icu': { parameters: NoParametersType } }, 'en'|'fr'>; +export declare const NOTIFICATION_COMMENT_CREATED_DESCRIPTION: Message<{ 'messages+intl-icu': { parameters: { 'title': string, 'link': string } } }, 'en'|'fr'>; +export declare const POST_NUM_COMMENTS: Message<{ 'messages+intl-icu': { parameters: { 'count': number } }, 'foobar': { parameters: { '%count%': number } } }, 'en'|'fr'>; +export declare const POST_NUM_COMMENTS_1: Message<{ 'messages+intl-icu': { parameters: { 'count': number } } }, 'en'|'fr'>; +export declare const SYMFONY_GREAT: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; +export declare const SYMFONY_WHAT: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>; +export declare const SYMFONY_WHAT_1: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>; +export declare const SYMFONY_WHAT_2: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>; +export declare const APPLES_COUNT0: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>; +export declare const APPLES_COUNT1: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>; +export declare const APPLES_COUNT2: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>; +export declare const APPLES_COUNT3: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>; +export declare const APPLES_COUNT4: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; +export declare const WHAT_COUNT1: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>; +export declare const WHAT_COUNT2: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>; +export declare const WHAT_COUNT3: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>; +export declare const WHAT_COUNT4: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>; +export declare const ANIMAL_DOG_CAT: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; +export declare const ANIMAL_DOG_CAT_1: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; +export declare const _0STARTS_WITH_NUMERIC: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; + +TYPESCRIPT); + } + + public function testDumpWithExcludedDomains(): void + { + $this->translationsDumper->addExcludedDomain('foobar'); + $this->translationsDumper->dump(...$this->getMessageCatalogues()); + + $this->assertFileExists(self::$translationsDumpDir.'/index.js'); + $this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js')); + } + + public function testDumpIncludedDomains(): void + { + $this->translationsDumper->addIncludedDomain('messages'); + $this->translationsDumper->dump(...$this->getMessageCatalogues()); - $translationsDumper->dump( + $this->assertFileExists(self::$translationsDumpDir.'/index.js'); + $this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js')); + } + + public function testSetBothIncludedAndExcludedDomains(): void + { + $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'); + } + + public function testSetBothExcludedAndIncludedDomains(): void + { + $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'); + } + + /** + * @return list + */ + private static function getMessageCatalogues(): array + { + return [ new MessageCatalogue('en', [ 'messages+intl-icu' => [ 'notification.comment_created' => 'Your post received a comment!', @@ -101,60 +200,7 @@ public function testDump(): void 'foobar' => [ 'post.num_comments' => 'Il y a 1 comment|Il y a %count% comments', ], - ]) - ); - - $this->assertFileExists(self::$translationsDumpDir.'/index.js'); - $this->assertFileExists(self::$translationsDumpDir.'/index.d.ts'); - - $this->assertStringEqualsFile(self::$translationsDumpDir.'/index.js', <<<'JAVASCRIPT' -export const NOTIFICATION_COMMENT_CREATED = {"id":"notification.comment_created","translations":{"messages+intl-icu":{"en":"Your post received a comment!","fr":"Votre article a re\u00e7u un commentaire !"}}}; -export const NOTIFICATION_COMMENT_CREATED_DESCRIPTION = {"id":"notification.comment_created.description","translations":{"messages+intl-icu":{"en":"Your post \"{title}\" has received a new comment. You can read the comment by following this link<\/a>","fr":"Votre article \"{title}\" a re\u00e7u un nouveau commentaire. Vous pouvez lire le commentaire en suivant ce lien<\/a>"}}}; -export const POST_NUM_COMMENTS = {"id":"post.num_comments","translations":{"messages+intl-icu":{"en":"{count, plural, one {# comment} other {# comments}}","fr":"{count, plural, one {# commentaire} other {# commentaires}}"},"foobar":{"en":"There is 1 comment|There are %count% comments","fr":"Il y a 1 comment|Il y a %count% comments"}}}; -export const POST_NUM_COMMENTS_1 = {"id":"post.num_comments.","translations":{"messages+intl-icu":{"en":"{count, plural, one {# comment} other {# comments}} (should not conflict with the previous one.)","fr":"{count, plural, one {# commentaire} other {# commentaires}} (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}}; -export const SYMFONY_GREAT = {"id":"symfony.great","translations":{"messages":{"en":"Symfony is awesome!","fr":"Symfony est g\u00e9nial !"}}}; -export const SYMFONY_WHAT = {"id":"symfony.what","translations":{"messages":{"en":"Symfony is %what%!","fr":"Symfony est %what%!"}}}; -export const SYMFONY_WHAT_1 = {"id":"symfony.what!","translations":{"messages":{"en":"Symfony is %what%! (should not conflict with the previous one.)","fr":"Symfony est %what%! (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}}; -export const SYMFONY_WHAT_2 = {"id":"symfony.what.","translations":{"messages":{"en":"Symfony is %what%. (should also not conflict with the previous one.)","fr":"Symfony est %what%. (ne doit pas non plus rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}}; -export const APPLES_COUNT0 = {"id":"apples.count.0","translations":{"messages":{"en":"There is 1 apple|There are %count% apples","fr":"Il y a 1 pomme|Il y a %count% pommes"}}}; -export const APPLES_COUNT1 = {"id":"apples.count.1","translations":{"messages":{"en":"{1} There is one apple|]1,Inf] There are %count% apples","fr":"{1} Il y a une pomme|]1,Inf] Il y a %count% pommes"}}}; -export const APPLES_COUNT2 = {"id":"apples.count.2","translations":{"messages":{"en":"{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples","fr":"{0} Il n'y a pas de pommes|{1} Il y a une pomme|]1,Inf] Il y a %count% pommes"}}}; -export const APPLES_COUNT3 = {"id":"apples.count.3","translations":{"messages":{"en":"one: There is one apple|more: There are %count% apples","fr":"one: Il y a une pomme|more: Il y a %count% pommes"}}}; -export const APPLES_COUNT4 = {"id":"apples.count.4","translations":{"messages":{"en":"one: There is one apple|more: There are more than one apple","fr":"one: Il y a une pomme|more: Il y a plus d'une pomme"}}}; -export const WHAT_COUNT1 = {"id":"what.count.1","translations":{"messages":{"en":"{1} There is one %what%|]1,Inf] There are %count% %what%","fr":"{1} Il y a une %what%|]1,Inf] Il y a %count% %what%"}}}; -export const WHAT_COUNT2 = {"id":"what.count.2","translations":{"messages":{"en":"{0} There are no %what%|{1} There is one %what%|]1,Inf] There are %count% %what%","fr":"{0} Il n'y a pas de %what%|{1} Il y a une %what%|]1,Inf] Il y a %count% %what%"}}}; -export const WHAT_COUNT3 = {"id":"what.count.3","translations":{"messages":{"en":"one: There is one %what%|more: There are %count% %what%","fr":"one: Il y a une %what%|more: Il y a %count% %what%"}}}; -export const WHAT_COUNT4 = {"id":"what.count.4","translations":{"messages":{"en":"one: There is one %what%|more: There are more than one %what%","fr":"one: Il y a une %what%|more: Il y a more than one %what%"}}}; -export const ANIMAL_DOG_CAT = {"id":"animal.dog-cat","translations":{"messages":{"en":"Dog and cat","fr":"Chien et chat"}}}; -export const ANIMAL_DOG_CAT_1 = {"id":"animal.dog_cat","translations":{"messages":{"en":"Dog and cat (should not conflict with the previous one)","fr":"Chien et chat (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}}; -export const _0STARTS_WITH_NUMERIC = {"id":"0starts.with.numeric","translations":{"messages":{"en":"Key starts with numeric char","fr":"La touche commence par un caract\u00e8re num\u00e9rique"}}}; - -JAVASCRIPT); - - $this->assertStringEqualsFile(self::$translationsDumpDir.'/index.d.ts', <<<'TYPESCRIPT' -import { Message, NoParametersType } from '@symfony/ux-translator'; - -export declare const NOTIFICATION_COMMENT_CREATED: Message<{ 'messages+intl-icu': { parameters: NoParametersType } }, 'en'|'fr'>; -export declare const NOTIFICATION_COMMENT_CREATED_DESCRIPTION: Message<{ 'messages+intl-icu': { parameters: { 'title': string, 'link': string } } }, 'en'|'fr'>; -export declare const POST_NUM_COMMENTS: Message<{ 'messages+intl-icu': { parameters: { 'count': number } }, 'foobar': { parameters: { '%count%': number } } }, 'en'|'fr'>; -export declare const POST_NUM_COMMENTS_1: Message<{ 'messages+intl-icu': { parameters: { 'count': number } } }, 'en'|'fr'>; -export declare const SYMFONY_GREAT: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; -export declare const SYMFONY_WHAT: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>; -export declare const SYMFONY_WHAT_1: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>; -export declare const SYMFONY_WHAT_2: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>; -export declare const APPLES_COUNT0: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>; -export declare const APPLES_COUNT1: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>; -export declare const APPLES_COUNT2: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>; -export declare const APPLES_COUNT3: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>; -export declare const APPLES_COUNT4: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; -export declare const WHAT_COUNT1: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>; -export declare const WHAT_COUNT2: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>; -export declare const WHAT_COUNT3: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>; -export declare const WHAT_COUNT4: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>; -export declare const ANIMAL_DOG_CAT: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; -export declare const ANIMAL_DOG_CAT_1: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; -export declare const _0STARTS_WITH_NUMERIC: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>; - -TYPESCRIPT); + ]), + ]; } }