2
2
3
3
namespace Drush \Drupal \Commands \core ;
4
4
5
+ use Consolidation \AnnotatedCommand \CommandData ;
6
+ use Drupal \Component \Gettext \PoStreamWriter ;
7
+ use Drupal \Core \Config \ConfigFactoryInterface ;
5
8
use Drupal \Core \Extension \ModuleHandlerInterface ;
9
+ use Drupal \Core \Language \LanguageInterface ;
10
+ use Drupal \Core \Language \LanguageManagerInterface ;
6
11
use Drupal \Core \State \StateInterface ;
12
+ use Drupal \language \Entity \ConfigurableLanguage ;
13
+ use Drupal \locale \PoDatabaseReader ;
7
14
use Drush \Commands \DrushCommands ;
8
15
9
16
class LocaleCommands extends DrushCommands
10
17
{
11
18
19
+ protected $ languageManager ;
20
+
21
+ protected $ configFactory ;
22
+
12
23
protected $ moduleHandler ;
13
24
14
25
protected $ state ;
15
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
+
16
43
/**
17
44
* @return \Drupal\Core\Extension\ModuleHandlerInterface
18
45
*/
@@ -29,8 +56,10 @@ public function getState()
29
56
return $ this ->state ;
30
57
}
31
58
32
- public function __construct (ModuleHandlerInterface $ moduleHandler , StateInterface $ state )
59
+ public function __construct (LanguageManagerInterface $ languageManager , ConfigFactoryInterface $ configFactory , ModuleHandlerInterface $ moduleHandler , StateInterface $ state )
33
60
{
61
+ $ this ->languageManager = $ languageManager ;
62
+ $ this ->configFactory = $ configFactory ;
34
63
$ this ->moduleHandler = $ moduleHandler ;
35
64
$ this ->state = $ state ;
36
65
}
@@ -128,4 +157,186 @@ public function update($options = ['langcodes' => self::REQ])
128
157
129
158
drush_backend_batch_process ();
130
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
+ }
131
342
}
0 commit comments