1111
1212namespace Symfony \Bundle \FrameworkBundle \Command ;
1313
14- use Symfony \Component \ Translation \Catalogue \ MergeOperation ;
14+ use Symfony \Bundle \ FrameworkBundle \ Translation \TranslationLoader ;
1515use Symfony \Component \Console \Helper \Table ;
16+ use Symfony \Component \HttpKernel \Kernel ;
17+ use Symfony \Component \Translation \Catalogue \MergeOperation ;
1618use Symfony \Component \Console \Input \InputInterface ;
1719use Symfony \Component \Console \Output \OutputInterface ;
1820use Symfony \Component \Console \Input \InputArgument ;
@@ -48,6 +50,7 @@ protected function configure()
4850 new InputOption ('domain ' , null , InputOption::VALUE_OPTIONAL , 'The messages domain ' ),
4951 new InputOption ('only-missing ' , null , InputOption::VALUE_NONE , 'Displays only missing messages ' ),
5052 new InputOption ('only-unused ' , null , InputOption::VALUE_NONE , 'Displays only unused messages ' ),
53+ new InputOption ('all ' , null , InputOption::VALUE_NONE , 'Load messages from all registered bundles ' ),
5154 ))
5255 ->setDescription ('Displays translation messages information ' )
5356 ->setHelp (<<<EOF
@@ -75,9 +78,12 @@ protected function configure()
7578
7679 <info>php %command.full_name% en</info>
7780
81+ You can display information about translations in all registered bundles in a specific locale:
82+
83+ <info>php %command.full_name% --all en</info>
84+
7885EOF
79- )
80- ;
86+ );
8187 }
8288
8389 /**
@@ -86,134 +92,139 @@ protected function configure()
8692 protected function execute (InputInterface $ input , OutputInterface $ output )
8793 {
8894 if (false !== strpos ($ input ->getFirstArgument (), ':d ' )) {
89- $ output ->writeln ('<comment>The use of "translation:debug" command is deprecated since version 2.7 and will be removed in 3.0. Use the "debug:translation" instead.</comment> ' );
95+ $ output ->writeln (
96+ '<comment>The use of "translation:debug" command is deprecated since version 2.7 and will be removed in 3.0. Use the "debug:translation" instead.</comment> '
97+ );
9098 }
9199
92100 $ locale = $ input ->getArgument ('locale ' );
93101 $ domain = $ input ->getOption ('domain ' );
102+ /** @var TranslationLoader $loader */
94103 $ loader = $ this ->getContainer ()->get ('translation.loader ' );
104+ /** @var Kernel $kernel */
95105 $ kernel = $ this ->getContainer ()->get ('kernel ' );
96106
97107 // Define Root Path to App folder
98- $ rootPath = $ kernel ->getRootDir ();
108+ $ rootPaths = array ( $ kernel ->getRootDir () );
99109
100110 // Override with provided Bundle info
101111 if (null !== $ input ->getArgument ('bundle ' )) {
102112 try {
103- $ rootPath = $ kernel ->getBundle ($ input ->getArgument ('bundle ' ))->getPath ();
113+ $ rootPaths = array ( $ kernel ->getBundle ($ input ->getArgument ('bundle ' ))->getPath () );
104114 } catch (\InvalidArgumentException $ e ) {
105115 // such a bundle does not exist, so treat the argument as path
106- $ rootPath = $ input ->getArgument ('bundle ' );
116+ $ rootPaths = array ( $ input ->getArgument ('bundle ' ) );
107117
108- if (!is_dir ($ rootPath )) {
109- throw new \InvalidArgumentException (sprintf ('<error>"%s" is neither an enabled bundle nor a directory.</error> ' , $ rootPath ));
118+ if (!is_dir ($ rootPaths [0 ])) {
119+ throw new \InvalidArgumentException (
120+ sprintf ('<error>"%s" is neither an enabled bundle nor a directory.</error> ' , $ rootPaths [0 ])
121+ );
110122 }
111123 }
124+ } elseif ($ input ->getOption ('all ' )) {
125+ foreach ($ kernel ->getBundles () as $ bundle ) {
126+ $ rootPaths [] = $ bundle ->getPath ();
127+ }
112128 }
113129
114- // get bundle directory
115- $ translationsPath = $ rootPath .'/Resources/translations ' ;
116-
117- // Extract used messages
118- $ extractedCatalogue = new MessageCatalogue ($ locale );
119- if (is_dir ($ rootPath .'/Resources/views ' )) {
120- $ this ->getContainer ()->get ('translation.extractor ' )->extract ($ rootPath .'/Resources/views ' , $ extractedCatalogue );
121- }
130+ foreach ($ rootPaths as $ rootPath ) {
131+ // get bundle directory
132+ $ translationsPath = $ rootPath .'/Resources/translations ' ;
122133
123- // Load defined messages
124- $ currentCatalogue = new MessageCatalogue ($ locale );
125- if (is_dir ($ translationsPath )) {
126- $ loader ->loadMessages ($ translationsPath , $ currentCatalogue );
127- }
134+ $ output ->writeln (sprintf ('Translations in <info>%s</info> ' , $ translationsPath ));
128135
129- // Merge defined and extracted messages to get all message ids
130- $ mergeOperation = new MergeOperation ($ extractedCatalogue , $ currentCatalogue );
131- $ allMessages = $ mergeOperation ->getResult ()->all ($ domain );
132- if (null !== $ domain ) {
133- $ allMessages = array ($ domain => $ allMessages );
134- }
136+ // Extract used messages
137+ $ extractedCatalogue = $ this ->extractMessages ($ locale , $ rootPath );
135138
136- // No defined or extracted messages
137- if (empty ($ allMessages ) || null !== $ domain && empty ($ allMessages [$ domain ])) {
138- $ outputMessage = sprintf ('<info>No defined or extracted messages for locale "%s"</info> ' , $ locale );
139+ // Load defined messages
140+ $ currentCatalogue = $ this ->loadCurrentMessages ($ locale , $ translationsPath , $ loader );
139141
142+ // Merge defined and extracted messages to get all message ids
143+ $ mergeOperation = new MergeOperation ($ extractedCatalogue , $ currentCatalogue );
144+ $ allMessages = $ mergeOperation ->getResult ()->all ($ domain );
140145 if (null !== $ domain ) {
141- $ outputMessage .= sprintf ( ' <info>and domain "%s"</info> ' , $ domain );
146+ $ allMessages = array ( $ domain => $ allMessages );
142147 }
143148
144- $ output ->writeln ($ outputMessage );
149+ // No defined or extracted messages
150+ if (empty ($ allMessages ) || null !== $ domain && empty ($ allMessages [$ domain ])) {
151+ $ outputMessage = sprintf ('<info>No defined or extracted messages for locale "%s"</info> ' , $ locale );
145152
146- return ;
147- }
148-
149- // Load the fallback catalogues
150- $ fallbackCatalogues = array ();
151- $ translator = $ this ->getContainer ()->get ('translator ' );
152- if ($ translator instanceof Translator) {
153- foreach ($ translator ->getFallbackLocales () as $ fallbackLocale ) {
154- if ($ fallbackLocale === $ locale ) {
155- continue ;
153+ if (null !== $ domain ) {
154+ $ outputMessage .= sprintf (' <info>and domain "%s"</info> ' , $ domain );
156155 }
157156
158- $ fallbackCatalogue = new MessageCatalogue ( $ fallbackLocale );
159- $ loader -> loadMessages ( $ translationsPath , $ fallbackCatalogue );
160- $ fallbackCatalogues [] = $ fallbackCatalogue ;
157+ $ output -> writeln ( $ outputMessage );
158+
159+ continue ;
161160 }
162- }
163161
164- /** @var \Symfony\Component\Console\Helper\Table $table */
165- $ table = new Table ( $ output );
162+ // Load the fallback catalogues
163+ $ fallbackCatalogues = $ this -> loadFallbackCatalogues ( $ locale , $ translationsPath , $ loader );
166164
167- // Display header line
168- $ headers = array ('State(s) ' , 'Domain ' , 'Id ' , sprintf ('Message Preview (%s) ' , $ locale ));
169- foreach ($ fallbackCatalogues as $ fallbackCatalogue ) {
170- $ headers [] = sprintf ('Fallback Message Preview (%s) ' , $ fallbackCatalogue ->getLocale ());
171- }
172- $ table ->setHeaders ($ headers );
165+ $ table = new Table ($ output );
173166
174- // Iterate all message ids and determine their state
175- foreach ($ allMessages as $ domain => $ messages ) {
176- foreach (array_keys ($ messages ) as $ messageId ) {
177- $ value = $ currentCatalogue ->get ($ messageId , $ domain );
178- $ states = array ();
167+ // Display header line
168+ $ headers = array ('State(s) ' , 'Domain ' , 'Id ' , sprintf ('Message Preview (%s) ' , $ locale ));
169+ foreach ($ fallbackCatalogues as $ fallbackCatalogue ) {
170+ $ headers [] = sprintf ('Fallback Message Preview (%s) ' , $ fallbackCatalogue ->getLocale ());
171+ }
172+ $ table ->setHeaders ($ headers );
173+
174+ // Iterate all message ids and determine their state
175+ foreach ($ allMessages as $ domain => $ messages ) {
176+ foreach (array_keys ($ messages ) as $ messageId ) {
177+ $ value = $ currentCatalogue ->get ($ messageId , $ domain );
178+ $ states = array ();
179+
180+ if ($ extractedCatalogue ->defines ($ messageId , $ domain )) {
181+ if (!$ currentCatalogue ->defines ($ messageId , $ domain )) {
182+ $ states [] = self ::MESSAGE_MISSING ;
183+ }
184+ } elseif ($ currentCatalogue ->defines ($ messageId , $ domain )) {
185+ $ states [] = self ::MESSAGE_UNUSED ;
186+ }
179187
180- if ($ extractedCatalogue ->defines ($ messageId , $ domain )) {
181- if (!$ currentCatalogue ->defines ($ messageId , $ domain )) {
182- $ states [] = self ::MESSAGE_MISSING ;
188+ if (!in_array (self ::MESSAGE_UNUSED , $ states ) && true === $ input ->getOption ('only-unused ' )
189+ || !in_array (self ::MESSAGE_MISSING , $ states ) && true === $ input ->getOption ('only-missing ' )
190+ ) {
191+ continue ;
183192 }
184- } elseif ($ currentCatalogue ->defines ($ messageId , $ domain )) {
185- $ states [] = self ::MESSAGE_UNUSED ;
186- }
187193
188- if (!in_array (self ::MESSAGE_UNUSED , $ states ) && true === $ input ->getOption ('only-unused ' )
189- || !in_array (self ::MESSAGE_MISSING , $ states ) && true === $ input ->getOption ('only-missing ' )) {
190- continue ;
191- }
194+ foreach ($ fallbackCatalogues as $ fallbackCatalogue ) {
195+ if ($ fallbackCatalogue ->defines ($ messageId , $ domain )
196+ && $ value === $ fallbackCatalogue ->get ($ messageId , $ domain )
197+ ) {
198+ $ states [] = self ::MESSAGE_EQUALS_FALLBACK ;
192199
193- foreach ( $ fallbackCatalogues as $ fallbackCatalogue ) {
194- if ( $ fallbackCatalogue -> defines ( $ messageId , $ domain ) && $ value === $ fallbackCatalogue -> get ( $ messageId , $ domain )) {
195- $ states [] = self :: MESSAGE_EQUALS_FALLBACK ;
200+ break ;
201+ }
202+ }
196203
197- break ;
204+ $ row = array (
205+ $ this ->formatStates ($ states ),
206+ $ domain ,
207+ $ this ->formatId ($ messageId ),
208+ $ this ->sanitizeString ($ value ),
209+ );
210+ foreach ($ fallbackCatalogues as $ fallbackCatalogue ) {
211+ $ row [] = $ this ->sanitizeString ($ fallbackCatalogue ->get ($ messageId , $ domain ));
198212 }
199- }
200213
201- $ row = array ($ this ->formatStates ($ states ), $ domain , $ this ->formatId ($ messageId ), $ this ->sanitizeString ($ value ));
202- foreach ($ fallbackCatalogues as $ fallbackCatalogue ) {
203- $ row [] = $ this ->sanitizeString ($ fallbackCatalogue ->get ($ messageId , $ domain ));
214+ $ table ->addRow ($ row );
204215 }
205-
206- $ table ->addRow ($ row );
207216 }
208- }
209217
210- $ table ->render ();
218+ $ table ->render ();
219+ $ output ->writeln ('' );
220+ }
211221
212- $ output ->writeln ('' );
213222 $ output ->writeln ('<info>Legend:</info> ' );
214223 $ output ->writeln (sprintf (' %s Missing message ' , $ this ->formatState (self ::MESSAGE_MISSING )));
215224 $ output ->writeln (sprintf (' %s Unused message ' , $ this ->formatState (self ::MESSAGE_UNUSED )));
216- $ output ->writeln (sprintf (' %s Same as the fallback message ' , $ this ->formatState (self ::MESSAGE_EQUALS_FALLBACK )));
225+ $ output ->writeln (
226+ sprintf (' %s Same as the fallback message ' , $ this ->formatState (self ::MESSAGE_EQUALS_FALLBACK ))
227+ );
217228 }
218229
219230 private function formatState ($ state )
@@ -262,4 +273,63 @@ private function sanitizeString($string, $length = 40)
262273
263274 return $ string ;
264275 }
276+
277+ /**
278+ * @param string $locale
279+ * @param string $rootPath
280+ *
281+ * @return MessageCatalogue
282+ */
283+ private function extractMessages ($ locale , $ rootPath )
284+ {
285+ $ extractedCatalogue = new MessageCatalogue ($ locale );
286+ if (is_dir ($ rootPath .'/Resources/views ' )) {
287+ $ this ->getContainer ()->get ('translation.extractor ' )->extract ($ rootPath .'/Resources/views ' , $ extractedCatalogue );
288+ }
289+
290+ return $ extractedCatalogue ;
291+ }
292+
293+ /**
294+ * @param string $locale
295+ * @param string $translationsPath
296+ * @param TranslationLoader $loader
297+ *
298+ * @return MessageCatalogue
299+ */
300+ private function loadCurrentMessages ($ locale , $ translationsPath , TranslationLoader $ loader )
301+ {
302+ $ currentCatalogue = new MessageCatalogue ($ locale );
303+ if (is_dir ($ translationsPath )) {
304+ $ loader ->loadMessages ($ translationsPath , $ currentCatalogue );
305+ }
306+
307+ return $ currentCatalogue ;
308+ }
309+
310+ /**
311+ * @param string $locale
312+ * @param string $translationsPath
313+ * @param TranslationLoader $loader
314+ *
315+ * @return MessageCatalogue[]
316+ */
317+ private function loadFallbackCatalogues ($ locale , $ translationsPath , TranslationLoader $ loader )
318+ {
319+ $ fallbackCatalogues = array ();
320+ $ translator = $ this ->getContainer ()->get ('translator ' );
321+ if ($ translator instanceof Translator) {
322+ foreach ($ translator ->getFallbackLocales () as $ fallbackLocale ) {
323+ if ($ fallbackLocale === $ locale ) {
324+ continue ;
325+ }
326+
327+ $ fallbackCatalogue = new MessageCatalogue ($ fallbackLocale );
328+ $ loader ->loadMessages ($ translationsPath , $ fallbackCatalogue );
329+ $ fallbackCatalogues [] = $ fallbackCatalogue ;
330+ }
331+ }
332+
333+ return $ fallbackCatalogues ;
334+ }
265335}
0 commit comments