Yaffs site version 1.1
[yaffs-website] / vendor / drupal / console / src / Command / Develop / TranslationStatsCommand.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Console\Command\Develop\TranslationStatsCommand.
6  */
7
8 namespace Drupal\Console\Command\Develop;
9
10 use Drupal\Console\Command\Shared\TranslationTrait;
11 use Symfony\Component\Console\Input\InputInterface;
12 use Symfony\Component\Console\Input\InputOption;
13 use Symfony\Component\Console\Output\OutputInterface;
14 use Symfony\Component\Console\Input\InputArgument;
15 use Symfony\Component\Finder\Finder;
16 use Symfony\Component\Yaml\Parser;
17 use Symfony\Component\Yaml\Exception\ParseException;
18 use Symfony\Component\Console\Command\Command;
19 use Drupal\Console\Core\Style\DrupalStyle;
20 use Drupal\Console\Core\Command\Shared\CommandTrait;
21 use Drupal\Console\Core\Utils\ConfigurationManager;
22 use Drupal\Console\Core\Utils\TwigRenderer;
23 use Drupal\Console\Core\Utils\NestedArray;
24
25 class TranslationStatsCommand extends Command
26 {
27     use TranslationTrait;
28     use CommandTrait;
29
30     /**
31      * @var string
32      */
33     protected $consoleRoot;
34
35     /**
36      * @var ConfigurationManager
37      */
38     protected $configurationManager;
39
40     /**
41      * @var TwigRenderer $renderer
42      */
43     protected $renderer;
44
45     /**
46       * @var NestedArray
47       */
48     protected $nestedArray;
49
50     /**
51      * TranslationStatsCommand constructor.
52      *
53      * @param $appRoot
54      * @param ConfigurationManager $configurationManager
55      * @param TwigRenderer         $renderer
56      * @param NestedArray          $nestedArray
57      */
58     public function __construct(
59         $consoleRoot,
60         ConfigurationManager $configurationManager,
61         TwigRenderer $renderer,
62         NestedArray $nestedArray
63     ) {
64         $this->consoleRoot = $consoleRoot;
65         $this->configurationManager = $configurationManager;
66         $this->renderer = $renderer;
67         $this->nestedArray = $nestedArray;
68         parent::__construct();
69     }
70
71     /**
72      * {@inheritdoc}
73      */
74
75     protected function configure()
76     {
77         $this
78             ->setName('translation:stats')
79             ->setDescription($this->trans('commands.translation.stats.description'))
80             ->addArgument(
81                 'language',
82                 InputArgument::OPTIONAL,
83                 $this->trans('commands.translation.stats.arguments.language'),
84                 null
85             )
86             ->addOption(
87                 'format',
88                 null,
89                 InputOption::VALUE_OPTIONAL,
90                 $this->trans('commands.translation.stats.options.format'),
91                 'table'
92             );
93     }
94
95     /**
96      * {@inheritdoc}
97      */
98     protected function execute(InputInterface $input, OutputInterface $output)
99     {
100         $io = new DrupalStyle($input, $output);
101
102         $language = $input->getArgument('language');
103         $format = $input->getOption('format');
104
105         $languages = $this->configurationManager->getConfiguration()->get('application.languages');
106         unset($languages['en']);
107
108         if ($language && !isset($languages[$language])) {
109             $io->error(
110                 sprintf(
111                     $this->trans('commands.translation.stats.messages.invalid-language'),
112                     $language
113                 )
114             );
115             return 1;
116         }
117
118         if ($language) {
119             $languages = [$language => $languages[$language]];
120         }
121
122         $stats = $this->calculateStats($io, $language, $languages);
123
124         if ($format == 'table') {
125             $tableHeaders = [
126                 $this->trans('commands.translation.stats.messages.language'),
127                 $this->trans('commands.translation.stats.messages.percentage'),
128                 $this->trans('commands.translation.stats.messages.iso')
129             ];
130
131             $io->table($tableHeaders, $stats);
132             return 0;
133         }
134
135         if ($format == 'markdown') {
136             $arguments['language'] = $this->trans('commands.translation.stats.messages.language');
137             $arguments['percentage'] = $this->trans('commands.translation.stats.messages.percentage');
138
139             $arguments['languages'] = $stats;
140
141             $io->writeln(
142                 $this->renderFile(
143                     'core/translation/stats.md.twig',
144                     null,
145                     $arguments
146                 )
147             );
148         }
149     }
150
151     protected function calculateStats($io, $language = null, $languages)
152     {
153         $englishFilesFinder = new Finder();
154         $yaml = new Parser();
155         $statistics = [];
156
157         $englishDirectory = $this->consoleRoot .
158             sprintf(
159                 DRUPAL_CONSOLE_LANGUAGE,
160                 'en'
161             );
162
163         $englishFiles = $englishFilesFinder->files()->name('*.yml')->in($englishDirectory);
164
165         foreach ($englishFiles as $file) {
166             $resource = $englishDirectory . '/' . $file->getBasename();
167             $filename = $file->getBasename('.yml');
168
169             try {
170                 $englishFileParsed = $yaml->parse(file_get_contents($resource));
171             } catch (ParseException $e) {
172                 $io->error($filename . '.yml: ' . $e->getMessage());
173                 continue;
174             }
175
176             foreach ($languages as $langCode => $languageName) {
177                 $languageDir = $this->consoleRoot .
178                                         sprintf(
179                                             DRUPAL_CONSOLE_LANGUAGE,
180                                             $langCode
181                                         );
182                                 //don't show that language if that repo isn't present
183                 if (!file_exists($languageDir)) {
184                     continue;
185                 }
186                 if (isset($language) && $langCode != $language) {
187                     continue;
188                 }
189                 if (!isset($statistics[$langCode])) {
190                     $statistics[$langCode] = ['total' => 0, 'equal'=> 0 , 'diff' => 0];
191                 }
192
193                 $resourceTranslated = $languageDir . '/' . $file->getBasename();
194                 if (!file_exists($resourceTranslated)) {
195                     $englishFileEntries = count($englishFileParsed, COUNT_RECURSIVE);
196                     $statistics[$langCode]['total'] += $englishFileEntries;
197                     $statistics[$langCode]['equal'] += $englishFileEntries;
198                     continue;
199                 }
200
201                 try {
202                     $resourceTranslatedParsed = $yaml->parse(file_get_contents($resourceTranslated));
203                 } catch (ParseException $e) {
204                     $io->error($resourceTranslated . ':' . $e->getMessage());
205                 }
206
207                 $diffStatistics = ['total' => 0, 'equal' => 0, 'diff' => 0];
208                 $diff = $this->nestedArray->arrayDiff($englishFileParsed, $resourceTranslatedParsed, true, $diffStatistics);
209
210                 $yamlKeys = 0;
211                 if (!empty($diff)) {
212                     $diffFlatten = [];
213                     $keyFlatten = '';
214                     $this->nestedArray->yamlFlattenArray($diff, $diffFlatten, $keyFlatten);
215
216                     // Determine how many yaml keys were returned as values
217                     foreach ($diffFlatten as $yamlKey => $yamlValue) {
218                         if ($this->isYamlKey($yamlValue)) {
219                             $yamlKeys++;
220                         }
221                     }
222                 }
223
224                 $statistics[$langCode]['total'] += $diffStatistics['total'];
225                 $statistics[$langCode]['equal'] += ($diffStatistics['equal'] - $yamlKeys);
226                 $statistics[$langCode]['diff'] += $diffStatistics['diff'] + $yamlKeys;
227             }
228         }
229
230         $stats = [];
231         foreach ($statistics as $langCode => $statistic) {
232             $index = isset($languages[$langCode])? $languages[$langCode]: $langCode;
233             $stats[] = [
234                 'name' => $index,
235                 'percentage' => round($statistic['diff']/$statistic['total']*100, 2),
236                 'iso' => $langCode
237             ];
238         }
239
240         usort(
241             $stats, function ($a, $b) {
242                 return $a["percentage"] <  $b["percentage"];
243             }
244         );
245
246         return $stats;
247     }
248 }