1212namespace Symfony \Bundle \FrameworkBundle \Command ;
1313
1414use Symfony \Component \Console \Command \Command ;
15+ use Symfony \Component \Console \Completion \CompletionInput ;
16+ use Symfony \Component \Console \Completion \CompletionSuggestions ;
1517use Symfony \Component \Console \Exception \InvalidArgumentException ;
1618use Symfony \Component \Console \Input \InputArgument ;
1719use Symfony \Component \Console \Input \InputInterface ;
@@ -40,6 +42,10 @@ class TranslationUpdateCommand extends Command
4042 private const ASC = 'asc ' ;
4143 private const DESC = 'desc ' ;
4244 private const SORT_ORDERS = [self ::ASC , self ::DESC ];
45+ private const FORMATS = [
46+ 'xlf12 ' => ['xlf ' , '1.2 ' ],
47+ 'xlf20 ' => ['xlf ' , '2.0 ' ],
48+ ];
4349
4450 protected static $ defaultName = 'translation:update ' ;
4551 protected static $ defaultDescription = 'Update the translation file ' ;
@@ -52,8 +58,9 @@ class TranslationUpdateCommand extends Command
5258 private $ defaultViewsPath ;
5359 private $ transPaths ;
5460 private $ codePaths ;
61+ private $ enabledLocales ;
5562
56- public function __construct (TranslationWriterInterface $ writer , TranslationReaderInterface $ reader , ExtractorInterface $ extractor , string $ defaultLocale , string $ defaultTransPath = null , string $ defaultViewsPath = null , array $ transPaths = [], array $ codePaths = [])
63+ public function __construct (TranslationWriterInterface $ writer , TranslationReaderInterface $ reader , ExtractorInterface $ extractor , string $ defaultLocale , string $ defaultTransPath = null , string $ defaultViewsPath = null , array $ transPaths = [], array $ codePaths = [], array $ enabledLocales = [] )
5764 {
5865 parent ::__construct ();
5966
@@ -65,6 +72,7 @@ public function __construct(TranslationWriterInterface $writer, TranslationReade
6572 $ this ->defaultViewsPath = $ defaultViewsPath ;
6673 $ this ->transPaths = $ transPaths ;
6774 $ this ->codePaths = $ codePaths ;
75+ $ this ->enabledLocales = $ enabledLocales ;
6876 }
6977
7078 /**
@@ -147,10 +155,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
147155 trigger_deprecation ('symfony/framework-bundle ' , '5.3 ' , 'The "--output-format" option is deprecated, use "--format=xlf%d" instead. ' , 10 * $ xliffVersion );
148156 }
149157
150- switch ($ format ) {
151- case 'xlf20 ' : $ xliffVersion = '2.0 ' ;
152- // no break
153- case 'xlf12 ' : $ format = 'xlf ' ;
158+ if (\in_array ($ format , array_keys (self ::FORMATS ), true )) {
159+ [$ format , $ xliffVersion ] = self ::FORMATS [$ format ];
154160 }
155161
156162 // check format
@@ -165,15 +171,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
165171 $ kernel = $ this ->getApplication ()->getKernel ();
166172
167173 // Define Root Paths
168- $ transPaths = $ this ->transPaths ;
169- if ($ this ->defaultTransPath ) {
170- $ transPaths [] = $ this ->defaultTransPath ;
171- }
172- $ codePaths = $ this ->codePaths ;
173- $ codePaths [] = $ kernel ->getProjectDir ().'/src ' ;
174- if ($ this ->defaultViewsPath ) {
175- $ codePaths [] = $ this ->defaultViewsPath ;
176- }
174+ $ transPaths = $ this ->getRootTransPaths ();
175+ $ codePaths = $ this ->getRootCodePaths ($ kernel );
176+
177177 $ currentName = 'default directory ' ;
178178
179179 // Override with provided Bundle info
@@ -206,24 +206,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
206206 $ io ->title ('Translation Messages Extractor and Dumper ' );
207207 $ io ->comment (sprintf ('Generating "<info>%s</info>" translation files for "<info>%s</info>" ' , $ input ->getArgument ('locale ' ), $ currentName ));
208208
209- // load any messages from templates
210- $ extractedCatalogue = new MessageCatalogue ($ input ->getArgument ('locale ' ));
211209 $ io ->comment ('Parsing templates... ' );
212- $ this ->extractor ->setPrefix ($ input ->getOption ('prefix ' ));
213- foreach ($ codePaths as $ path ) {
214- if (is_dir ($ path ) || is_file ($ path )) {
215- $ this ->extractor ->extract ($ path , $ extractedCatalogue );
216- }
217- }
210+ $ extractedCatalogue = $ this ->extractMessages ($ input ->getArgument ('locale ' ), $ codePaths , $ input ->getOption ('prefix ' ));
218211
219- // load any existing messages from the translation files
220- $ currentCatalogue = new MessageCatalogue ($ input ->getArgument ('locale ' ));
221212 $ io ->comment ('Loading translation files... ' );
222- foreach ($ transPaths as $ path ) {
223- if (is_dir ($ path )) {
224- $ this ->reader ->read ($ path , $ currentCatalogue );
225- }
226- }
213+ $ currentCatalogue = $ this ->loadCurrentMessages ($ input ->getArgument ('locale ' ), $ transPaths );
227214
228215 if (null !== $ domain = $ input ->getOption ('domain ' )) {
229216 $ currentCatalogue = $ this ->filterCatalogue ($ currentCatalogue , $ domain );
@@ -321,6 +308,60 @@ protected function execute(InputInterface $input, OutputInterface $output): int
321308 return 0 ;
322309 }
323310
311+ public function complete (CompletionInput $ input , CompletionSuggestions $ suggestions ): void
312+ {
313+ if ($ input ->mustSuggestArgumentValuesFor ('locale ' )) {
314+ $ suggestions ->suggestValues ($ this ->enabledLocales );
315+
316+ return ;
317+ }
318+
319+ /** @var KernelInterface $kernel */
320+ $ kernel = $ this ->getApplication ()->getKernel ();
321+ if ($ input ->mustSuggestArgumentValuesFor ('bundle ' )) {
322+ $ bundles = [];
323+
324+ foreach ($ kernel ->getBundles () as $ bundle ) {
325+ $ bundles [] = $ bundle ->getName ();
326+ if ($ bundle ->getContainerExtension ()) {
327+ $ bundles [] = $ bundle ->getContainerExtension ()->getAlias ();
328+ }
329+ }
330+
331+ $ suggestions ->suggestValues ($ bundles );
332+
333+ return ;
334+ }
335+
336+ if ($ input ->mustSuggestOptionValuesFor ('format ' )) {
337+ $ suggestions ->suggestValues (array_merge (
338+ $ this ->writer ->getFormats (),
339+ array_keys (self ::FORMATS )
340+ ));
341+
342+ return ;
343+ }
344+
345+ if ($ input ->mustSuggestOptionValuesFor ('domain ' ) && $ locale = $ input ->getArgument ('locale ' )) {
346+ $ extractedCatalogue = $ this ->extractMessages ($ locale , $ this ->getRootCodePaths ($ kernel ), $ input ->getOption ('prefix ' ));
347+
348+ $ currentCatalogue = $ this ->loadCurrentMessages ($ locale , $ this ->getRootTransPaths ());
349+
350+ // process catalogues
351+ $ operation = $ input ->getOption ('clean ' )
352+ ? new TargetOperation ($ currentCatalogue , $ extractedCatalogue )
353+ : new MergeOperation ($ currentCatalogue , $ extractedCatalogue );
354+
355+ $ suggestions ->suggestValues ($ operation ->getDomains ());
356+
357+ return ;
358+ }
359+
360+ if ($ input ->mustSuggestOptionValuesFor ('sort ' )) {
361+ $ suggestions ->suggestValues (self ::SORT_ORDERS );
362+ }
363+ }
364+
324365 private function filterCatalogue (MessageCatalogue $ catalogue , string $ domain ): MessageCatalogue
325366 {
326367 $ filteredCatalogue = new MessageCatalogue ($ catalogue ->getLocale ());
@@ -353,4 +394,50 @@ private function filterCatalogue(MessageCatalogue $catalogue, string $domain): M
353394
354395 return $ filteredCatalogue ;
355396 }
397+
398+ private function extractMessages (string $ locale , array $ transPaths , string $ prefix ): MessageCatalogue
399+ {
400+ $ extractedCatalogue = new MessageCatalogue ($ locale );
401+ $ this ->extractor ->setPrefix ($ prefix );
402+ foreach ($ transPaths as $ path ) {
403+ if (is_dir ($ path ) || is_file ($ path )) {
404+ $ this ->extractor ->extract ($ path , $ extractedCatalogue );
405+ }
406+ }
407+
408+ return $ extractedCatalogue ;
409+ }
410+
411+ private function loadCurrentMessages (string $ locale , array $ transPaths ): MessageCatalogue
412+ {
413+ $ currentCatalogue = new MessageCatalogue ($ locale );
414+ foreach ($ transPaths as $ path ) {
415+ if (is_dir ($ path )) {
416+ $ this ->reader ->read ($ path , $ currentCatalogue );
417+ }
418+ }
419+
420+ return $ currentCatalogue ;
421+ }
422+
423+ private function getRootTransPaths (): array
424+ {
425+ $ transPaths = $ this ->transPaths ;
426+ if ($ this ->defaultTransPath ) {
427+ $ transPaths [] = $ this ->defaultTransPath ;
428+ }
429+
430+ return $ transPaths ;
431+ }
432+
433+ private function getRootCodePaths (KernelInterface $ kernel ): array
434+ {
435+ $ codePaths = $ this ->codePaths ;
436+ $ codePaths [] = $ kernel ->getProjectDir ().'/src ' ;
437+ if ($ this ->defaultViewsPath ) {
438+ $ codePaths [] = $ this ->defaultViewsPath ;
439+ }
440+
441+ return $ codePaths ;
442+ }
356443}
0 commit comments