Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / drush / drush / src / Drupal / Commands / core / LocaleCommands.php
1 <?php
2
3 namespace Drush\Drupal\Commands\core;
4
5 use Consolidation\AnnotatedCommand\CommandData;
6 use Drupal\Component\Gettext\PoStreamWriter;
7 use Drupal\Core\Config\ConfigFactoryInterface;
8 use Drupal\Core\Extension\ModuleHandlerInterface;
9 use Drupal\Core\Language\LanguageInterface;
10 use Drupal\Core\Language\LanguageManagerInterface;
11 use Drupal\Core\State\StateInterface;
12 use Drupal\language\Entity\ConfigurableLanguage;
13 use Drupal\locale\PoDatabaseReader;
14 use Drush\Commands\DrushCommands;
15
16 class LocaleCommands extends DrushCommands
17 {
18
19     protected $languageManager;
20
21     protected $configFactory;
22
23     protected $moduleHandler;
24
25     protected $state;
26
27     /**
28      * @return \Drupal\Core\Language\LanguageManagerInterface
29      */
30     protected function getLanguageManager()
31     {
32         return $this->languageManager;
33     }
34
35     /**
36      * @return \Drupal\Core\Config\ConfigFactoryInterface
37      */
38     protected function getConfigFactory()
39     {
40         return $this->configFactory;
41     }
42
43     /**
44      * @return \Drupal\Core\Extension\ModuleHandlerInterface
45      */
46     public function getModuleHandler()
47     {
48         return $this->moduleHandler;
49     }
50
51     /**
52      * @return mixed
53      */
54     public function getState()
55     {
56         return $this->state;
57     }
58
59     public function __construct(LanguageManagerInterface $languageManager, ConfigFactoryInterface $configFactory, ModuleHandlerInterface $moduleHandler, StateInterface $state)
60     {
61         $this->languageManager = $languageManager;
62         $this->configFactory = $configFactory;
63         $this->moduleHandler = $moduleHandler;
64         $this->state = $state;
65     }
66
67     /**
68      * Checks for available translation updates.
69      *
70      * @command locale:check
71      * @aliases locale-check
72      * @validate-module-enabled locale
73      */
74     public function check()
75     {
76         $this->getModuleHandler()->loadInclude('locale', 'inc', 'locale.compare');
77
78         // Check translation status of all translatable project in all languages.
79         // First we clear the cached list of projects. Although not strictly
80         // necessary, this is helpful in case the project list is out of sync.
81         locale_translation_flush_projects();
82         locale_translation_check_projects();
83
84         // Execute a batch if required. A batch is only used when remote files
85         // are checked.
86         if (batch_get()) {
87             drush_backend_batch_process();
88         }
89     }
90
91     /**
92      * Imports the available translation updates.
93      *
94      * @see TranslationStatusForm::buildForm()
95      * @see TranslationStatusForm::prepareUpdateData()
96      * @see TranslationStatusForm::submitForm()
97      *
98      * @todo This can be simplified once https://www.drupal.org/node/2631584 lands
99      *   in Drupal core.
100      *
101      * @command locale:update
102      * @aliases locale-update
103      * @option langcodes A comma-separated list of language codes to update. If omitted, all translations will be updated.
104      * @validate-module-enabled locale
105      */
106     public function update($options = ['langcodes' => self::REQ])
107     {
108         $module_handler = $this->getModuleHandler();
109         $module_handler->loadInclude('locale', 'fetch.inc');
110         $module_handler->loadInclude('locale', 'bulk.inc');
111
112         $langcodes = [];
113         foreach (locale_translation_get_status() as $project_id => $project) {
114             foreach ($project as $langcode => $project_info) {
115                 if (!empty($project_info->type) && !in_array($langcode, $langcodes)) {
116                     $langcodes[] = $langcode;
117                 }
118             }
119         }
120
121         if ($passed_langcodes = $options['langcodes']) {
122             $langcodes = array_intersect($langcodes, explode(',', $passed_langcodes));
123             // @todo Not selecting any language code in the user interface results in
124             //   all translations being updated, so we mimick that behavior here.
125         }
126
127         // Deduplicate the list of langcodes since each project may have added the
128         // same language several times.
129         $langcodes = array_unique($langcodes);
130
131         // @todo Restricting by projects is not possible in the user interface and is
132         //   broken when attempting to do it in a hook_form_alter() implementation so
133         //   we do not allow for it here either.
134         $projects = [];
135
136         // Set the translation import options. This determines if existing
137         // translations will be overwritten by imported strings.
138         $translationOptions = _locale_translation_default_update_options();
139
140         // If the status was updated recently we can immediately start fetching the
141         // translation updates. If the status is expired we clear it an run a batch to
142         // update the status and then fetch the translation updates.
143         $last_checked = $this->getState()->get('locale.translation_last_checked');
144         if ($last_checked < REQUEST_TIME - LOCALE_TRANSLATION_STATUS_TTL) {
145             locale_translation_clear_status();
146             $batch = locale_translation_batch_update_build([], $langcodes, $translationOptions);
147             batch_set($batch);
148         } else {
149             // Set a batch to download and import translations.
150             $batch = locale_translation_batch_fetch_build($projects, $langcodes, $translationOptions);
151             batch_set($batch);
152             // Set a batch to update configuration as well.
153             if ($batch = locale_config_batch_update_components($translationOptions, $langcodes)) {
154                 batch_set($batch);
155             }
156         }
157
158         drush_backend_batch_process();
159     }
160
161     /**
162      * Imports to a gettext translation file.
163      *
164      * @command locale:import
165      * @validate-module-enabled locale
166      * @param $langcode The language code of the imported translations.
167      * @param $file Path and file name of the gettext file.
168      * @option type The type of translations to be imported, defaults to 'not-customized'. Options:
169      *   - customized: Treat imported strings as custom translations.
170      *   - not-customized: Treat imported strings as not-custom translations.
171      * @option override Whether and how imported strings will override existing translations. Defaults to the Import behavior configurred in the admin interface. Options:
172      *  - none: Don't overwrite existing translations. Only append new translations.
173      *  - customized: Only override existing customized translations.
174      *  - not-customized: Only override non-customized translations, customized translations are kept.
175      *  - all: Override any existing translation.
176      * @usage drush locale-import nl drupal-8.4.2.nl.po
177      *   Import the Dutch drupal core translation.
178      * @usage drush locale-import nl custom-translations.po --type=custom --override=all
179      *   Import customized Dutch translations and override any existing translation.
180      * @aliases locale-export
181      * @throws \Exception
182      */
183     public function import($langcode, $file, $options = ['type' => self::OPT, 'override' => self::OPT])
184     {
185         if (!drush_file_not_empty($file)) {
186             throw new \Exception(dt('File @file not found or empty.', ['@file' => $file]));
187         }
188
189         $language = $this->getTranslatableLanguage($langcode, true);
190
191         $this->getModuleHandler()->loadInclude('locale', 'translation.inc');
192         $this->getModuleHandler()->loadInclude('locale', 'bulk.inc');
193
194         $translationOptions = _locale_translation_default_update_options();
195         $translationOptions['langcode'] = $language->getId();
196         $translationOptions['customized'] = $this->convertCustomizedType($options['type']);
197         $override = $this->convertOverrideOption($options['override']);
198         if ($override) {
199             $translationOptions['overwrite_options'] = $override;
200         }
201
202         $poFile = (object) [
203             'filename' => basename($file),
204             'uri' => $file,
205         ];
206         $poFile = locale_translate_file_attach_properties($poFile, $translationOptions);
207
208         // Set a batch to download and import translations.
209         $batch = locale_translate_batch_build([$poFile->uri => $poFile], $translationOptions);
210         batch_set($batch);
211         if ($batch = locale_config_batch_update_components($translationOptions, [$language->getId()])) {
212             batch_set($batch);
213         }
214
215         drush_backend_batch_process();
216     }
217
218     /**
219      * Converts input of translation type.
220      *
221      * @param $type
222      * @return integer
223      */
224     private function convertCustomizedType($type)
225     {
226         switch ($type) {
227             case 'customized':
228                 $result = LOCALE_CUSTOMIZED;
229                 break;
230
231             default:
232                 $result = LOCALE_NOT_CUSTOMIZED;
233                 break;
234         }
235
236         return $result;
237     }
238
239     /**
240      * Converts input of override option.
241      *
242      * @param $override
243      * @return array
244      */
245     private function convertOverrideOption($override)
246     {
247         $result = [];
248
249         switch ($override) {
250             case 'none':
251                 $result = [
252                     'not_customized' => false,
253                     'customized' => false,
254                 ];
255                 break;
256
257             case 'customized':
258                 $result = [
259                     'not_customized' => false,
260                     'customized' => true,
261                 ];
262                 break;
263
264             case 'not-customized':
265                 $result = [
266                     'not_customized' => true,
267                     'customized' => false,
268                 ];
269                 break;
270
271             case 'all':
272                 $result = [
273                     'not_customized' => true,
274                     'customized' => true,
275                 ];
276                 break;
277         }
278
279         return $result;
280     }
281
282     /**
283      * Get translatable language object.
284      *
285      * @param string $langcode The language code of the language object.
286      * @param bool $addLanguage Create language when not available.
287      * @return LanguageInterface|null
288      * @throws \Exception
289      */
290     private function getTranslatableLanguage($langcode, $addLanguage = false)
291     {
292         if (!$langcode) {
293             return null;
294         }
295
296         $language = $this->getLanguageManager()->getLanguage($langcode);
297
298         if (!$language) {
299             if ($addLanguage) {
300                 $language = ConfigurableLanguage::createFromLangcode($langcode);
301                 $language->save();
302
303                 $this->logger->success(dt('Added language @language', [
304                     '@language' => $language->label(),
305                 ]));
306             } else {
307                 throw new \Exception(dt('Language code @langcode is not configured.', [
308                     '@langcode' => $langcode,
309                 ]));
310             }
311         }
312
313         if (!$this->isTranslatable($language)) {
314             throw new \Exception(dt('Language code @langcode is not translatable.', [
315                 '@langcode' => $langcode,
316             ]));
317         }
318
319         return $language;
320     }
321
322     /**
323      * Check if language is translatable.
324      *
325      * @param LanguageInterface $language
326      * @return bool
327      */
328     private function isTranslatable(LanguageInterface $language)
329     {
330         if ($language->isLocked()) {
331             return false;
332         }
333
334         if ($language->getId() != 'en') {
335             return true;
336         }
337
338         return (bool)$this->getConfigFactory()
339             ->get('locale.settings')
340             ->get('translate_english');
341     }
342 }