From d62556d564ff5e1ad6f183ab07a684be60608a39 Mon Sep 17 00:00:00 2001 From: fgm Date: Sat, 17 Feb 2018 14:33:28 +0100 Subject: [PATCH 01/16] Issue #2914081 by Grimreaper, fgm: Convert for Drush 8/9/console --- README.md | 24 ++ composer.json | 18 +- drush.services.yml | 12 + drush_language.drush.inc | 4 +- drush_language.info.yml | 6 +- src/Commands/DrushLanguageCommands.php | 557 +++++++++++++++++++++++++++++++++ 6 files changed, 615 insertions(+), 6 deletions(-) create mode 100644 README.md create mode 100644 drush.services.yml create mode 100644 src/Commands/DrushLanguageCommands.php diff --git a/README.md b/README.md new file mode 100644 index 0000000..5d0ceea --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Drush 9 language commands + +## Upgrading + +At the time of this commit (Drush 9.0.0-beta5), Drush 9 needs commands using +Drupal services to be placed in a module, which was not necessary for Drush 8. + +Quoting Greg Anderson in https://github.com/drush-ops/drush/issues/3050 : + +
Drush extensions that are not part of a module can be policy files + (hooks) or standalone commands, but cannot do dependency injection. +
+ +As a result this plugin is no longer of type `drupal-drush` but is a normal +Drupal module. Assuming it is being used in a Composer `drupal-project` workflow, +this means: + +* Removing the `drush/drush_language/` or `drush/contrib/drush_language` + directory. +* Running `composer update` to obtain the new version of the plugin implemented + as a module and placed in the `web/modules/contrib/drush_language` directory. +* Enabling the `drush_language` module to make the commands discoverable by + Drush. + diff --git a/composer.json b/composer.json index c84c222..2e2eec7 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,20 @@ { - "name": "drupal/drush_language", + "autoload": { + "psr-4": { + "Drush\\": "src" + } + }, "description": "Provides drush commands", - "type": "drupal-drush", + "extra": { + "drush": { + "services": { + "drush.services.yml": "^9" + } + } + }, "license": "GPL-2.0+", "minimum-stability": "dev", - "require": { } + "name": "drupal/drush_language", + "require": { }, + "type": "drupal-module" } diff --git a/drush.services.yml b/drush.services.yml new file mode 100644 index 0000000..7476209 --- /dev/null +++ b/drush.services.yml @@ -0,0 +1,12 @@ +services: + drush_language.commands: + class: \Drush\Commands\DrushLanguageCommands + arguments: + - '@cache.page' + - '@config.factory' + - '@country_manager' + - '@entity_type.manager' + - '@language_manager' + - '@module_handler' + tags: + - { name: drush.command } diff --git a/drush_language.drush.inc b/drush_language.drush.inc index 93f6096..521e907 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -173,7 +173,8 @@ function drush_language_enable() { $languages = language_list(); if (array_key_exists($langcode, $languages)) { if (!$languages[$langcode]->enabled) { - // disable the default english + // Disable the default english. + // FIXME find the D8 equivalent: this is D7 logic. db_update('languages') ->condition('language', $langcode) ->fields(array( @@ -181,6 +182,7 @@ function drush_language_enable() { )) ->execute(); + // FIXME probably needs a more generic invalidation. // Changing the language settings impacts the interface. cache_clear_all('*', 'cache_page', TRUE); drush_log(dt("Enabled language : !language ", array('!language' => $langcode)), 'ok'); diff --git a/drush_language.info.yml b/drush_language.info.yml index 31f7289..324c415 100644 --- a/drush_language.info.yml +++ b/drush_language.info.yml @@ -1,5 +1,7 @@ -name: Language drush -type: module core: 8.x dependencies: - language +description: 'Provides Drush commands for language manipulation' +name: 'Drush Language commands' +package: Multilingual +type: module diff --git a/src/Commands/DrushLanguageCommands.php b/src/Commands/DrushLanguageCommands.php new file mode 100644 index 0000000..c566c3a --- /dev/null +++ b/src/Commands/DrushLanguageCommands.php @@ -0,0 +1,557 @@ +cachePage = $cachePage; + $this->configFactory = $configFactory; + $this->countryManager = $countryManager; + $this->entityTypeManager = $entityTypeManager; + $this->languageManager = $languageManager; + $this->moduleHandler = $moduleHandler; + } + + /** + * Add and import one or more new language definitions. + * + * @param array $langcodes + * A comma-delimited list of langcodes for which a definition will be added. + * + * @command language:add + * + * @aliases langadd,language-add + */ + public function add(array $langcodes) { + $langcodes = StringUtils::csvToArray($langcodes); + + if (empty($langcodes)) { + $this->logger()->error('Please provide one or more comma-separated language codes as arguments.'); + return; + } + + foreach ($langcodes as $langcode) { + $messageArgs = ['langcode' => $langcode]; + // In the foreach loop because the list changes on successful iterations. + $languages = $this->languageManager->getLanguages(); + + // Do not re-add existing languages. + if (isset($languages[$langcode])) { + $this->logger()->warning('The language with code {langcode} already exists.', $messageArgs); + continue; + } + + // Only allow adding languages for predefined langcodes. + // In the foreach loop because the list changes on successful iterations. + $predefined = $this->languageManager->getStandardLanguageListWithoutConfigured(); + if (!isset($predefined[$langcode])) { + $this->logger()->warning('Invalid language code {langcode}', $messageArgs); + continue; + } + + // Add the language definition. + $language = ConfigurableLanguage::createFromLangcode($langcode); + $language->save(); + + // Download and import translations for the newly added language if + // interface translation is enabled. + if ($this->moduleHandler->moduleExists('locale')) { + module_load_include('fetch.inc', 'locale'); + $options = _locale_translation_default_update_options(); + if ($batch = locale_translation_batch_update_build([], [$langcode], $options)) { + batch_set($batch); + $batch =& batch_get(); + $batch['progressive'] = FALSE; + + // Process the batch. + drush_backend_batch_process(); + } + } + + $this->logger()->info('Added language: {langcode}', $messageArgs); + } + } + + /** + * Enable one or more already defined languages. + * + * @param array $langcodes + * A comma-separated list of langcodes which will be enabled. + * + * @command language:enable + * + * @aliases langen,language-enable + */ + public function enable(array $langcodes) { + $langcodes = StringUtils::csvToArray($langcodes); + + if (empty($langcodes)) { + $this->logger()->error('Please provide one or more comma-separated language codes as arguments.'); + return; + } + + foreach ($langcodes as $langcode) { + $messageArgs = ['langcode' => $langcode]; + + // In the foreach loop because the list changes on successful iterations. + $languages = $this->languageManager->getLanguages(); + + // Skip nonexistent languages. + if (!isset($languages[$langcode])) { + $this->logger()->warning('Specified language does not exist {langcode}', $messageArgs); + continue; + } + + // Skip already-enabled languages. + if ($languages[$langcode]->enabled) { + $this->logger()->warning('Language already enabled: !language', $messageArgs); + continue; + } + + // FIXME find the D8 equivalent: this is D7 logic. + db_update('languages') + ->condition('language', $langcode) + ->fields([ + 'enabled' => 1, + ]) + ->execute(); + + // FIXME probably needs a more generic invalidation. + // Changing the language settings impacts the interface. + $this->cachePage->deleteAll(); + $this->logger()->info('Enabled language : {langcode}', $messageArgs); + } + } + + /** + * Disable one or more already defined languages. + * + * @param array $langcodes + * The comma-separated langcodes of the languages which will be disabled. + * + * @command language:disable + * + * @aliases langdis,language-disable + */ + public function disable(array $langcodes) { + $langcodes = StringUtils::csvToArray($langcodes); + + if (empty($langcodes)) { + $this->logger()->error('Please provide one or more comma-separated language codes as arguments.'); + return; + } + + foreach ($langcodes as $langcode) { + $messageArgs = ['langcode' => $langcode]; + // In the foreach loop because the list changes on successful iterations. + $languages = $this->languageManager->getLanguages(); + + // Skip nonexistent languages. + if (!isset($languages[$langcode])) { + $this->logger()->warning('Specified language does not exist {langcode}', $messageArgs); + continue; + } + + // Skip locked languages. + if ($languages[$langcode]->isLocked()) { + $this->logger()->warning('Not disabling locked specified language {langcode}', $messageArgs); + continue; + } + + // Skip already-disabled languages. + if (!$languages[$langcode]->enabled) { + $this->logger()->warning('Language already disabled: {langcode}', $messageArgs); + continue; + } + + // FIXME find the D8 equivalent: this is D7 logic. + db_update('languages') + ->condition('language', $langcode) + ->fields([ + 'enabled' => 0, + ]) + ->execute(); + + // FIXME probably needs a more generic invalidation. + // Changing the language settings impacts the interface. + $this->cachePage->deleteAll(); + $this->logger()->info('Disabled language : {langcode}', $messageArgs); + } + } + + /** + * Assign an enabled language as default. + * + * @param string $langcode + * The langcode of the language which will be set as the default language. + * + * @command language:default + * + * @aliases langdef, language-default + */ + public function languageDefault($langcode) { + $messageArgs = ['langcode' => $langcode]; + $languages = $this->languageManager->getLanguages(); + if (!isset($languages[$langcode])) { + $this->logger()->warning('Specified language does not exist {langcode}', $messageArgs); + return; + } + + /** @var \Drupal\language\ConfigurableLanguageInterface $default_language */ + $default_language = ConfigurableLanguage::load($langcode); + $default_language->set('default', TRUE) + ->save(); + $this->logger()->info('{langcode} assigned as default', $messageArgs); + } + + /** + * Import a single .po file. + * + * @param string $langcode + * The langcode of the language in which the string will be imported. + * @param array $poFiles + * Comma-separated list of paths .po files containing the translations. + * + * @command language:import:translations + * + * @option replace Replace existing translations. + * + * @usage Import multiple files + * drush langimp eo file1.po file2.po ... + * @usage Import with replacement + * drush langimp eo file.po --replace + * + * @aliases langimp,language-import,language-import-translations + * + * @see \Drupal\locale\Form\ImportForm::submitForm + * + * @todo Implement \Drupal\locale\Form\ImportForm::buildForm + * @todo This can be simplified once https://www.drupal.org/node/2631584 + * lands + * in Drupal core. + */ + public function importTranslations( + string $langcode, + array $poFiles, + array $options = ['replace' => FALSE]) { + $this->moduleHandler->loadInclude('locale', 'translation.inc'); + + $poFiles = StringUtils::csvToArray($poFiles); + + // Add language, if not yet supported. + $language = $this->languageManager->getLanguage($langcode); + if (empty($language)) { + $language = ConfigurableLanguage::createFromLangcode($langcode); + $language->save(); + $this->logger()->notice('Language {langcode} ({language}) has been created.', [ + 'langcode' => $langcode, + 'language' => $this->t($language->label()), + ]); + } + + $this->moduleHandler->loadInclude('locale', 'bulk.inc'); + $replace = isset($options['replace']) ? $options['replace'] : FALSE; + $buildOptions = array_merge(_locale_translation_default_update_options(), [ + 'langcode' => $langcode, + 'customized' => $replace ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, + 'overwrite_options' => $replace + ? ['customized' => 1, 'not_customized' => 1] + : ['customized' => 0, 'not_customized' => 1], + ]); + + // Import language files. + $files = []; + $langcodes = []; + foreach ($poFiles as $poFile) { + // Probably not an absolute path: test from the original $cwd. + if (!file_exists($poFile)) { + $poFile = drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . $poFile; + } + + // Ensure we have the file intended for upload. + if (file_exists($poFile)) { + // Create file object. + $file = locale_translate_file_create($poFile); + // Extract project, version and language code from the file name + // Supported: + // - {project}-{version}.{langcode}.po, {prefix}.{langcode}.po + // - {langcode}.po + // or from user input. + $file = locale_translate_file_attach_properties($file, $buildOptions); + if ($file->langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) { + $file->langcode = $langcode; + if (empty($file->version) && !empty($file->project) && !empty($file->langcode)) { + $sources = locale_translation_get_status(); + $source = $sources[$file->project][$file->langcode]; + if (isset($source->version)) { + $file->version = $source->version; + } + } + } + $langcodes[] = $file->langcode; + $files[] = $file; + } + else { + $this->logger()->error('File to import at {filepath} not found.', [ + 'filepath' => $poFile, + ]); + } + } + + $batch = locale_translate_batch_build($files, $buildOptions); + batch_set($batch); + + // Create or update all configuration translations for this language. + $langcodes = array_unique($langcodes); + if ($batch = locale_config_batch_update_components($buildOptions, $langcodes)) { + batch_set($batch); + } + + drush_backend_batch_process(); + $this->logger()->info('Import complete.'); + } + + /** + * Export strings of a language as a .po file. + * + * @param string $langcode + * The langcode of the language to exported. + * @param string $poFile + * Path to a .po file. Use "-" or /dev/stdin to use standard output. + * + * @command language:export:translations + * + * @option status The statuses to export, defaults to 'customized'. + * This can be a comma-separated list of 'customized', 'not-customized', + * 'not-translated', or 'all'. + * + * @usage Export the french translation + * drush langexp fr fr.po + * + * @aliases langexp,language-export,language-export-translations + * + * @todo Implement \Drupal\locale\Form\ExportForm::buildForm + * @todo This can be simplified once https://www.drupal.org/node/2631584 + * lands + * in Drupal core. + * + * @throws \Exception + * Invalid values passed. + */ + public function exportTranslations( + string $langcode, + string $poFile, + array $options = ['status' => NULL] + ) { + // Ensure the langcode matches an existing language. + $language = $this->languageManager->getLanguage($langcode); + if (empty($language)) { + throw new \Exception('drush language-export: no such language'); + } + + // Validate export statuses. + $exportStatusesAllowed = [ + // Internal-value => input-value. + 'customized' => 'customized', + 'not_customized' => 'not-customized', + 'not_translated' => 'not-translated', + ]; + $exportStatusesInput = isset($options['status']) ? $options['status'] : ['customized']; + $exportStatusesInput = array_values($exportStatusesInput); + if ($exportStatusesInput == ['all']) { + $exportStatusesInput = $exportStatusesAllowed; + } + + $exportStatusesUnknown = array_diff($exportStatusesInput, $exportStatusesAllowed); + if ($exportStatusesUnknown) { + $statusArgs = ['options' => implode(', ', $exportStatusesUnknown)]; + throw new \Exception($this->t('drush language-export: Unknown status options: {options}', + $statusArgs)); + } + + $exportStatusesFiltered = array_intersect($exportStatusesAllowed, $exportStatusesInput); + $exportStatuses = array_fill_keys(array_keys($exportStatusesFiltered), TRUE); + + // Relative path should be relative to cwd(), rather than Drupal root-dir. + $filePath = drush_is_absolute_path($poFile) + ? $poFile + : drush_get_context('DRUSH_DRUPAL_ROOT') . DIRECTORY_SEPARATOR . $poFile; + + // Check if file_path exists and is writable. + $dir = dirname($filePath); + if (!file_prepare_directory($dir)) { + file_prepare_directory($dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY); + } + + $reader = new PoDatabaseReader(); + $language_name = ''; + if ($language != NULL) { + $reader->setLangcode($language->getId()); + $reader->setOptions($exportStatuses); + $languages = $this->languageManager->getLanguages(); + $language_name = isset($languages[$language->getId()]) ? $languages[$language->getId()]->getName() : ''; + } + $item = $reader->readItem(); + if (!empty($item)) { + $header = $reader->getHeader(); + $header->setProjectName($this->configFactory->get('system.site')->get('name')); + $header->setLanguageName($language_name); + + $writer = new PoStreamWriter(); + $writer->setUri($filePath); + $writer->setHeader($header); + + $writer->open(); + $writer->writeItem($item); + $writer->writeItems($reader); + $writer->close(); + + $this->logger()->info('Export complete.'); + } + else { + throw new \Exception($this->t('Nothing to export.')); + } + } + + /** + * Export all translations to files. + * + * @param string $langcodes + * A comma-separated list of the language codes to export. Defaults to all + * enabled languages. + * + * @command language:export:all:translations + * + * @option file-pattern The target file pattern. Defaults to + * 'translations/custom/%language.po'. Note that this is the only place + * where this module's auto-importing works. + * @option all If set, exports all translations instead of only customized + * ones. + * + * @aliases langexpall,language-export-all,language-export-all-translations + */ + public function exportAllTranslations( + string $langcodes = NULL, + array $options = [ + 'all' => NULL, + 'file-pattern' => NULL, + ] + ) { + $langcodes = StringUtils::csvToArray((array) $langcodes); + + if (empty($langcodes)) { + $languages = $this->languageManager->getLanguages(); + $langcodes = array_keys($languages); + } + + $file_pattern = isset($options['file_pattern']) + ? $options['file_pattern'] + : 'translations/custom/%language.po'; + + $exportOptions = [ + 'status' => empty($options['all']) ? ['customized'] : ['all'], + ]; + + foreach ($langcodes as $langcode) { + $filePathRelative = preg_replace('/%language/u', $langcode, $file_pattern); + $fileNameAbsolute = drush_is_absolute_path($filePathRelative) + ? $filePathRelative + : drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . $filePathRelative; + + drush_invoke_process('@self', 'language:export:translation', [ + $langcode, + $fileNameAbsolute, + ], $exportOptions); + + $this->logger()->info('Exported translations for language {langcode} to file !file.', [ + 'langcode' => $langcode, + '!file' => $filePathRelative, + ]); + } + } + +} -- 2.1.4 From d6d0adf96e149a6c0e4d0e1801f4d0307d9cc306 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 14:48:17 +0100 Subject: [PATCH 02/16] Issue #2914081 by Grimreaper: Fix coding standards --- README.md | 4 +- composer.json | 19 ++++------ drush_language.drush.inc | 69 +++++++++++++++++----------------- drush_language.info.yml | 10 ++--- src/Commands/DrushLanguageCommands.php | 9 ++++- 5 files changed, 56 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 5d0ceea..710252e 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ Quoting Greg Anderson in https://github.com/drush-ops/drush/issues/3050 : As a result this plugin is no longer of type `drupal-drush` but is a normal -Drupal module. Assuming it is being used in a Composer `drupal-project` workflow, -this means: +Drupal module. Assuming it is being used in a Composer `drupal-project` +workflow, this means: * Removing the `drush/drush_language/` or `drush/contrib/drush_language` directory. diff --git a/composer.json b/composer.json index 2e2eec7..9649a89 100644 --- a/composer.json +++ b/composer.json @@ -1,20 +1,15 @@ { - "autoload": { - "psr-4": { - "Drush\\": "src" - } - }, - "description": "Provides drush commands", + "name": "drupal/drush_language", + "description": "Provides Drush commands for language manipulation", + "type": "drupal-module", + "license": "GPL-2.0+", + "minimum-stability": "dev", + "require": { }, "extra": { "drush": { "services": { "drush.services.yml": "^9" } } - }, - "license": "GPL-2.0+", - "minimum-stability": "dev", - "name": "drupal/drush_language", - "require": { }, - "type": "drupal-module" + } } diff --git a/drush_language.drush.inc b/drush_language.drush.inc index 521e907..0c33e82 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -1,17 +1,21 @@ 'drush langimp', 'Import single file with explicit langcode' => 'drush langimp --langcode=ru file.po', 'Import not-customized (e.g. module) translations, without replacing custom translations, with auto langcode (these are the recognized patterns)' - => 'drush langimp --langcode=eo --no-set-customized --no-replace-customized de.po foomodule.fr.po barmodule-8.x-2.2-rc1.es.po', + => 'drush langimp --langcode=eo --no-set-customized --no-replace-customized de.po foomodule.fr.po barmodule-8.x-2.2-rc1.es.po', ), 'options' => array( 'langcode' => array( 'description' => 'Language code to be imported. If not given, extracted from file name.', - 'value' => 'optional' + 'value' => 'optional', ), 'replace-customized' => array( 'description' => 'Replace existing customized translations. Defaults to true.', - 'value' => 'optional' + 'value' => 'optional', ), 'replace-not-customized' => array( 'description' => 'Replace existing not-customized translations. Defaults to true.', - 'value' => 'optional' + 'value' => 'optional', ), 'set-customized' => array( 'description' => 'Set all existing translations as being customized. Defaults to true.', - 'value' => 'optional' + 'value' => 'optional', ), 'autocreate-language' => array( 'description' => 'Autocreate any imported language if it does not yet exist. Defaults to true.', - 'value' => 'optional' + 'value' => 'optional', ), ), 'aliases' => array('langimp', 'language-import'), @@ -83,28 +87,26 @@ function drush_language_drush_command() { 'description' => "Export string of a language as one or more .po files", 'examples' => array( 'Export all custom translations into the directory defined in $settings[\'custom_translations_directory\'].' - => 'drush langexp', + => 'drush langexp', 'Export all german translated strings' => 'drush langexp --langcodes=de --status=customized,not-customized --file=all-de.po', 'Export untranslated strings from all languages to current dir' => 'drush langexp --status=untranslated --file=./todo-%langcode.po', ), 'options' => array( 'statuses' => array( - 'description' => 'The statuses to export, defaults to \'customized\'.' . "\n" . - 'This can be a comma-separated list of \'customized\', \'not-customized\', \'not-translated\', or (as abbreviation) \'all\'.', - 'value' => 'optional' + 'description' => 'The statuses to export, defaults to \'customized\'.' . "\n" . 'This can be a comma-separated list of \'customized\', \'not-customized\', \'not-translated\', or (as abbreviation) \'all\'.', + 'value' => 'optional', ), 'langcodes' => array( 'description' => 'The language codes to export, comma-separated. Defaults to all enabled languages.', - 'value' => 'optional' + 'value' => 'optional', ), 'file' => array( - 'description' => 'The target file pattern. You can use %langcode as placeholder. Defaults to "%language.po". ' . - 'If the path is relative and does not start with ".", $settings[\'custom_translations_directory\'] must be defined and the path is relatve to that directory.', - 'value' => 'optional' + 'description' => 'The target file pattern. You can use %langcode as placeholder. Defaults to "%language.po". ' . 'If the path is relative and does not start with ".", $settings[\'custom_translations_directory\'] must be defined and the path is relatve to that directory.', + 'value' => 'optional', ), 'force' => array( 'description' => 'Write file even if no translations. Defaults to true.', - 'value' => 'optional' + 'value' => 'optional', ), ), 'aliases' => array('langexp', 'language-export'), @@ -113,7 +115,7 @@ function drush_language_drush_command() { } /** - * Add a language + * Add a language. */ function drush_drush_language_language_add() { if (!\Drupal::moduleHandler()->moduleExists('language')) { @@ -161,7 +163,7 @@ function drush_drush_language_language_add() { } /** - * Enable a language + * Enable a language. */ function drush_language_enable() { $args = func_get_args(); @@ -211,7 +213,7 @@ function drush_drush_language_disable() { $languages = $language_manager->getLanguages(); if (array_key_exists($langcode, $languages)) { if ($languages[$langcode]->is) { - // disable the default english + // Disable the default english. db_update('languages') ->condition('language', $langcode) ->fields(array( @@ -231,7 +233,7 @@ function drush_drush_language_disable() { } /** - * Assigns the default language + * Assigns the default language. */ function drush_drush_language_default() { $args = func_get_args(); @@ -240,7 +242,7 @@ function drush_drush_language_default() { } foreach ($args as $langcode) { - // get all the languages + // Get all the languages. $language_manager = \Drupal::languageManager(); $languages = $language_manager->getLanguages(); if (array_key_exists($langcode, $languages)) { @@ -278,22 +280,21 @@ function drush_drush_language_language_import_translations() { $opt_autocreate_language = drush_get_option('autocreate-language', TRUE); if (!$file_paths) { - if ($dir = \Drupal\Core\Site\Settings::get('custom_translations_directory')) { + if ($dir = Settings::get('custom_translations_directory')) { $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'); $file_paths = glob("$drupal_root/$dir/*.po"); } else { - drush_log(dt('Nothing to do, no file given and no custom translation directory set.'), \Drush\Log\LogLevel::SUCCESS); + drush_log(dt('Nothing to do, no file given and no custom translation directory set.'), LogLevel::SUCCESS); } } $importer_options = array_merge(_locale_translation_default_update_options(), [ 'langcode' => $opt_langcode, - 'customized' => $opt_set_customized ? - LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, + 'customized' => $opt_set_customized ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, 'overwrite_options' => [ - 'customized' => (int)$opt_replace_customized, - 'not_customized' => (int)$opt_replace_not_customized, + 'customized' => (int) $opt_replace_customized, + 'not_customized' => (int) $opt_replace_not_customized, ], ]); @@ -378,7 +379,7 @@ function drush_drush_language_language_export_translations() { // Massage options. // Massage translation statuses. $export_statuses_allowed = [ - // internal-value => input-value + // internal-value => input-value. 'customized' => 'customized', 'not_customized' => 'not-customized', 'not_translated' => 'not-translated', @@ -397,7 +398,7 @@ function drush_drush_language_language_export_translations() { // Massage file path pattern. if (!drush_is_absolute_path($opt_filepath) && !('./' === substr($opt_filepath, 0, 2))) { - $opt_filedir = \Drupal\Core\Site\Settings::get('custom_translations_directory'); + $opt_filedir = Settings::get('custom_translations_directory'); if (!$opt_filedir) { return drush_set_error('DRUSH_LANGUAGE', dt('Can not export, relative path given and no $settings[\'custom_translations_directory\'] defined. You can instead use an absolute filename or one starting with "./".')); } @@ -433,7 +434,7 @@ function drush_drush_language_language_export_translations() { // Check if file_path exists and is writable. $dir = dirname($filepath); - if(!file_prepare_directory($dir)) { + if (!file_prepare_directory($dir)) { file_prepare_directory($dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY); } diff --git a/drush_language.info.yml b/drush_language.info.yml index 324c415..ea51292 100644 --- a/drush_language.info.yml +++ b/drush_language.info.yml @@ -1,7 +1,7 @@ -core: 8.x -dependencies: - - language -description: 'Provides Drush commands for language manipulation' name: 'Drush Language commands' -package: Multilingual type: module +description: 'Provides Drush commands for language manipulation' +core: 8.x +package: Multilingual +dependencies: + - drupal:language diff --git a/src/Commands/DrushLanguageCommands.php b/src/Commands/DrushLanguageCommands.php index c566c3a..284f99d 100644 --- a/src/Commands/DrushLanguageCommands.php +++ b/src/Commands/DrushLanguageCommands.php @@ -295,6 +295,8 @@ class DrushLanguageCommands extends DrushCommands { * The langcode of the language in which the string will be imported. * @param array $poFiles * Comma-separated list of paths .po files containing the translations. + * @param array $options + * The command options. * * @command language:import:translations * @@ -317,7 +319,8 @@ class DrushLanguageCommands extends DrushCommands { public function importTranslations( string $langcode, array $poFiles, - array $options = ['replace' => FALSE]) { + array $options = ['replace' => FALSE] + ) { $this->moduleHandler->loadInclude('locale', 'translation.inc'); $poFiles = StringUtils::csvToArray($poFiles); @@ -329,7 +332,7 @@ class DrushLanguageCommands extends DrushCommands { $language->save(); $this->logger()->notice('Language {langcode} ({language}) has been created.', [ 'langcode' => $langcode, - 'language' => $this->t($language->label()), + 'language' => $language->label(), ]); } @@ -503,6 +506,8 @@ class DrushLanguageCommands extends DrushCommands { * @param string $langcodes * A comma-separated list of the language codes to export. Defaults to all * enabled languages. + * @param array $options + * The command options. * * @command language:export:all:translations * -- 2.1.4 From ec626247d558205fe46d671155b647be51cdccb7 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 14:49:09 +0100 Subject: [PATCH 03/16] Issue #2914081 by Grimreaper: PHP5 compatibility --- src/Commands/DrushLanguageCommands.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Commands/DrushLanguageCommands.php b/src/Commands/DrushLanguageCommands.php index 284f99d..d771059 100644 --- a/src/Commands/DrushLanguageCommands.php +++ b/src/Commands/DrushLanguageCommands.php @@ -317,7 +317,7 @@ class DrushLanguageCommands extends DrushCommands { * in Drupal core. */ public function importTranslations( - string $langcode, + $langcode, array $poFiles, array $options = ['replace' => FALSE] ) { @@ -426,8 +426,8 @@ class DrushLanguageCommands extends DrushCommands { * Invalid values passed. */ public function exportTranslations( - string $langcode, - string $poFile, + $langcode, + $poFile, array $options = ['status' => NULL] ) { // Ensure the langcode matches an existing language. @@ -520,7 +520,7 @@ class DrushLanguageCommands extends DrushCommands { * @aliases langexpall,language-export-all,language-export-all-translations */ public function exportAllTranslations( - string $langcodes = NULL, + $langcodes = NULL, array $options = [ 'all' => NULL, 'file-pattern' => NULL, -- 2.1.4 From 516c59d94802914deb047541c2fb4930ea5e5f01 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 15:01:16 +0100 Subject: [PATCH 04/16] Issue #2914081 by Grimreaper: Use short array syntax. --- drush_language.drush.inc | 146 +++++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/drush_language.drush.inc b/drush_language.drush.inc index 0c33e82..8a9d676 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -18,99 +18,99 @@ use Drush\Log\LogLevel; * @See drush_parse_command() for a list of recognized keys. */ function drush_language_drush_command() { - $items = array(); - $items['language-add'] = array( + $items = []; + $items['language-add'] = [ 'description' => "Add and import a new language definition", - 'arguments' => array( + 'arguments' => [ 'langcode' => 'The langcode of the language for which a definition will be added.', - ), - 'aliases' => array('langadd'), - ); - $items['language-enable'] = array( + ], + 'aliases' => ['langadd'], + ]; + $items['language-enable'] = [ 'description' => "Enable an already defined language", - 'arguments' => array( + 'arguments' => [ 'langcode' => 'The langcode of the language which will be enabled.', - ), - 'aliases' => array('langen'), - ); - $items['language-disable'] = array( + ], + 'aliases' => ['langen'], + ]; + $items['language-disable'] = [ 'description' => "Disable an already defined language", - 'arguments' => array( + 'arguments' => [ 'langcode' => 'The langcode of the language which will be disabled.', - ), - 'aliases' => array('langdis'), - ); - $items['language-default'] = array( + ], + 'aliases' => ['langdis'], + ]; + $items['language-default'] = [ 'description' => "Assign an enabled language as default", - 'arguments' => array( + 'arguments' => [ 'langcode' => 'The langcode of the language which will be set as the default language.', - ), - 'aliases' => array('langdef'), - ); - $items['language-import-translations'] = array( + ], + 'aliases' => ['langdef'], + ]; + $items['language-import-translations'] = [ 'description' => "Import a single .po file", - 'arguments' => array( + 'arguments' => [ '.po file(s)' => 'Path to one or more .po files to import. If omitted, $settings[\'custom_translations_directory\'] must be set and all .po files from that directory will be taken. If langcode (overridable), project and version can be deduced from the filename, they will be stored in the translation database.', - ), - 'examples' => array( + ], + 'examples' => [ 'Import all custom translations from the directory defined in $settings[\'custom_translations_directory\'].' => 'drush langimp', 'Import single file with explicit langcode' => 'drush langimp --langcode=ru file.po', 'Import not-customized (e.g. module) translations, without replacing custom translations, with auto langcode (these are the recognized patterns)' => 'drush langimp --langcode=eo --no-set-customized --no-replace-customized de.po foomodule.fr.po barmodule-8.x-2.2-rc1.es.po', - ), - 'options' => array( - 'langcode' => array( + ], + 'options' => [ + 'langcode' => [ 'description' => 'Language code to be imported. If not given, extracted from file name.', 'value' => 'optional', - ), - 'replace-customized' => array( + ], + 'replace-customized' => [ 'description' => 'Replace existing customized translations. Defaults to true.', 'value' => 'optional', - ), - 'replace-not-customized' => array( + ], + 'replace-not-customized' => [ 'description' => 'Replace existing not-customized translations. Defaults to true.', 'value' => 'optional', - ), - 'set-customized' => array( + ], + 'set-customized' => [ 'description' => 'Set all existing translations as being customized. Defaults to true.', 'value' => 'optional', - ), - 'autocreate-language' => array( + ], + 'autocreate-language' => [ 'description' => 'Autocreate any imported language if it does not yet exist. Defaults to true.', 'value' => 'optional', - ), - ), - 'aliases' => array('langimp', 'language-import'), - ); - $items['language-export-translations'] = array( + ], + ], + 'aliases' => ['langimp', 'language-import'], + ]; + $items['language-export-translations'] = [ 'description' => "Export string of a language as one or more .po files", - 'examples' => array( + 'examples' => [ 'Export all custom translations into the directory defined in $settings[\'custom_translations_directory\'].' => 'drush langexp', 'Export all german translated strings' => 'drush langexp --langcodes=de --status=customized,not-customized --file=all-de.po', 'Export untranslated strings from all languages to current dir' => 'drush langexp --status=untranslated --file=./todo-%langcode.po', - ), - 'options' => array( - 'statuses' => array( + ], + 'options' => [ + 'statuses' => [ 'description' => 'The statuses to export, defaults to \'customized\'.' . "\n" . 'This can be a comma-separated list of \'customized\', \'not-customized\', \'not-translated\', or (as abbreviation) \'all\'.', 'value' => 'optional', - ), - 'langcodes' => array( + ], + 'langcodes' => [ 'description' => 'The language codes to export, comma-separated. Defaults to all enabled languages.', 'value' => 'optional', - ), - 'file' => array( + ], + 'file' => [ 'description' => 'The target file pattern. You can use %langcode as placeholder. Defaults to "%language.po". ' . 'If the path is relative and does not start with ".", $settings[\'custom_translations_directory\'] must be defined and the path is relatve to that directory.', 'value' => 'optional', - ), - 'force' => array( + ], + 'force' => [ 'description' => 'Write file even if no translations. Defaults to true.', 'value' => 'optional', - ), - ), - 'aliases' => array('langexp', 'language-export'), - ); + ], + ], + 'aliases' => ['langexp', 'language-export'], + ]; return $items; } @@ -129,13 +129,13 @@ function drush_drush_language_language_add() { foreach ($args as $langcode) { $language_list = \Drupal::languageManager()->getLanguages(); if (array_key_exists($langcode, $language_list)) { - drush_log(dt('The language with code !code already exists.', array('!code' => $langcode)), 'warning'); + drush_log(dt('The language with code !code already exists.', ['!code' => $langcode]), 'warning'); } else { // Predefined language selection. $predefined = \Drupal::languageManager()->getStandardLanguageListWithoutConfigured(); if (!isset($predefined[$langcode])) { - drush_log(dt('Invalid language code !language', array('!language' => $langcode)), 'warning'); + drush_log(dt('Invalid language code !language', ['!language' => $langcode]), 'warning'); } else { // Add the language definition. @@ -147,7 +147,7 @@ function drush_drush_language_language_add() { if (\Drupal::moduleHandler()->moduleExists('locale')) { module_load_include('fetch.inc', 'locale'); $options = _locale_translation_default_update_options(); - if ($batch = locale_translation_batch_update_build(array(), array($langcode), $options)) { + if ($batch = locale_translation_batch_update_build([], [$langcode], $options)) { batch_set($batch); $batch =& batch_get(); $batch['progressive'] = FALSE; @@ -156,7 +156,7 @@ function drush_drush_language_language_add() { drush_backend_batch_process(); } } - drush_log(dt('Added language: !language', array('!language' => $langcode)), 'ok'); + drush_log(dt('Added language: !language', ['!language' => $langcode]), 'ok'); } } } @@ -179,28 +179,28 @@ function drush_language_enable() { // FIXME find the D8 equivalent: this is D7 logic. db_update('languages') ->condition('language', $langcode) - ->fields(array( + ->fields([ 'enabled' => 1, - )) + ]) ->execute(); // FIXME probably needs a more generic invalidation. // Changing the language settings impacts the interface. cache_clear_all('*', 'cache_page', TRUE); - drush_log(dt("Enabled language : !language ", array('!language' => $langcode)), 'ok'); + drush_log(dt("Enabled language : !language ", ['!language' => $langcode]), 'ok'); } else { - drush_log(dt("Language already enabled: !language ", array('!language' => $langcode)), 'warning'); + drush_log(dt("Language already enabled: !language ", ['!language' => $langcode]), 'warning'); } } else { - drush_log(dt("Specified language does not exist !language", array('!language' => $langcode)), 'warning'); + drush_log(dt("Specified language does not exist !language", ['!language' => $langcode]), 'warning'); } } } /** - * Disables a language + * Disables a language. */ function drush_drush_language_disable() { $args = func_get_args(); @@ -216,17 +216,17 @@ function drush_drush_language_disable() { // Disable the default english. db_update('languages') ->condition('language', $langcode) - ->fields(array( + ->fields([ 'enabled' => 0, - )) + ]) ->execute(); // Changing the language settings impacts the interface. cache_clear_all('*', 'cache_page', TRUE); - drush_log(dt("Disabled language : !language ", array('!language' => $langcode)), 'ok'); + drush_log(dt("Disabled language : !language ", ['!language' => $langcode]), 'ok'); } else { - drush_print(dt("Language already disabled: !language ", array('!language' => $langcode)), 'warning'); + drush_print(dt("Language already disabled: !language ", ['!language' => $langcode]), 'warning'); } } } @@ -249,10 +249,10 @@ function drush_drush_language_default() { $default_language = ConfigurableLanguage::load($langcode); $default_language->set('default', TRUE); $default_language->save(); - drush_log(dt("!language assigned as default", array('!language' => $langcode)), 'ok'); + drush_log(dt("!language assigned as default", ['!language' => $langcode]), 'ok'); } else { - drush_log(dt("Specified language does not exist !language", array('!language' => $langcode)), 'warning'); + drush_log(dt("Specified language does not exist !language", ['!language' => $langcode]), 'warning'); } } } @@ -340,10 +340,10 @@ function drush_drush_language_language_import_translations() { if (!isset($languages[$langcode_to_import])) { $language_storage = \Drupal::entityTypeManager()->getStorage('configurable_language'); $language = $language_storage->create(['langcode' => $opt_langcode]); - drush_log(dt('The language @id (@label) has been created.', array( + drush_log(dt('The language @id (@label) has been created.', [ '@id' => $language->id(), '@label' => $language->label(), - ))); + ])); } } } -- 2.1.4 From 70245d7a794f9279ad4bec243d0fdd769203113b Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 17:02:13 +0100 Subject: [PATCH 05/16] Issue #2914081 by Grimreaper: WIP (not tested): make Drush 9 commands use the new Cli service. --- drush.services.yml | 9 +- drush_language.services.yml | 11 + src/Commands/DrushLanguageCommands.php | 417 ++-------------------- src/Drush8Io.php | 33 ++ src/Service/DrushLanguageCliService.php | 588 ++++++++++++++++++++++++++++++++ 5 files changed, 655 insertions(+), 403 deletions(-) create mode 100644 drush_language.services.yml create mode 100644 src/Drush8Io.php create mode 100644 src/Service/DrushLanguageCliService.php diff --git a/drush.services.yml b/drush.services.yml index 7476209..f32a1c3 100644 --- a/drush.services.yml +++ b/drush.services.yml @@ -1,12 +1,7 @@ services: drush_language.commands: - class: \Drush\Commands\DrushLanguageCommands + class: \Drupal\drupal_language\Commands\DrushLanguageCommands arguments: - - '@cache.page' - - '@config.factory' - - '@country_manager' - - '@entity_type.manager' - - '@language_manager' - - '@module_handler' + - '@drush_language.cli' tags: - { name: drush.command } diff --git a/drush_language.services.yml b/drush_language.services.yml new file mode 100644 index 0000000..0f2e72b --- /dev/null +++ b/drush_language.services.yml @@ -0,0 +1,11 @@ +services: + drush_language.cli: + class: Drupal\drush_language\Service\DrushLanguageCliService + arguments: + - '@string_translation' + - '@cache.page' + - '@config.factory' + - '@country_manager' + - '@entity_type.manager' + - '@language_manager' + - '@module_handler' diff --git a/src/Commands/DrushLanguageCommands.php b/src/Commands/DrushLanguageCommands.php index d771059..93fa44a 100644 --- a/src/Commands/DrushLanguageCommands.php +++ b/src/Commands/DrushLanguageCommands.php @@ -1,18 +1,9 @@ cachePage = $cachePage; - $this->configFactory = $configFactory; - $this->countryManager = $countryManager; - $this->entityTypeManager = $entityTypeManager; - $this->languageManager = $languageManager; - $this->moduleHandler = $moduleHandler; + public function __construct(DrushLanguageCliService $cliService) { + $this->cliService = $cliService; } /** @@ -109,51 +41,7 @@ class DrushLanguageCommands extends DrushCommands { public function add(array $langcodes) { $langcodes = StringUtils::csvToArray($langcodes); - if (empty($langcodes)) { - $this->logger()->error('Please provide one or more comma-separated language codes as arguments.'); - return; - } - - foreach ($langcodes as $langcode) { - $messageArgs = ['langcode' => $langcode]; - // In the foreach loop because the list changes on successful iterations. - $languages = $this->languageManager->getLanguages(); - - // Do not re-add existing languages. - if (isset($languages[$langcode])) { - $this->logger()->warning('The language with code {langcode} already exists.', $messageArgs); - continue; - } - - // Only allow adding languages for predefined langcodes. - // In the foreach loop because the list changes on successful iterations. - $predefined = $this->languageManager->getStandardLanguageListWithoutConfigured(); - if (!isset($predefined[$langcode])) { - $this->logger()->warning('Invalid language code {langcode}', $messageArgs); - continue; - } - - // Add the language definition. - $language = ConfigurableLanguage::createFromLangcode($langcode); - $language->save(); - - // Download and import translations for the newly added language if - // interface translation is enabled. - if ($this->moduleHandler->moduleExists('locale')) { - module_load_include('fetch.inc', 'locale'); - $options = _locale_translation_default_update_options(); - if ($batch = locale_translation_batch_update_build([], [$langcode], $options)) { - batch_set($batch); - $batch =& batch_get(); - $batch['progressive'] = FALSE; - - // Process the batch. - drush_backend_batch_process(); - } - } - - $this->logger()->info('Added language: {langcode}', $messageArgs); - } + $this->cliService->add($this->io(), 'dt', $langcodes); } /** @@ -169,42 +57,7 @@ class DrushLanguageCommands extends DrushCommands { public function enable(array $langcodes) { $langcodes = StringUtils::csvToArray($langcodes); - if (empty($langcodes)) { - $this->logger()->error('Please provide one or more comma-separated language codes as arguments.'); - return; - } - - foreach ($langcodes as $langcode) { - $messageArgs = ['langcode' => $langcode]; - - // In the foreach loop because the list changes on successful iterations. - $languages = $this->languageManager->getLanguages(); - - // Skip nonexistent languages. - if (!isset($languages[$langcode])) { - $this->logger()->warning('Specified language does not exist {langcode}', $messageArgs); - continue; - } - - // Skip already-enabled languages. - if ($languages[$langcode]->enabled) { - $this->logger()->warning('Language already enabled: !language', $messageArgs); - continue; - } - - // FIXME find the D8 equivalent: this is D7 logic. - db_update('languages') - ->condition('language', $langcode) - ->fields([ - 'enabled' => 1, - ]) - ->execute(); - - // FIXME probably needs a more generic invalidation. - // Changing the language settings impacts the interface. - $this->cachePage->deleteAll(); - $this->logger()->info('Enabled language : {langcode}', $messageArgs); - } + $this->cliService->enable($this->io(), 'dt', $langcodes); } /** @@ -220,47 +73,7 @@ class DrushLanguageCommands extends DrushCommands { public function disable(array $langcodes) { $langcodes = StringUtils::csvToArray($langcodes); - if (empty($langcodes)) { - $this->logger()->error('Please provide one or more comma-separated language codes as arguments.'); - return; - } - - foreach ($langcodes as $langcode) { - $messageArgs = ['langcode' => $langcode]; - // In the foreach loop because the list changes on successful iterations. - $languages = $this->languageManager->getLanguages(); - - // Skip nonexistent languages. - if (!isset($languages[$langcode])) { - $this->logger()->warning('Specified language does not exist {langcode}', $messageArgs); - continue; - } - - // Skip locked languages. - if ($languages[$langcode]->isLocked()) { - $this->logger()->warning('Not disabling locked specified language {langcode}', $messageArgs); - continue; - } - - // Skip already-disabled languages. - if (!$languages[$langcode]->enabled) { - $this->logger()->warning('Language already disabled: {langcode}', $messageArgs); - continue; - } - - // FIXME find the D8 equivalent: this is D7 logic. - db_update('languages') - ->condition('language', $langcode) - ->fields([ - 'enabled' => 0, - ]) - ->execute(); - - // FIXME probably needs a more generic invalidation. - // Changing the language settings impacts the interface. - $this->cachePage->deleteAll(); - $this->logger()->info('Disabled language : {langcode}', $messageArgs); - } + $this->cliService->disable($this->io(), 'dt', $langcodes); } /** @@ -274,18 +87,7 @@ class DrushLanguageCommands extends DrushCommands { * @aliases langdef, language-default */ public function languageDefault($langcode) { - $messageArgs = ['langcode' => $langcode]; - $languages = $this->languageManager->getLanguages(); - if (!isset($languages[$langcode])) { - $this->logger()->warning('Specified language does not exist {langcode}', $messageArgs); - return; - } - - /** @var \Drupal\language\ConfigurableLanguageInterface $default_language */ - $default_language = ConfigurableLanguage::load($langcode); - $default_language->set('default', TRUE) - ->save(); - $this->logger()->info('{langcode} assigned as default', $messageArgs); + $this->cliService->languageDefault($this->io(), 'dt', $langcode); } /** @@ -308,94 +110,15 @@ class DrushLanguageCommands extends DrushCommands { * drush langimp eo file.po --replace * * @aliases langimp,language-import,language-import-translations - * - * @see \Drupal\locale\Form\ImportForm::submitForm - * - * @todo Implement \Drupal\locale\Form\ImportForm::buildForm - * @todo This can be simplified once https://www.drupal.org/node/2631584 - * lands - * in Drupal core. */ public function importTranslations( $langcode, array $poFiles, array $options = ['replace' => FALSE] ) { - $this->moduleHandler->loadInclude('locale', 'translation.inc'); - $poFiles = StringUtils::csvToArray($poFiles); - // Add language, if not yet supported. - $language = $this->languageManager->getLanguage($langcode); - if (empty($language)) { - $language = ConfigurableLanguage::createFromLangcode($langcode); - $language->save(); - $this->logger()->notice('Language {langcode} ({language}) has been created.', [ - 'langcode' => $langcode, - 'language' => $language->label(), - ]); - } - - $this->moduleHandler->loadInclude('locale', 'bulk.inc'); - $replace = isset($options['replace']) ? $options['replace'] : FALSE; - $buildOptions = array_merge(_locale_translation_default_update_options(), [ - 'langcode' => $langcode, - 'customized' => $replace ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, - 'overwrite_options' => $replace - ? ['customized' => 1, 'not_customized' => 1] - : ['customized' => 0, 'not_customized' => 1], - ]); - - // Import language files. - $files = []; - $langcodes = []; - foreach ($poFiles as $poFile) { - // Probably not an absolute path: test from the original $cwd. - if (!file_exists($poFile)) { - $poFile = drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . $poFile; - } - - // Ensure we have the file intended for upload. - if (file_exists($poFile)) { - // Create file object. - $file = locale_translate_file_create($poFile); - // Extract project, version and language code from the file name - // Supported: - // - {project}-{version}.{langcode}.po, {prefix}.{langcode}.po - // - {langcode}.po - // or from user input. - $file = locale_translate_file_attach_properties($file, $buildOptions); - if ($file->langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) { - $file->langcode = $langcode; - if (empty($file->version) && !empty($file->project) && !empty($file->langcode)) { - $sources = locale_translation_get_status(); - $source = $sources[$file->project][$file->langcode]; - if (isset($source->version)) { - $file->version = $source->version; - } - } - } - $langcodes[] = $file->langcode; - $files[] = $file; - } - else { - $this->logger()->error('File to import at {filepath} not found.', [ - 'filepath' => $poFile, - ]); - } - } - - $batch = locale_translate_batch_build($files, $buildOptions); - batch_set($batch); - - // Create or update all configuration translations for this language. - $langcodes = array_unique($langcodes); - if ($batch = locale_config_batch_update_components($buildOptions, $langcodes)) { - batch_set($batch); - } - - drush_backend_batch_process(); - $this->logger()->info('Import complete.'); + $this->cliService->importTranslations($this->io(), 'dt', $langcode, $poFiles, $options); } /** @@ -405,6 +128,8 @@ class DrushLanguageCommands extends DrushCommands { * The langcode of the language to exported. * @param string $poFile * Path to a .po file. Use "-" or /dev/stdin to use standard output. + * @param array $options + * The command options. * * @command language:export:translations * @@ -416,88 +141,16 @@ class DrushLanguageCommands extends DrushCommands { * drush langexp fr fr.po * * @aliases langexp,language-export,language-export-translations - * - * @todo Implement \Drupal\locale\Form\ExportForm::buildForm - * @todo This can be simplified once https://www.drupal.org/node/2631584 - * lands - * in Drupal core. - * - * @throws \Exception - * Invalid values passed. */ public function exportTranslations( $langcode, $poFile, array $options = ['status' => NULL] ) { - // Ensure the langcode matches an existing language. - $language = $this->languageManager->getLanguage($langcode); - if (empty($language)) { - throw new \Exception('drush language-export: no such language'); - } - - // Validate export statuses. - $exportStatusesAllowed = [ - // Internal-value => input-value. - 'customized' => 'customized', - 'not_customized' => 'not-customized', - 'not_translated' => 'not-translated', - ]; - $exportStatusesInput = isset($options['status']) ? $options['status'] : ['customized']; - $exportStatusesInput = array_values($exportStatusesInput); - if ($exportStatusesInput == ['all']) { - $exportStatusesInput = $exportStatusesAllowed; - } - - $exportStatusesUnknown = array_diff($exportStatusesInput, $exportStatusesAllowed); - if ($exportStatusesUnknown) { - $statusArgs = ['options' => implode(', ', $exportStatusesUnknown)]; - throw new \Exception($this->t('drush language-export: Unknown status options: {options}', - $statusArgs)); - } - - $exportStatusesFiltered = array_intersect($exportStatusesAllowed, $exportStatusesInput); - $exportStatuses = array_fill_keys(array_keys($exportStatusesFiltered), TRUE); - - // Relative path should be relative to cwd(), rather than Drupal root-dir. - $filePath = drush_is_absolute_path($poFile) - ? $poFile - : drush_get_context('DRUSH_DRUPAL_ROOT') . DIRECTORY_SEPARATOR . $poFile; - - // Check if file_path exists and is writable. - $dir = dirname($filePath); - if (!file_prepare_directory($dir)) { - file_prepare_directory($dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY); - } - - $reader = new PoDatabaseReader(); - $language_name = ''; - if ($language != NULL) { - $reader->setLangcode($language->getId()); - $reader->setOptions($exportStatuses); - $languages = $this->languageManager->getLanguages(); - $language_name = isset($languages[$language->getId()]) ? $languages[$language->getId()]->getName() : ''; - } - $item = $reader->readItem(); - if (!empty($item)) { - $header = $reader->getHeader(); - $header->setProjectName($this->configFactory->get('system.site')->get('name')); - $header->setLanguageName($language_name); - - $writer = new PoStreamWriter(); - $writer->setUri($filePath); - $writer->setHeader($header); - - $writer->open(); - $writer->writeItem($item); - $writer->writeItems($reader); - $writer->close(); - - $this->logger()->info('Export complete.'); - } - else { - throw new \Exception($this->t('Nothing to export.')); + try { + $this->cliService->exportTranslations($this->io(), 'dt', $langcode, $poFile, $options); } + catch (\Exception $exception) {} } /** @@ -528,35 +181,7 @@ class DrushLanguageCommands extends DrushCommands { ) { $langcodes = StringUtils::csvToArray((array) $langcodes); - if (empty($langcodes)) { - $languages = $this->languageManager->getLanguages(); - $langcodes = array_keys($languages); - } - - $file_pattern = isset($options['file_pattern']) - ? $options['file_pattern'] - : 'translations/custom/%language.po'; - - $exportOptions = [ - 'status' => empty($options['all']) ? ['customized'] : ['all'], - ]; - - foreach ($langcodes as $langcode) { - $filePathRelative = preg_replace('/%language/u', $langcode, $file_pattern); - $fileNameAbsolute = drush_is_absolute_path($filePathRelative) - ? $filePathRelative - : drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . $filePathRelative; - - drush_invoke_process('@self', 'language:export:translation', [ - $langcode, - $fileNameAbsolute, - ], $exportOptions); - - $this->logger()->info('Exported translations for language {langcode} to file !file.', [ - 'langcode' => $langcode, - '!file' => $filePathRelative, - ]); - } + $this->cliService->exportAllTranslations($this->io(), 'dt', $langcodes, $options); } } diff --git a/src/Drush8Io.php b/src/Drush8Io.php new file mode 100644 index 0000000..1ea4ab3 --- /dev/null +++ b/src/Drush8Io.php @@ -0,0 +1,33 @@ +stringTranslation = $string_translation; + $this->cachePage = $cachePage; + $this->configFactory = $configFactory; + $this->countryManager = $countryManager; + $this->entityTypeManager = $entityTypeManager; + $this->languageManager = $languageManager; + $this->moduleHandler = $moduleHandler; + $this->errors = []; + } + + /** + * Add and import one or more new language definitions. + * + * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * The $io interface of the cli tool calling. + * @param callable $t + * The translation function akin to t(). + * @param array $langcodes + * A list of langcodes for which a definition will be added. + */ + public function add($io, callable $t, array $langcodes) { + if (empty($langcodes)) { + $io->error($t('Please provide one or more comma-separated language codes as arguments.')); + return; + } + + foreach ($langcodes as $langcode) { + $messageArgs = ['langcode' => $langcode]; + // In the foreach loop because the list changes on successful iterations. + $languages = $this->languageManager->getLanguages(); + + // Do not re-add existing languages. + if (isset($languages[$langcode])) { + $io->warning($t('The language with code {langcode} already exists.', $messageArgs)); + continue; + } + + // Only allow adding languages for predefined langcodes. + // In the foreach loop because the list changes on successful iterations. + $predefined = $this->languageManager->getStandardLanguageListWithoutConfigured(); + if (!isset($predefined[$langcode])) { + $io->warning($t('Invalid language code {langcode}', $messageArgs)); + continue; + } + + // Add the language definition. + $language = ConfigurableLanguage::createFromLangcode($langcode); + $language->save(); + + // Download and import translations for the newly added language if + // interface translation is enabled. + if ($this->moduleHandler->moduleExists('locale')) { + module_load_include('fetch.inc', 'locale'); + $options = _locale_translation_default_update_options(); + if ($batch = locale_translation_batch_update_build([], [$langcode], $options)) { + batch_set($batch); + $batch =& batch_get(); + $batch['progressive'] = FALSE; + + // TODO: The batch will need rework for Drupal console compatibility. + // Process the batch. + drush_backend_batch_process(); + } + } + + $io->text($t('Added language: {langcode}', $messageArgs)); + } + } + + /** + * Enable one or more already defined languages. + * + * @param \Symfony\Component\Console\Style\StyleInterface|\Drupal\drush_language\Drush8Io $io + * The $io interface of the cli tool calling. + * @param callable $t + * The translation function akin to t(). + * @param array $langcodes + * A list of langcodes which will be enabled. + */ + public function enable($io, callable $t, array $langcodes) { + if (empty($langcodes)) { + $io->error($t('Please provide one or more comma-separated language codes as arguments.')); + return; + } + + foreach ($langcodes as $langcode) { + $messageArgs = ['langcode' => $langcode]; + + // In the foreach loop because the list changes on successful iterations. + $languages = $this->languageManager->getLanguages(); + + // Skip nonexistent languages. + if (!isset($languages[$langcode])) { + $io->warning($t('Specified language does not exist {langcode}', $messageArgs)); + continue; + } + + // Skip already-enabled languages. + if ($languages[$langcode]->enabled) { + $io->warning($t('Language already enabled: !language', $messageArgs)); + continue; + } + + // FIXME find the D8 equivalent: this is D7 logic. + db_update('languages') + ->condition('language', $langcode) + ->fields([ + 'enabled' => 1, + ]) + ->execute(); + + // FIXME probably needs a more generic invalidation. + // Changing the language settings impacts the interface. + $this->cachePage->deleteAll(); + $io->text($t('Enabled language : {langcode}', $messageArgs)); + } + } + + /** + * Disable one or more already defined languages. + * + * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * The $io interface of the cli tool calling. + * @param callable $t + * The translation function akin to t(). + * @param array $langcodes + * The langcodes of the languages which will be disabled. + */ + public function disable($io, callable $t, array $langcodes) { + if (empty($langcodes)) { + $io->error($t('Please provide one or more comma-separated language codes as arguments.')); + return; + } + + foreach ($langcodes as $langcode) { + $messageArgs = ['langcode' => $langcode]; + // In the foreach loop because the list changes on successful iterations. + $languages = $this->languageManager->getLanguages(); + + // Skip nonexistent languages. + if (!isset($languages[$langcode])) { + $io->warning($t('Specified language does not exist {langcode}', $messageArgs)); + continue; + } + + // Skip locked languages. + if ($languages[$langcode]->isLocked()) { + $io->warning($t('Not disabling locked specified language {langcode}', $messageArgs)); + continue; + } + + // Skip already-disabled languages. + if (!$languages[$langcode]->enabled) { + $io->warning($t('Language already disabled: {langcode}', $messageArgs)); + continue; + } + + // FIXME find the D8 equivalent: this is D7 logic. + db_update('languages') + ->condition('language', $langcode) + ->fields([ + 'enabled' => 0, + ]) + ->execute(); + + // FIXME probably needs a more generic invalidation. + // Changing the language settings impacts the interface. + $this->cachePage->deleteAll(); + $io->text($t('Disabled language : {langcode}', $messageArgs)); + } + } + + /** + * Assign an enabled language as default. + * + * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * The $io interface of the cli tool calling. + * @param callable $t + * The translation function akin to t(). + * @param string $langcode + * The langcode of the language which will be set as the default language. + */ + public function languageDefault($io, callable $t, $langcode) { + $messageArgs = ['langcode' => $langcode]; + $languages = $this->languageManager->getLanguages(); + if (!isset($languages[$langcode])) { + $io->warning($t('Specified language does not exist {langcode}', $messageArgs)); + return; + } + + try { + /** @var \Drupal\language\ConfigurableLanguageInterface $default_language */ + $default_language = ConfigurableLanguage::load($langcode); + $default_language->set('default', TRUE)->save(); + $io->text($t('{langcode} assigned as default', $messageArgs)); + } + catch (EntityStorageException $exception) { + $io->error($exception->getMessage()); + } + } + + /** + * Import a single .po file. + * + * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * The $io interface of the cli tool calling. + * @param callable $t + * The translation function akin to t(). + * @param string $langcode + * The langcode of the language in which the string will be imported. + * @param array $poFiles + * A list of paths .po files containing the translations. + * @param array $options + * The command options. + * + * @see \Drupal\locale\Form\ImportForm::submitForm + * + * @todo Implement \Drupal\locale\Form\ImportForm::buildForm + * @todo This can be simplified once https://www.drupal.org/node/2631584 + * lands in Drupal core. + */ + public function importTranslations( + $io, + callable $t, + $langcode, + array $poFiles, + array $options = ['replace' => FALSE] + ) { + $this->moduleHandler->loadInclude('locale', 'translation.inc'); + + // Add language, if not yet supported. + $language = $this->languageManager->getLanguage($langcode); + if (empty($language)) { + $language = ConfigurableLanguage::createFromLangcode($langcode); + $language->save(); + $io->text($t('Language {langcode} ({language}) has been created.', [ + 'langcode' => $langcode, + 'language' => $language->label(), + ])); + } + + $this->moduleHandler->loadInclude('locale', 'bulk.inc'); + $replace = isset($options['replace']) ? $options['replace'] : FALSE; + $buildOptions = array_merge(_locale_translation_default_update_options(), [ + 'langcode' => $langcode, + 'customized' => $replace ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, + 'overwrite_options' => $replace ? ['customized' => 1, 'not_customized' => 1] : ['customized' => 0, 'not_customized' => 1], + ]); + + // Import language files. + $files = []; + $langcodes = []; + foreach ($poFiles as $poFile) { + // Probably not an absolute path: test from the original $cwd. + if (!file_exists($poFile)) { + $poFile = DRUPAL_ROOT . DIRECTORY_SEPARATOR . $poFile; + } + + // Ensure we have the file intended for upload. + if (file_exists($poFile)) { + // Create file object. + $file = locale_translate_file_create($poFile); + // Extract project, version and language code from the file name + // Supported: + // - {project}-{version}.{langcode}.po, {prefix}.{langcode}.po + // - {langcode}.po + // or from user input. + $file = locale_translate_file_attach_properties($file, $buildOptions); + if ($file->langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) { + $file->langcode = $langcode; + if (empty($file->version) && !empty($file->project) && !empty($file->langcode)) { + $sources = locale_translation_get_status(); + $source = $sources[$file->project][$file->langcode]; + if (isset($source->version)) { + $file->version = $source->version; + } + } + } + $langcodes[] = $file->langcode; + $files[] = $file; + } + else { + $io->error($t('File to import at {filepath} not found.', [ + 'filepath' => $poFile, + ])); + } + } + + $batch = locale_translate_batch_build($files, $buildOptions); + batch_set($batch); + + // Create or update all configuration translations for this language. + $langcodes = array_unique($langcodes); + if ($batch = locale_config_batch_update_components($buildOptions, $langcodes)) { + batch_set($batch); + } + + // TODO: The batch will need rework for Drupal console compatibility. + drush_backend_batch_process(); + $io->text($t('Import complete.')); + } + + /** + * Export strings of a language as a .po file. + * + * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * The $io interface of the cli tool calling. + * @param callable $t + * The translation function akin to t(). + * @param string $langcode + * The langcode of the language to exported. + * @param string $poFile + * Path to a .po file. Use "-" or /dev/stdin to use standard output. + * @param array $options + * The command options. + * + * @todo Implement \Drupal\locale\Form\ExportForm::buildForm + * @todo This can be simplified once https://www.drupal.org/node/2631584 + * lands in Drupal core. + * + * @throws \Exception + * Invalid values passed. + */ + public function exportTranslations( + $io, + callable $t, + $langcode, + $poFile, + array $options = ['status' => NULL] + ) { + // Ensure the langcode matches an existing language. + $language = $this->languageManager->getLanguage($langcode); + if (empty($language)) { + throw new \Exception('No such language {langcode}', [ + 'langcode' => $langcode, + ]); + } + + // Validate export statuses. + $exportStatusesAllowed = [ + // Internal-value => input-value. + 'customized' => 'customized', + 'not_customized' => 'not-customized', + 'not_translated' => 'not-translated', + ]; + $exportStatusesInput = isset($options['status']) ? $options['status'] : ['customized']; + $exportStatusesInput = array_values($exportStatusesInput); + if ($exportStatusesInput == ['all']) { + $exportStatusesInput = $exportStatusesAllowed; + } + + $exportStatusesUnknown = array_diff($exportStatusesInput, $exportStatusesAllowed); + if ($exportStatusesUnknown) { + $statusArgs = ['options' => implode(', ', $exportStatusesUnknown)]; + throw new \Exception($t('Unknown status options: {options}', + $statusArgs)); + } + + $exportStatusesFiltered = array_intersect($exportStatusesAllowed, $exportStatusesInput); + $exportStatuses = array_fill_keys(array_keys($exportStatusesFiltered), TRUE); + + // Relative path should be relative to cwd(), rather than Drupal root-dir. + // TODO: This will need rework for Drupal console compatibility. + $filePath = drush_is_absolute_path($poFile) + ? $poFile + : DRUPAL_ROOT . DIRECTORY_SEPARATOR . $poFile; + + // Check if file_path exists and is writable. + $dir = dirname($filePath); + if (!file_prepare_directory($dir)) { + file_prepare_directory($dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY); + } + + $reader = new PoDatabaseReader(); + $language_name = ''; + if ($language != NULL) { + $reader->setLangcode($language->getId()); + $reader->setOptions($exportStatuses); + $languages = $this->languageManager->getLanguages(); + $language_name = isset($languages[$language->getId()]) ? $languages[$language->getId()]->getName() : ''; + } + $item = $reader->readItem(); + if (!empty($item)) { + try { + $header = $reader->getHeader(); + $header->setProjectName($this->configFactory->get('system.site')->get('name')); + $header->setLanguageName($language_name); + + $writer = new PoStreamWriter(); + $writer->setUri($filePath); + $writer->setHeader($header); + + $writer->open(); + $writer->writeItem($item); + $writer->writeItems($reader); + $writer->close(); + + $io->text($t('Export complete.')); + } + catch (\Exception $exception) { + $io->error($t('Error when exporting @filePath: @message', [ + '@filePath' => $filePath, + '@message' => $exception->getMessage(), + ])); + } + } + else { + throw new \Exception($t('Nothing to export.')); + } + } + + /** + * Export all translations to files. + * + * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * The $io interface of the cli tool calling. + * @param callable $t + * The translation function akin to t(). + * @param string $langcodes + * A list of the language codes to export. Defaults to all enabled + * languages. + * @param array $options + * The command options. + */ + public function exportAllTranslations( + $io, + callable $t, + $langcodes = NULL, + array $options = [ + 'all' => NULL, + 'file-pattern' => NULL, + ] + ) { + if (empty($langcodes)) { + $languages = $this->languageManager->getLanguages(); + $langcodes = array_keys($languages); + } + + $file_pattern = isset($options['file_pattern']) + ? $options['file_pattern'] + : 'translations/custom/%language.po'; + + $exportOptions = [ + 'status' => empty($options['all']) ? ['customized'] : ['all'], + ]; + + foreach ($langcodes as $langcode) { + $filePathRelative = preg_replace('/%language/u', $langcode, $file_pattern); + + // TODO: This will need rework for Drupal console compatibility. + $fileNameAbsolute = drush_is_absolute_path($filePathRelative) + ? $filePathRelative + : DRUPAL_ROOT . DIRECTORY_SEPARATOR . $filePathRelative; + + try { + $this->exportTranslations($io, $t, $langcode, $fileNameAbsolute, $exportOptions); + + $io->text($t('Exported translations for language {langcode} to file !file.', [ + 'langcode' => $langcode, + '!file' => $filePathRelative, + ])); + } + catch (\Exception $exception) { + $io->error($exception->getMessage()); + } + } + } + + /** + * Returns error messages created while running the import. + * + * @return array + * List of messages. + */ + public function getErrors() { + return $this->errors; + } + +} -- 2.1.4 From 1c7ea422739fdec18f1dda6a146a04f292acedda Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 17:04:21 +0100 Subject: [PATCH 06/16] Issue #2914081 by Grimreaper: Remove disable and enable commands as languages do not have status anymore --- drush_language.drush.inc | 84 -------------------------- src/Commands/DrushLanguageCommands.php | 35 +---------- src/Service/DrushLanguageCliService.php | 103 -------------------------------- 3 files changed, 2 insertions(+), 220 deletions(-) diff --git a/drush_language.drush.inc b/drush_language.drush.inc index 8a9d676..a27b45a 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -26,20 +26,6 @@ function drush_language_drush_command() { ], 'aliases' => ['langadd'], ]; - $items['language-enable'] = [ - 'description' => "Enable an already defined language", - 'arguments' => [ - 'langcode' => 'The langcode of the language which will be enabled.', - ], - 'aliases' => ['langen'], - ]; - $items['language-disable'] = [ - 'description' => "Disable an already defined language", - 'arguments' => [ - 'langcode' => 'The langcode of the language which will be disabled.', - ], - 'aliases' => ['langdis'], - ]; $items['language-default'] = [ 'description' => "Assign an enabled language as default", 'arguments' => [ @@ -163,76 +149,6 @@ function drush_drush_language_language_add() { } /** - * Enable a language. - */ -function drush_language_enable() { - $args = func_get_args(); - if (count($args) == 0) { - return drush_set_error('DRUSH_LANGUAGE', dt('Please provide one or more language codes as arguments.')); - } - - foreach ($args as $langcode) { - $languages = language_list(); - if (array_key_exists($langcode, $languages)) { - if (!$languages[$langcode]->enabled) { - // Disable the default english. - // FIXME find the D8 equivalent: this is D7 logic. - db_update('languages') - ->condition('language', $langcode) - ->fields([ - 'enabled' => 1, - ]) - ->execute(); - - // FIXME probably needs a more generic invalidation. - // Changing the language settings impacts the interface. - cache_clear_all('*', 'cache_page', TRUE); - drush_log(dt("Enabled language : !language ", ['!language' => $langcode]), 'ok'); - } - else { - drush_log(dt("Language already enabled: !language ", ['!language' => $langcode]), 'warning'); - } - } - else { - drush_log(dt("Specified language does not exist !language", ['!language' => $langcode]), 'warning'); - } - } -} - -/** - * Disables a language. - */ -function drush_drush_language_disable() { - $args = func_get_args(); - if (count($args) == 0) { - return drush_set_error('DRUSH_LANGUAGE', dt('Please provide one or more language codes as arguments.')); - } - - foreach ($args as $langcode) { - $language_manager = \Drupal::languageManager(); - $languages = $language_manager->getLanguages(); - if (array_key_exists($langcode, $languages)) { - if ($languages[$langcode]->is) { - // Disable the default english. - db_update('languages') - ->condition('language', $langcode) - ->fields([ - 'enabled' => 0, - ]) - ->execute(); - - // Changing the language settings impacts the interface. - cache_clear_all('*', 'cache_page', TRUE); - drush_log(dt("Disabled language : !language ", ['!language' => $langcode]), 'ok'); - } - else { - drush_print(dt("Language already disabled: !language ", ['!language' => $langcode]), 'warning'); - } - } - } -} - -/** * Assigns the default language. */ function drush_drush_language_default() { diff --git a/src/Commands/DrushLanguageCommands.php b/src/Commands/DrushLanguageCommands.php index 93fa44a..420a472 100644 --- a/src/Commands/DrushLanguageCommands.php +++ b/src/Commands/DrushLanguageCommands.php @@ -45,38 +45,6 @@ class DrushLanguageCommands extends DrushCommands { } /** - * Enable one or more already defined languages. - * - * @param array $langcodes - * A comma-separated list of langcodes which will be enabled. - * - * @command language:enable - * - * @aliases langen,language-enable - */ - public function enable(array $langcodes) { - $langcodes = StringUtils::csvToArray($langcodes); - - $this->cliService->enable($this->io(), 'dt', $langcodes); - } - - /** - * Disable one or more already defined languages. - * - * @param array $langcodes - * The comma-separated langcodes of the languages which will be disabled. - * - * @command language:disable - * - * @aliases langdis,language-disable - */ - public function disable(array $langcodes) { - $langcodes = StringUtils::csvToArray($langcodes); - - $this->cliService->disable($this->io(), 'dt', $langcodes); - } - - /** * Assign an enabled language as default. * * @param string $langcode @@ -150,7 +118,8 @@ class DrushLanguageCommands extends DrushCommands { try { $this->cliService->exportTranslations($this->io(), 'dt', $langcode, $poFile, $options); } - catch (\Exception $exception) {} + catch (\Exception $exception) { + } } /** diff --git a/src/Service/DrushLanguageCliService.php b/src/Service/DrushLanguageCliService.php index 5a98bab..951d85d 100644 --- a/src/Service/DrushLanguageCliService.php +++ b/src/Service/DrushLanguageCliService.php @@ -177,109 +177,6 @@ class DrushLanguageCliService { } /** - * Enable one or more already defined languages. - * - * @param \Symfony\Component\Console\Style\StyleInterface|\Drupal\drush_language\Drush8Io $io - * The $io interface of the cli tool calling. - * @param callable $t - * The translation function akin to t(). - * @param array $langcodes - * A list of langcodes which will be enabled. - */ - public function enable($io, callable $t, array $langcodes) { - if (empty($langcodes)) { - $io->error($t('Please provide one or more comma-separated language codes as arguments.')); - return; - } - - foreach ($langcodes as $langcode) { - $messageArgs = ['langcode' => $langcode]; - - // In the foreach loop because the list changes on successful iterations. - $languages = $this->languageManager->getLanguages(); - - // Skip nonexistent languages. - if (!isset($languages[$langcode])) { - $io->warning($t('Specified language does not exist {langcode}', $messageArgs)); - continue; - } - - // Skip already-enabled languages. - if ($languages[$langcode]->enabled) { - $io->warning($t('Language already enabled: !language', $messageArgs)); - continue; - } - - // FIXME find the D8 equivalent: this is D7 logic. - db_update('languages') - ->condition('language', $langcode) - ->fields([ - 'enabled' => 1, - ]) - ->execute(); - - // FIXME probably needs a more generic invalidation. - // Changing the language settings impacts the interface. - $this->cachePage->deleteAll(); - $io->text($t('Enabled language : {langcode}', $messageArgs)); - } - } - - /** - * Disable one or more already defined languages. - * - * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io - * The $io interface of the cli tool calling. - * @param callable $t - * The translation function akin to t(). - * @param array $langcodes - * The langcodes of the languages which will be disabled. - */ - public function disable($io, callable $t, array $langcodes) { - if (empty($langcodes)) { - $io->error($t('Please provide one or more comma-separated language codes as arguments.')); - return; - } - - foreach ($langcodes as $langcode) { - $messageArgs = ['langcode' => $langcode]; - // In the foreach loop because the list changes on successful iterations. - $languages = $this->languageManager->getLanguages(); - - // Skip nonexistent languages. - if (!isset($languages[$langcode])) { - $io->warning($t('Specified language does not exist {langcode}', $messageArgs)); - continue; - } - - // Skip locked languages. - if ($languages[$langcode]->isLocked()) { - $io->warning($t('Not disabling locked specified language {langcode}', $messageArgs)); - continue; - } - - // Skip already-disabled languages. - if (!$languages[$langcode]->enabled) { - $io->warning($t('Language already disabled: {langcode}', $messageArgs)); - continue; - } - - // FIXME find the D8 equivalent: this is D7 logic. - db_update('languages') - ->condition('language', $langcode) - ->fields([ - 'enabled' => 0, - ]) - ->execute(); - - // FIXME probably needs a more generic invalidation. - // Changing the language settings impacts the interface. - $this->cachePage->deleteAll(); - $io->text($t('Disabled language : {langcode}', $messageArgs)); - } - } - - /** * Assign an enabled language as default. * * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io -- 2.1.4 From ec484f05096f3aaa8372c7164ec0a1a46d2f5a53 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 17:12:10 +0100 Subject: [PATCH 07/16] Issue #2914081 by Grimreaper: Better usage of singlequote and doublequotes --- drush_language.drush.inc | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drush_language.drush.inc b/drush_language.drush.inc index a27b45a..c2e15e7 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -20,30 +20,28 @@ use Drush\Log\LogLevel; function drush_language_drush_command() { $items = []; $items['language-add'] = [ - 'description' => "Add and import a new language definition", - 'arguments' => [ - 'langcode' => 'The langcode of the language for which a definition will be added.', + 'description' => 'Add and import a new language definition', + 'arguments' => [ + 'langcode' => 'The langcode of the language for which a definition will be added.', ], 'aliases' => ['langadd'], ]; $items['language-default'] = [ - 'description' => "Assign an enabled language as default", - 'arguments' => [ - 'langcode' => 'The langcode of the language which will be set as the default language.', + 'description' => 'Assign an enabled language as default', + 'arguments' => [ + 'langcode' => 'The langcode of the language which will be set as the default language.', ], 'aliases' => ['langdef'], ]; $items['language-import-translations'] = [ - 'description' => "Import a single .po file", - 'arguments' => [ - '.po file(s)' => 'Path to one or more .po files to import. If omitted, $settings[\'custom_translations_directory\'] must be set and all .po files from that directory will be taken. If langcode (overridable), project and version can be deduced from the filename, they will be stored in the translation database.', + 'description' => 'Import a single .po file', + 'arguments' => [ + '.po file(s)' => 'Path to one or more .po files to import. If omitted, $settings[\'custom_translations_directory\'] must be set and all .po files from that directory will be taken. If langcode (overridable), project and version can be deduced from the filename, they will be stored in the translation database.', ], 'examples' => [ - 'Import all custom translations from the directory defined in $settings[\'custom_translations_directory\'].' - => 'drush langimp', + 'Import all custom translations from the directory defined in $settings[\'custom_translations_directory\'].' => 'drush langimp', 'Import single file with explicit langcode' => 'drush langimp --langcode=ru file.po', - 'Import not-customized (e.g. module) translations, without replacing custom translations, with auto langcode (these are the recognized patterns)' - => 'drush langimp --langcode=eo --no-set-customized --no-replace-customized de.po foomodule.fr.po barmodule-8.x-2.2-rc1.es.po', + 'Import not-customized (e.g. module) translations, without replacing custom translations, with auto langcode (these are the recognized patterns)' => 'drush langimp --langcode=eo --no-set-customized --no-replace-customized de.po foomodule.fr.po barmodule-8.x-2.2-rc1.es.po', ], 'options' => [ 'langcode' => [ @@ -70,16 +68,15 @@ function drush_language_drush_command() { 'aliases' => ['langimp', 'language-import'], ]; $items['language-export-translations'] = [ - 'description' => "Export string of a language as one or more .po files", + 'description' => 'Export string of a language as one or more .po files', 'examples' => [ - 'Export all custom translations into the directory defined in $settings[\'custom_translations_directory\'].' - => 'drush langexp', + 'Export all custom translations into the directory defined in $settings[\'custom_translations_directory\'].' => 'drush langexp', 'Export all german translated strings' => 'drush langexp --langcodes=de --status=customized,not-customized --file=all-de.po', 'Export untranslated strings from all languages to current dir' => 'drush langexp --status=untranslated --file=./todo-%langcode.po', ], 'options' => [ 'statuses' => [ - 'description' => 'The statuses to export, defaults to \'customized\'.' . "\n" . 'This can be a comma-separated list of \'customized\', \'not-customized\', \'not-translated\', or (as abbreviation) \'all\'.', + 'description' => "The statuses to export, defaults to 'customized'\nThis can be a comma-separated list of 'customized', 'not-customized', 'not-translated', or (as abbreviation) 'all'.", 'value' => 'optional', ], 'langcodes' => [ -- 2.1.4 From c584f39a5b0c0a3266539ffe875845e912d2340f Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 17:21:40 +0100 Subject: [PATCH 08/16] Issue #2914081 by Grimreaper: WIP (not tested): convert Drush 8 language-add and language-default commands. --- drush_language.drush.inc | 64 +++--------------------------------------------- 1 file changed, 3 insertions(+), 61 deletions(-) diff --git a/drush_language.drush.inc b/drush_language.drush.inc index c2e15e7..f41e38a 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -7,6 +7,7 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Site\Settings; +use Drupal\drupal_language\Drush8Io; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\locale\PoDatabaseReader; use Drupal\Component\Gettext\PoStreamWriter; @@ -101,48 +102,12 @@ function drush_language_drush_command() { * Add a language. */ function drush_drush_language_language_add() { - if (!\Drupal::moduleHandler()->moduleExists('language')) { - return drush_set_error('DRUSH_LANGUAGE', dt('Could not add language. Is the \'language\' module enabled?')); - } $args = func_get_args(); if (count($args) == 0) { return drush_set_error('DRUSH_LANGUAGE', dt('Please provide one or more language codes as arguments.')); } - foreach ($args as $langcode) { - $language_list = \Drupal::languageManager()->getLanguages(); - if (array_key_exists($langcode, $language_list)) { - drush_log(dt('The language with code !code already exists.', ['!code' => $langcode]), 'warning'); - } - else { - // Predefined language selection. - $predefined = \Drupal::languageManager()->getStandardLanguageListWithoutConfigured(); - if (!isset($predefined[$langcode])) { - drush_log(dt('Invalid language code !language', ['!language' => $langcode]), 'warning'); - } - else { - // Add the language definition. - $language = ConfigurableLanguage::createFromLangcode($langcode); - $language->save(); - - // Download and import translations for the newly added language if - // interface translation is enabled. - if (\Drupal::moduleHandler()->moduleExists('locale')) { - module_load_include('fetch.inc', 'locale'); - $options = _locale_translation_default_update_options(); - if ($batch = locale_translation_batch_update_build([], [$langcode], $options)) { - batch_set($batch); - $batch =& batch_get(); - $batch['progressive'] = FALSE; - - // Process the batch. - drush_backend_batch_process(); - } - } - drush_log(dt('Added language: !language', ['!language' => $langcode]), 'ok'); - } - } - } + \Drupal::service('drush_language.cli')->languageDefault(new Drush8Io(), 'dt', $args); } /** @@ -155,29 +120,12 @@ function drush_drush_language_default() { } foreach ($args as $langcode) { - // Get all the languages. - $language_manager = \Drupal::languageManager(); - $languages = $language_manager->getLanguages(); - if (array_key_exists($langcode, $languages)) { - $default_language = ConfigurableLanguage::load($langcode); - $default_language->set('default', TRUE); - $default_language->save(); - drush_log(dt("!language assigned as default", ['!language' => $langcode]), 'ok'); - } - else { - drush_log(dt("Specified language does not exist !language", ['!language' => $langcode]), 'warning'); - } + \Drupal::service('drush_language.cli')->languageDefault(new Drush8Io(), 'dt', $langcode); } } /** * Imports .po file(s). - * - * @see \Drupal\locale\Form\ImportForm::submitForm - * - * @todo Implement \Drupal\locale\Form\ImportForm::buildForm - * @todo This can be simplified once https://www.drupal.org/node/2631584 lands - * in Drupal core. */ function drush_drush_language_language_import_translations() { $module_handler = \Drupal::moduleHandler(); @@ -275,12 +223,6 @@ function drush_drush_language_language_import_translations() { /** * Exports .po file(s). - * - * @see \Drupal\locale\Form\ExportForm::submitForm - * - * @todo Implement \Drupal\locale\Form\ExportForm::buildForm - * @todo This can be simplified once https://www.drupal.org/node/2631584 lands - * in Drupal core. */ function drush_drush_language_language_export_translations() { // Get options. -- 2.1.4 From 2505979c3f732a3fa0d4cdebe0fbd1bb0f51c81e Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 17:28:02 +0100 Subject: [PATCH 09/16] Issue #2914081 by Grimreaper: Remove the Drush 9 "export all translations" command as it has been removed from Drush 8 commands. --- src/Commands/DrushLanguageCommands.php | 31 ------------------ src/Service/DrushLanguageCliService.php | 57 --------------------------------- 2 files changed, 88 deletions(-) diff --git a/src/Commands/DrushLanguageCommands.php b/src/Commands/DrushLanguageCommands.php index 420a472..29a7cb8 100644 --- a/src/Commands/DrushLanguageCommands.php +++ b/src/Commands/DrushLanguageCommands.php @@ -122,35 +122,4 @@ class DrushLanguageCommands extends DrushCommands { } } - /** - * Export all translations to files. - * - * @param string $langcodes - * A comma-separated list of the language codes to export. Defaults to all - * enabled languages. - * @param array $options - * The command options. - * - * @command language:export:all:translations - * - * @option file-pattern The target file pattern. Defaults to - * 'translations/custom/%language.po'. Note that this is the only place - * where this module's auto-importing works. - * @option all If set, exports all translations instead of only customized - * ones. - * - * @aliases langexpall,language-export-all,language-export-all-translations - */ - public function exportAllTranslations( - $langcodes = NULL, - array $options = [ - 'all' => NULL, - 'file-pattern' => NULL, - ] - ) { - $langcodes = StringUtils::csvToArray((array) $langcodes); - - $this->cliService->exportAllTranslations($this->io(), 'dt', $langcodes, $options); - } - } diff --git a/src/Service/DrushLanguageCliService.php b/src/Service/DrushLanguageCliService.php index 951d85d..fab39d7 100644 --- a/src/Service/DrushLanguageCliService.php +++ b/src/Service/DrushLanguageCliService.php @@ -416,63 +416,6 @@ class DrushLanguageCliService { } /** - * Export all translations to files. - * - * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io - * The $io interface of the cli tool calling. - * @param callable $t - * The translation function akin to t(). - * @param string $langcodes - * A list of the language codes to export. Defaults to all enabled - * languages. - * @param array $options - * The command options. - */ - public function exportAllTranslations( - $io, - callable $t, - $langcodes = NULL, - array $options = [ - 'all' => NULL, - 'file-pattern' => NULL, - ] - ) { - if (empty($langcodes)) { - $languages = $this->languageManager->getLanguages(); - $langcodes = array_keys($languages); - } - - $file_pattern = isset($options['file_pattern']) - ? $options['file_pattern'] - : 'translations/custom/%language.po'; - - $exportOptions = [ - 'status' => empty($options['all']) ? ['customized'] : ['all'], - ]; - - foreach ($langcodes as $langcode) { - $filePathRelative = preg_replace('/%language/u', $langcode, $file_pattern); - - // TODO: This will need rework for Drupal console compatibility. - $fileNameAbsolute = drush_is_absolute_path($filePathRelative) - ? $filePathRelative - : DRUPAL_ROOT . DIRECTORY_SEPARATOR . $filePathRelative; - - try { - $this->exportTranslations($io, $t, $langcode, $fileNameAbsolute, $exportOptions); - - $io->text($t('Exported translations for language {langcode} to file !file.', [ - 'langcode' => $langcode, - '!file' => $filePathRelative, - ])); - } - catch (\Exception $exception) { - $io->error($exception->getMessage()); - } - } - } - - /** * Returns error messages created while running the import. * * @return array -- 2.1.4 From 8cb24cee7207751a0e1454b4b526c47266791f11 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 19:11:23 +0100 Subject: [PATCH 10/16] Issue #2914081 by Grimreaper: Make Drush 8 commands use Cli service. Update Drush 9 commands, and cli service declaration and behavior to reflect Drush 8 command updates since the initial Drush 9 port. --- drush_language.drush.inc | 209 ++----------------------- src/Commands/DrushLanguageCommands.php | 114 +++++++++----- src/Service/DrushLanguageCliService.php | 262 +++++++++++++++++++------------- 3 files changed, 248 insertions(+), 337 deletions(-) diff --git a/drush_language.drush.inc b/drush_language.drush.inc index f41e38a..e77f5bd 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -5,13 +5,7 @@ * Drush (< 9) integration for the drush_language module. */ -use Drupal\Core\Language\LanguageInterface; -use Drupal\Core\Site\Settings; use Drupal\drupal_language\Drush8Io; -use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\locale\PoDatabaseReader; -use Drupal\Component\Gettext\PoStreamWriter; -use Drush\Log\LogLevel; /** * Implements hook_drush_command(). @@ -23,7 +17,7 @@ function drush_language_drush_command() { $items['language-add'] = [ 'description' => 'Add and import a new language definition', 'arguments' => [ - 'langcode' => 'The langcode of the language for which a definition will be added.', + 'langcodes' => 'The langcodes of the languages for which a definition will be added.', ], 'aliases' => ['langadd'], ]; @@ -85,7 +79,7 @@ function drush_language_drush_command() { 'value' => 'optional', ], 'file' => [ - 'description' => 'The target file pattern. You can use %langcode as placeholder. Defaults to "%language.po". ' . 'If the path is relative and does not start with ".", $settings[\'custom_translations_directory\'] must be defined and the path is relatve to that directory.', + 'description' => 'The target file pattern. You can use %langcode as placeholder. Defaults to "%language.po". If the path is relative and does not start with ".", $settings[\'custom_translations_directory\'] must be defined and the path is relative to that directory.', 'value' => 'optional', ], 'force' => [ @@ -128,97 +122,17 @@ function drush_drush_language_default() { * Imports .po file(s). */ function drush_drush_language_language_import_translations() { - $module_handler = \Drupal::moduleHandler(); - $module_handler->loadInclude('locale', 'translation.inc'); - $module_handler->loadInclude('locale', 'bulk.inc'); - // Get arguments and options. $file_paths = func_get_args(); - $opt_langcode = drush_get_option('langcode', NULL); - $opt_set_customized = drush_get_option('set-customized', TRUE); - $opt_replace_customized = drush_get_option('replace-customized', TRUE); - $opt_replace_not_customized = drush_get_option('replace-not-customized', TRUE); - $opt_autocreate_language = drush_get_option('autocreate-language', TRUE); - - if (!$file_paths) { - if ($dir = Settings::get('custom_translations_directory')) { - $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'); - $file_paths = glob("$drupal_root/$dir/*.po"); - } - else { - drush_log(dt('Nothing to do, no file given and no custom translation directory set.'), LogLevel::SUCCESS); - } - } - - $importer_options = array_merge(_locale_translation_default_update_options(), [ - 'langcode' => $opt_langcode, - 'customized' => $opt_set_customized ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, - 'overwrite_options' => [ - 'customized' => (int) $opt_replace_customized, - 'not_customized' => (int) $opt_replace_not_customized, - ], - ]); - - // Import language files. - $files = []; - $langcodes_to_import = []; - foreach ($file_paths as $file_path) { - // Ensure we have the file intended for upload. - if (file_exists($file_path)) { - $file = locale_translate_file_create($file_path); - - // Extract project, version and language code from the file name - // Supported: - // - {project}-{version}.{langcode}.po, {prefix}.{langcode}.po - // - {langcode}.po - // Note: $options['langcode'] will override file langcode. - $file = locale_translate_file_attach_properties($file, $importer_options); - if ($file->langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) { - if (!$opt_langcode) { - return drush_set_error('DRUSH_LANGUAGE', dt('Can not autodetect language of file @file', ['@file' => $file_path])); - } - $file->langcode = $opt_langcode; - if (empty($file->version) && !empty($file->project) && !empty($file->langcode)) { - $sources = locale_translation_get_status(); - $source = $sources[$file->project][$file->langcode]; - if (isset($source->version)) { - $file->version = $source->version; - } - } - } - $langcodes_to_import[$file->langcode] = $file->langcode; - $files[] = $file; - } - else { - $variables = ['@filepath' => $file_path]; - drush_log(dt('File to import at @filepath not found.', $variables), 'error'); - } - } - - if ($opt_autocreate_language) { - $languages = \Drupal::languageManager()->getLanguages(); - foreach ($langcodes_to_import as $langcode_to_import) { - if (!isset($languages[$langcode_to_import])) { - $language_storage = \Drupal::entityTypeManager()->getStorage('configurable_language'); - $language = $language_storage->create(['langcode' => $opt_langcode]); - drush_log(dt('The language @id (@label) has been created.', [ - '@id' => $language->id(), - '@label' => $language->label(), - ])); - } - } - } - - $batch = locale_translate_batch_build($files, $importer_options); - batch_set($batch); - - // Create or update all configuration translations for this language. - if ($batch = locale_config_batch_update_components($importer_options, $langcodes_to_import)) { - batch_set($batch); - } + $options = [ + 'langcode' => drush_get_option('langcode', NULL), + 'replace-customized' => drush_get_option('set-customized', TRUE), + 'replace-not-customized' => drush_get_option('replace-customized', TRUE), + 'set-customized' => drush_get_option('replace-not-customized', TRUE), + 'autocreate-language' => drush_get_option('autocreate-language', TRUE), + ]; - drush_backend_batch_process(); - drush_log('Import complete.', 'success'); + \Drupal::service('drush_language.cli')->importTranslations(new Drush8Io(), 'dt', $file_paths, $options); } /** @@ -226,103 +140,12 @@ function drush_drush_language_language_import_translations() { */ function drush_drush_language_language_export_translations() { // Get options. - $opt_langcodes = drush_get_option_list('langcodes'); - $opt_filepath = drush_get_option('file', '%langcode.po'); - $opt_force_write = drush_get_option('force', TRUE); - $opt_statuses = drush_get_option_list('statuses', 'customized'); - - // Massage options. - // Massage translation statuses. - $export_statuses_allowed = [ - // internal-value => input-value. - 'customized' => 'customized', - 'not_customized' => 'not-customized', - 'not_translated' => 'not-translated', + $options = [ + 'statuses' => drush_get_option_list('statuses', 'customized'), + 'langcodes' => drush_get_option_list('langcodes'), + 'file' => drush_get_option('file', '%langcode.po'), + 'force' => drush_get_option('force', TRUE), ]; - $opt_statuses = array_values($opt_statuses); - if ($opt_statuses == ['all']) { - $opt_statuses = $export_statuses_allowed; - } - $export_statuses_unknown = array_diff($opt_statuses, $export_statuses_allowed); - if ($export_statuses_unknown) { - $t_args = ['@options' => implode(', ', $export_statuses_unknown)]; - return drush_set_error('DRUSH_LANGUAGE', dt('drush language-export: Unknown status options: @options', $t_args)); - } - $export_statuses_filtered = array_intersect($export_statuses_allowed, $opt_statuses); - $export_statuses = array_fill_keys(array_keys($export_statuses_filtered), TRUE); - - // Massage file path pattern. - if (!drush_is_absolute_path($opt_filepath) && !('./' === substr($opt_filepath, 0, 2))) { - $opt_filedir = Settings::get('custom_translations_directory'); - if (!$opt_filedir) { - return drush_set_error('DRUSH_LANGUAGE', dt('Can not export, relative path given and no $settings[\'custom_translations_directory\'] defined. You can instead use an absolute filename or one starting with "./".')); - } - if (!drush_is_absolute_path($opt_filedir)) { - $opt_filedir = drush_get_context('DRUSH_DRUPAL_ROOT') . DIRECTORY_SEPARATOR . $opt_filedir; - } - $opt_filepath = "$opt_filedir/$opt_filepath"; - } - // Massage langcodes. - if (!$opt_langcodes) { - $languages = \Drupal::languageManager()->getLanguages(); - $opt_langcodes = array_keys($languages); - } - - // Validate options. - // Yell if more than 1 langcode and no placeholder. - if (count($opt_langcodes) > 1 && !preg_match('/%langcode/u', $opt_filepath)) { - return drush_set_error('DRUSH_LANGUAGE', dt('You must use %langcode file placeholder when exporting multiple languages.')); - } - // Check that all langcodes are valid, before beginning. - foreach ($opt_langcodes as $langcode) { - $language = \Drupal::languageManager()->getLanguage($langcode); - if ($language == NULL) { - return drush_set_error('DRUSH_LANGUAGE', dt('Unknown language: %langcode', ['%langcode' => $langcode])); - } - } - - // Do our work. - foreach ($opt_langcodes as $langcode) { - $filepath = preg_replace('/%langcode/u', $langcode, $opt_filepath); - $language = \Drupal::languageManager()->getLanguage($langcode); - - // Check if file_path exists and is writable. - $dir = dirname($filepath); - if (!file_prepare_directory($dir)) { - file_prepare_directory($dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY); - } - - $reader = new PoDatabaseReader(); - $language_name = ''; - if ($language != NULL) { - $reader->setLangcode($language->getId()); - $reader->setOptions($export_statuses); - $languages = \Drupal::languageManager()->getLanguages(); - $language_name = isset($languages[$language->getId()]) ? $languages[$language->getId()]->getName() : ''; - } - $item = $reader->readItem(); - if ($item || $opt_force_write) { - $header = $reader->getHeader(); - $header->setProjectName(\Drupal::config('system.site')->get('name')); - $header->setLanguageName($language_name); - - $writer = new PoStreamWriter(); - $writer->setUri($filepath); - $writer->setHeader($header); - - $writer->open(); - if ($item) { - $writer->writeItem($item); - } - $writer->writeItems($reader); - $writer->close(); - - drush_log(dt('Exported translations for language !langcode to file !file.', ['!langcode' => $langcode, '!file' => $filepath]), 'ok'); - } - else { - return drush_set_error('DRUSH_LANGUAGE', dt('Nothing to export for language !langcode.', ['!langcode' => $langcode])); - } - } - drush_log('Export complete.', 'success'); + \Drupal::service('drush_language.cli')->exportTranslations(new Drush8Io(), 'dt', $options); } diff --git a/src/Commands/DrushLanguageCommands.php b/src/Commands/DrushLanguageCommands.php index 29a7cb8..0eb4ba1 100644 --- a/src/Commands/DrushLanguageCommands.php +++ b/src/Commands/DrushLanguageCommands.php @@ -31,12 +31,14 @@ class DrushLanguageCommands extends DrushCommands { /** * Add and import one or more new language definitions. * + * @codingStandardsIgnoreStart + * @command language:add + * * @param array $langcodes * A comma-delimited list of langcodes for which a definition will be added. * - * @command language:add - * * @aliases langadd,language-add + * @codingStandardsIgnoreEnd */ public function add(array $langcodes) { $langcodes = StringUtils::csvToArray($langcodes); @@ -47,79 +49,111 @@ class DrushLanguageCommands extends DrushCommands { /** * Assign an enabled language as default. * + * @codingStandardsIgnoreStart + * @command language:default + * * @param string $langcode * The langcode of the language which will be set as the default language. * - * @command language:default - * - * @aliases langdef, language-default + * @aliases langdef,language-default + * @codingStandardsIgnoreEnd */ public function languageDefault($langcode) { $this->cliService->languageDefault($this->io(), 'dt', $langcode); } + // @codingStandardsIgnoreStart /** * Import a single .po file. * - * @param string $langcode - * The langcode of the language in which the string will be imported. - * @param array $poFiles - * Comma-separated list of paths .po files containing the translations. - * @param array $options - * The command options. - * * @command language:import:translations * - * @option replace Replace existing translations. + * @param array $poFiles + * Comma-separated list of paths .po files containing the translations. * - * @usage Import multiple files - * drush langimp eo file1.po file2.po ... - * @usage Import with replacement - * drush langimp eo file.po --replace + * @option langcode + * Language code to be imported. If not given, extracted from file name. + * @option replace-customized + * Replace existing customized translations. Defaults to true. + * @option replace-not-customized + * Replace existing not-customized translations. Defaults to true. + * @option set-customized + * Set all existing translations as being customized. Defaults to true. + * @option autocreate-language + * Autocreate any imported language if it does not yet exist. Defaults to + * true. + * + * @usage drush langimp + * Import all custom translations from the directory defined in + * $settings['custom_translations_directory']. + * @usage drush langimp --langcode=ru file.po + * Import single file with explicit langcode. + * @usage drush langimp --langcode=eo --no-set-customized --no-replace-customized de.po foomodule.fr.po barmodule-8.x-2.2-rc1.es.po + * Import not-customized (e.g. module) translations, without replacing + * custom translations, with auto langcode (these are the recognized + * patterns)'. * * @aliases langimp,language-import,language-import-translations */ public function importTranslations( - $langcode, array $poFiles, - array $options = ['replace' => FALSE] + array $options = [ + 'langcode' => NULL, + 'replace-customized' => TRUE, + 'replace-not-customized' => TRUE, + 'set-customized' => TRUE, + 'autocreate-language' => TRUE, + ] ) { $poFiles = StringUtils::csvToArray($poFiles); - $this->cliService->importTranslations($this->io(), 'dt', $langcode, $poFiles, $options); + $this->cliService->importTranslations($this->io(), 'dt', $poFiles, $options); } + // @codingStandardsIgnoreEnd + // @codingStandardsIgnoreStart /** - * Export strings of a language as a .po file. - * - * @param string $langcode - * The langcode of the language to exported. - * @param string $poFile - * Path to a .po file. Use "-" or /dev/stdin to use standard output. - * @param array $options - * The command options. + * Export string of a language as one or more .po files. * * @command language:export:translations * - * @option status The statuses to export, defaults to 'customized'. - * This can be a comma-separated list of 'customized', 'not-customized', - * 'not-translated', or 'all'. - * - * @usage Export the french translation - * drush langexp fr fr.po + * @option statuses + * The statuses to export, defaults to 'customized'. This can be a + * comma-separated list of 'customized', 'not-customized', 'not-translated', + * or (as abbreviation) 'all'. + * @option langcodes + * The language codes to export, comma-separated. Defaults to all enabled + * languages. + * @option file + * The target file pattern. You can use %langcode as placeholder. Defaults + * to "%language.po". If the path is relative and does not start with ".", + * $settings[\'custom_translations_directory\'] must be defined and the path + * is relative to that directory. + * @option force + * Write file even if no translations. Defaults to true. + * + * @usage drush langexp + * Export all custom translations into the directory defined in + * $settings['custom_translations_directory']. + * @usage drush langexp --langcodes=de --status=customized,not-customized --file=all-de.po + * Export all german translated strings + * @usage drush langexp --status=untranslated --file=./todo-%langcode.po + * Export untranslated strings from all languages to current dir * * @aliases langexp,language-export,language-export-translations */ - public function exportTranslations( - $langcode, - $poFile, - array $options = ['status' => NULL] - ) { + public function exportTranslations($options = [ + 'statuses' => ['customized'], + 'langcodes' => [], + 'file' => '%langcode.po', + 'force' => TRUE, + ]) { try { - $this->cliService->exportTranslations($this->io(), 'dt', $langcode, $poFile, $options); + $this->cliService->exportTranslations($this->io(), 'dt', $options); } catch (\Exception $exception) { } } + // @codingStandardsIgnoreEnd } diff --git a/src/Service/DrushLanguageCliService.php b/src/Service/DrushLanguageCliService.php index fab39d7..d707863 100644 --- a/src/Service/DrushLanguageCliService.php +++ b/src/Service/DrushLanguageCliService.php @@ -3,6 +3,7 @@ namespace Drupal\drush_language\Service; use Drupal\Component\Gettext\PoStreamWriter; +use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityStorageException; @@ -10,6 +11,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Locale\CountryManagerInterface; +use Drupal\Core\Site\Settings; use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\language\ConfigurableLanguageManagerInterface; use Drupal\language\Entity\ConfigurableLanguage; @@ -120,7 +122,7 @@ class DrushLanguageCliService { /** * Add and import one or more new language definitions. * - * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * @param \Symfony\Component\Console\Style\StyleInterface|\Drupal\drush_language\Drush8Io $io * The $io interface of the cli tool calling. * @param callable $t * The translation function akin to t(). @@ -179,7 +181,7 @@ class DrushLanguageCliService { /** * Assign an enabled language as default. * - * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * @param \Symfony\Component\Console\Style\StyleInterface|\Drupal\drush_language\Drush8Io $io * The $io interface of the cli tool calling. * @param callable $t * The translation function akin to t(). @@ -208,12 +210,10 @@ class DrushLanguageCliService { /** * Import a single .po file. * - * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * @param \Symfony\Component\Console\Style\StyleInterface|\Drupal\drush_language\Drush8Io $io * The $io interface of the cli tool calling. * @param callable $t * The translation function akin to t(). - * @param string $langcode - * The langcode of the language in which the string will be imported. * @param array $poFiles * A list of paths .po files containing the translations. * @param array $options @@ -228,52 +228,62 @@ class DrushLanguageCliService { public function importTranslations( $io, callable $t, - $langcode, array $poFiles, - array $options = ['replace' => FALSE] + array $options = [ + 'langcode' => NULL, + 'replace-customized' => TRUE, + 'replace-not-customized' => TRUE, + 'set-customized' => TRUE, + 'autocreate-language' => TRUE, + ] ) { $this->moduleHandler->loadInclude('locale', 'translation.inc'); + $this->moduleHandler->loadInclude('locale', 'bulk.inc'); - // Add language, if not yet supported. - $language = $this->languageManager->getLanguage($langcode); - if (empty($language)) { - $language = ConfigurableLanguage::createFromLangcode($langcode); - $language->save(); - $io->text($t('Language {langcode} ({language}) has been created.', [ - 'langcode' => $langcode, - 'language' => $language->label(), - ])); + $opt_langcode = $options['langcode']; + $opt_set_customized = $options['set-customized']; + $opt_replace_customized = $options['replace-customized']; + $opt_replace_not_customized = $options['replace-not-customized']; + $opt_autocreate_language = $options['autocreate-language']; + + if (!$poFiles) { + if ($dir = Settings::get('custom_translations_directory')) { + $poFiles = glob(DRUPAL_ROOT . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR . '*.po'); + } + else { + $io->success($t('Nothing to do, no file given and no custom translation directory set.')); + } } - $this->moduleHandler->loadInclude('locale', 'bulk.inc'); - $replace = isset($options['replace']) ? $options['replace'] : FALSE; - $buildOptions = array_merge(_locale_translation_default_update_options(), [ - 'langcode' => $langcode, - 'customized' => $replace ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, - 'overwrite_options' => $replace ? ['customized' => 1, 'not_customized' => 1] : ['customized' => 0, 'not_customized' => 1], + $importer_options = array_merge(_locale_translation_default_update_options(), [ + 'langcode' => $opt_langcode, + 'customized' => $opt_set_customized ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, + 'overwrite_options' => [ + 'customized' => (int) $opt_replace_customized, + 'not_customized' => (int) $opt_replace_not_customized, + ], ]); // Import language files. $files = []; - $langcodes = []; - foreach ($poFiles as $poFile) { - // Probably not an absolute path: test from the original $cwd. - if (!file_exists($poFile)) { - $poFile = DRUPAL_ROOT . DIRECTORY_SEPARATOR . $poFile; - } - + $langcodes_to_import = []; + foreach ($poFiles as $file_path) { // Ensure we have the file intended for upload. - if (file_exists($poFile)) { - // Create file object. - $file = locale_translate_file_create($poFile); + if (file_exists($file_path)) { + $file = locale_translate_file_create($file_path); + // Extract project, version and language code from the file name // Supported: // - {project}-{version}.{langcode}.po, {prefix}.{langcode}.po // - {langcode}.po - // or from user input. - $file = locale_translate_file_attach_properties($file, $buildOptions); + // Note: $options['langcode'] will override file langcode. + $file = locale_translate_file_attach_properties($file, $importer_options); if ($file->langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) { - $file->langcode = $langcode; + if (!$opt_langcode) { + $io->error($t('Can not autodetect language of file @file', ['@file' => $file_path])); + return; + } + $file->langcode = $opt_langcode; if (empty($file->version) && !empty($file->project) && !empty($file->langcode)) { $sources = locale_translation_get_status(); $source = $sources[$file->project][$file->langcode]; @@ -282,41 +292,54 @@ class DrushLanguageCliService { } } } - $langcodes[] = $file->langcode; + $langcodes_to_import[$file->langcode] = $file->langcode; $files[] = $file; } else { - $io->error($t('File to import at {filepath} not found.', [ - 'filepath' => $poFile, - ])); + $io->error($t('File to import at @filepath not found.', ['@filepath' => $file_path])); + } + } + + if ($opt_autocreate_language) { + $languages = $this->languageManager->getLanguages(); + foreach ($langcodes_to_import as $langcode_to_import) { + if (!isset($languages[$langcode_to_import])) { + try { + /** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $language_storage */ + $language_storage = $this->entityTypeManager->getStorage('configurable_language'); + $language = $language_storage->create(['langcode' => $opt_langcode]); + $io->success($t('The language @id (@label) has been created.', [ + '@id' => $language->id(), + '@label' => $language->label(), + ])); + } + catch (InvalidPluginDefinitionException $exception) { + $io->error($exception->getMessage()); + } + } } } - $batch = locale_translate_batch_build($files, $buildOptions); + $batch = locale_translate_batch_build($files, $importer_options); batch_set($batch); // Create or update all configuration translations for this language. - $langcodes = array_unique($langcodes); - if ($batch = locale_config_batch_update_components($buildOptions, $langcodes)) { + if ($batch = locale_config_batch_update_components($importer_options, $langcodes_to_import)) { batch_set($batch); } // TODO: The batch will need rework for Drupal console compatibility. drush_backend_batch_process(); - $io->text($t('Import complete.')); + $io->success($t('Import complete.')); } /** * Export strings of a language as a .po file. * - * @param \Symfony\Component\Console\Style\StyleInterface|\ConfigSplitDrush8Io $io + * @param \Symfony\Component\Console\Style\StyleInterface|\Drupal\drush_language\Drush8Io $io * The $io interface of the cli tool calling. * @param callable $t * The translation function akin to t(). - * @param string $langcode - * The langcode of the language to exported. - * @param string $poFile - * Path to a .po file. Use "-" or /dev/stdin to use standard output. * @param array $options * The command options. * @@ -330,89 +353,120 @@ class DrushLanguageCliService { public function exportTranslations( $io, callable $t, - $langcode, - $poFile, - array $options = ['status' => NULL] + array $options = [ + 'statuses' => ['customized'], + 'langcodes' => [], + 'file' => '%langcode.po', + 'force' => TRUE, + ] ) { - // Ensure the langcode matches an existing language. - $language = $this->languageManager->getLanguage($langcode); - if (empty($language)) { - throw new \Exception('No such language {langcode}', [ - 'langcode' => $langcode, - ]); - } - - // Validate export statuses. - $exportStatusesAllowed = [ - // Internal-value => input-value. + // Get options. + $opt_langcodes = $options['langcodes']; + $opt_filepath = $options['file']; + $opt_force_write = $options['force']; + $opt_statuses = $options['statuses']; + + // Massage options. + // Massage translation statuses. + $export_statuses_allowed = [ + // internal-value => input-value. 'customized' => 'customized', 'not_customized' => 'not-customized', 'not_translated' => 'not-translated', ]; - $exportStatusesInput = isset($options['status']) ? $options['status'] : ['customized']; - $exportStatusesInput = array_values($exportStatusesInput); - if ($exportStatusesInput == ['all']) { - $exportStatusesInput = $exportStatusesAllowed; + $opt_statuses = array_values($opt_statuses); + if ($opt_statuses == ['all']) { + $opt_statuses = $export_statuses_allowed; } - - $exportStatusesUnknown = array_diff($exportStatusesInput, $exportStatusesAllowed); - if ($exportStatusesUnknown) { - $statusArgs = ['options' => implode(', ', $exportStatusesUnknown)]; - throw new \Exception($t('Unknown status options: {options}', - $statusArgs)); + $export_statuses_unknown = array_diff($opt_statuses, $export_statuses_allowed); + if ($export_statuses_unknown) { + $io->error($t('Unknown status options: @options', + ['@options' => implode(', ', $export_statuses_unknown)] + )); + return; } + $export_statuses_filtered = array_intersect($export_statuses_allowed, $opt_statuses); + $export_statuses = array_fill_keys(array_keys($export_statuses_filtered), TRUE); - $exportStatusesFiltered = array_intersect($exportStatusesAllowed, $exportStatusesInput); - $exportStatuses = array_fill_keys(array_keys($exportStatusesFiltered), TRUE); - - // Relative path should be relative to cwd(), rather than Drupal root-dir. // TODO: This will need rework for Drupal console compatibility. - $filePath = drush_is_absolute_path($poFile) - ? $poFile - : DRUPAL_ROOT . DIRECTORY_SEPARATOR . $poFile; - - // Check if file_path exists and is writable. - $dir = dirname($filePath); - if (!file_prepare_directory($dir)) { - file_prepare_directory($dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY); + // Massage file path pattern. + if (!drush_is_absolute_path($opt_filepath) && !('./' === substr($opt_filepath, 0, 2))) { + $opt_filedir = Settings::get('custom_translations_directory'); + if (!$opt_filedir) { + $io->error($t('Can not export, relative path given and no $settings[\'custom_translations_directory\'] defined. You can instead use an absolute filename or one starting with "./".')); + return; + } + if (!drush_is_absolute_path($opt_filedir)) { + $opt_filedir = DRUPAL_ROOT . DIRECTORY_SEPARATOR . $opt_filedir; + } + $opt_filepath = $opt_filedir . DIRECTORY_SEPARATOR . $opt_filepath; } - $reader = new PoDatabaseReader(); - $language_name = ''; - if ($language != NULL) { - $reader->setLangcode($language->getId()); - $reader->setOptions($exportStatuses); + // Massage langcodes. + if (!$opt_langcodes) { $languages = $this->languageManager->getLanguages(); - $language_name = isset($languages[$language->getId()]) ? $languages[$language->getId()]->getName() : ''; + $opt_langcodes = array_keys($languages); + } + + // Validate options. + // Yell if more than 1 langcode and no placeholder. + if (count($opt_langcodes) > 1 && !preg_match('/%langcode/u', $opt_filepath)) { + $io->error($t('You must use %langcode file placeholder when exporting multiple languages.')); + return; } - $item = $reader->readItem(); - if (!empty($item)) { - try { + // Check that all langcodes are valid, before beginning. + foreach ($opt_langcodes as $langcode) { + $language = $this->languageManager->getLanguage($langcode); + if ($language == NULL) { + $io->error($t('Unknown language: %langcode', ['%langcode' => $langcode])); + return; + } + } + + // Do our work. + foreach ($opt_langcodes as $langcode) { + $filepath = preg_replace('/%langcode/u', $langcode, $opt_filepath); + $language = $this->languageManager->getLanguage($langcode); + + // Check if file_path exists and is writable. + $dir = dirname($filepath); + if (!file_prepare_directory($dir)) { + file_prepare_directory($dir, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY); + } + + $reader = new PoDatabaseReader(); + $language_name = ''; + if ($language != NULL) { + $reader->setLangcode($language->getId()); + $reader->setOptions($export_statuses); + $languages = $this->languageManager->getLanguages(); + $language_name = isset($languages[$language->getId()]) ? $languages[$language->getId()]->getName() : ''; + } + $item = $reader->readItem(); + if ($item || $opt_force_write) { $header = $reader->getHeader(); $header->setProjectName($this->configFactory->get('system.site')->get('name')); $header->setLanguageName($language_name); $writer = new PoStreamWriter(); - $writer->setUri($filePath); + $writer->setUri($filepath); $writer->setHeader($header); $writer->open(); - $writer->writeItem($item); + if ($item) { + $writer->writeItem($item); + } $writer->writeItems($reader); $writer->close(); - $io->text($t('Export complete.')); + $io->success($t('Exported translations for language !langcode to file !file.', ['!langcode' => $langcode, '!file' => $filepath])); } - catch (\Exception $exception) { - $io->error($t('Error when exporting @filePath: @message', [ - '@filePath' => $filePath, - '@message' => $exception->getMessage(), - ])); + else { + $io->error($t('Nothing to export for language !langcode.', ['!langcode' => $langcode])); + return; } } - else { - throw new \Exception($t('Nothing to export.')); - } + $io->success($t('Export complete.')); } /** -- 2.1.4 From 58a43f2d1c14bd47c2449fb60ae2904cf6bdd4f7 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 19:34:14 +0100 Subject: [PATCH 11/16] Issue #2914081 by Grimreaper: Fix service namespace --- drush.services.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drush.services.yml b/drush.services.yml index f32a1c3..3511f22 100644 --- a/drush.services.yml +++ b/drush.services.yml @@ -1,6 +1,6 @@ services: drush_language.commands: - class: \Drupal\drupal_language\Commands\DrushLanguageCommands + class: \Drupal\drush_language\Commands\DrushLanguageCommands arguments: - '@drush_language.cli' tags: -- 2.1.4 From 49ab3bf4d90576df0a611ab64b91d5112aa8e582 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 19:34:41 +0100 Subject: [PATCH 12/16] Issue #2914081 by Grimreaper: Fix default language command --- src/Service/DrushLanguageCliService.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Service/DrushLanguageCliService.php b/src/Service/DrushLanguageCliService.php index d707863..ca6c6f3 100644 --- a/src/Service/DrushLanguageCliService.php +++ b/src/Service/DrushLanguageCliService.php @@ -196,15 +196,8 @@ class DrushLanguageCliService { return; } - try { - /** @var \Drupal\language\ConfigurableLanguageInterface $default_language */ - $default_language = ConfigurableLanguage::load($langcode); - $default_language->set('default', TRUE)->save(); - $io->text($t('{langcode} assigned as default', $messageArgs)); - } - catch (EntityStorageException $exception) { - $io->error($exception->getMessage()); - } + $this->configFactory->getEditable('system.site')->set('default_langcode', $langcode)->save(); + $this->languageManager->reset(); } /** -- 2.1.4 From fc9a777112ddbf2ceabdae4b247378bb2a42ffb7 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 19:52:47 +0100 Subject: [PATCH 13/16] Issue #2914081 by Grimreaper: Fix method "drush_is_absolute_path" no more exists in Drush 9 --- src/Service/DrushLanguageCliService.php | 34 +++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Service/DrushLanguageCliService.php b/src/Service/DrushLanguageCliService.php index ca6c6f3..468021a 100644 --- a/src/Service/DrushLanguageCliService.php +++ b/src/Service/DrushLanguageCliService.php @@ -6,7 +6,6 @@ use Drupal\Component\Gettext\PoStreamWriter; use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageInterface; @@ -381,15 +380,14 @@ class DrushLanguageCliService { $export_statuses_filtered = array_intersect($export_statuses_allowed, $opt_statuses); $export_statuses = array_fill_keys(array_keys($export_statuses_filtered), TRUE); - // TODO: This will need rework for Drupal console compatibility. // Massage file path pattern. - if (!drush_is_absolute_path($opt_filepath) && !('./' === substr($opt_filepath, 0, 2))) { + if (!$this->isAbsolutePath($opt_filepath) && !('./' === substr($opt_filepath, 0, 2))) { $opt_filedir = Settings::get('custom_translations_directory'); if (!$opt_filedir) { $io->error($t('Can not export, relative path given and no $settings[\'custom_translations_directory\'] defined. You can instead use an absolute filename or one starting with "./".')); return; } - if (!drush_is_absolute_path($opt_filedir)) { + if (!$this->isAbsolutePath($opt_filedir)) { $opt_filedir = DRUPAL_ROOT . DIRECTORY_SEPARATOR . $opt_filedir; } $opt_filepath = $opt_filedir . DIRECTORY_SEPARATOR . $opt_filepath; @@ -472,4 +470,32 @@ class DrushLanguageCliService { return $this->errors; } + /** + * Helper function to check if a path is an absolute path. + * + * TODO: This will need work for Drupal console compatibility. + * + * @param string $path + * The path to check. + * + * @return bool + * TRUE if the path is absolute. FALSE otherwise. + */ + protected function isAbsolutePath($path) { + $result = FALSE; + + // Targets Drush 9 or higher. + if (class_exists('\Drush\Drush')) { + // @codingStandardsIgnoreStart + \Webmozart\PathUtil\Path::isAbsolute($path); + // @codingStandardsIgnoreEnd + } + // Targets Drush 8 or lower. + elseif (function_exists('drush_is_absolute_path')) { + $result = drush_is_absolute_path($path); + } + + return $result; + } + } -- 2.1.4 From b98b9770201c280c84c039550c68a75daf8ec9c7 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 20:18:50 +0100 Subject: [PATCH 14/16] Issue #2914081 by Grimreaper: Drush 8: Fix warning display, namespace and string replacements. --- drush_language.drush.inc | 5 +++-- src/Drush8Io.php | 6 +++++- src/Service/DrushLanguageCliService.php | 12 ++++++------ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drush_language.drush.inc b/drush_language.drush.inc index e77f5bd..fad39e7 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -5,7 +5,7 @@ * Drush (< 9) integration for the drush_language module. */ -use Drupal\drupal_language\Drush8Io; +use Drupal\drush_language\Drush8Io; /** * Implements hook_drush_command(). @@ -101,7 +101,8 @@ function drush_drush_language_language_add() { return drush_set_error('DRUSH_LANGUAGE', dt('Please provide one or more language codes as arguments.')); } - \Drupal::service('drush_language.cli')->languageDefault(new Drush8Io(), 'dt', $args); + $langcodes = explode(',', $args[0]); + \Drupal::service('drush_language.cli')->add(new Drush8Io(), 'dt', $langcodes); } /** diff --git a/src/Drush8Io.php b/src/Drush8Io.php index 1ea4ab3..e5d5867 100644 --- a/src/Drush8Io.php +++ b/src/Drush8Io.php @@ -1,6 +1,6 @@ $langcode]; + $messageArgs = ['@langcode' => $langcode]; // In the foreach loop because the list changes on successful iterations. $languages = $this->languageManager->getLanguages(); // Do not re-add existing languages. if (isset($languages[$langcode])) { - $io->warning($t('The language with code {langcode} already exists.', $messageArgs)); + $io->warning($t('The language with code @langcode already exists.', $messageArgs)); continue; } @@ -149,7 +149,7 @@ class DrushLanguageCliService { // In the foreach loop because the list changes on successful iterations. $predefined = $this->languageManager->getStandardLanguageListWithoutConfigured(); if (!isset($predefined[$langcode])) { - $io->warning($t('Invalid language code {langcode}', $messageArgs)); + $io->warning($t('Invalid language code: @langcode', $messageArgs)); continue; } @@ -173,7 +173,7 @@ class DrushLanguageCliService { } } - $io->text($t('Added language: {langcode}', $messageArgs)); + $io->text($t('Added language: @langcode', $messageArgs)); } } @@ -188,10 +188,10 @@ class DrushLanguageCliService { * The langcode of the language which will be set as the default language. */ public function languageDefault($io, callable $t, $langcode) { - $messageArgs = ['langcode' => $langcode]; + $messageArgs = ['@langcode' => $langcode]; $languages = $this->languageManager->getLanguages(); if (!isset($languages[$langcode])) { - $io->warning($t('Specified language does not exist {langcode}', $messageArgs)); + $io->warning($t('Specified language does not exist: @langcode', $messageArgs)); return; } -- 2.1.4 From 317f75ab912dbc02967bf524d1e2a148c04e7a8f Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 20:50:35 +0100 Subject: [PATCH 15/16] Issue #2914081 by Grimreaper: Drush 8: Fix missing hook command callback for default language. --- drush_language.drush.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drush_language.drush.inc b/drush_language.drush.inc index fad39e7..dab858c 100644 --- a/drush_language.drush.inc +++ b/drush_language.drush.inc @@ -108,7 +108,7 @@ function drush_drush_language_language_add() { /** * Assigns the default language. */ -function drush_drush_language_default() { +function drush_drush_language_language_default() { $args = func_get_args(); if (count($args) == 0) { return drush_set_error('DRUSH_LANGUAGE', dt('Please provide one or more language codes as arguments.')); -- 2.1.4 From 1423cc442188a1d791a99ef79cbdb92974bb1647 Mon Sep 17 00:00:00 2001 From: florenttorregrosa Date: Sat, 17 Feb 2018 20:55:13 +0100 Subject: [PATCH 16/16] Issue #2914081 by Grimreaper: Remove TODO relative to Drupal console. This module name is "drush_language". --- src/Service/DrushLanguageCliService.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Service/DrushLanguageCliService.php b/src/Service/DrushLanguageCliService.php index 4ce768d..ad7de98 100644 --- a/src/Service/DrushLanguageCliService.php +++ b/src/Service/DrushLanguageCliService.php @@ -167,7 +167,6 @@ class DrushLanguageCliService { $batch =& batch_get(); $batch['progressive'] = FALSE; - // TODO: The batch will need rework for Drupal console compatibility. // Process the batch. drush_backend_batch_process(); } @@ -320,7 +319,6 @@ class DrushLanguageCliService { batch_set($batch); } - // TODO: The batch will need rework for Drupal console compatibility. drush_backend_batch_process(); $io->success($t('Import complete.')); } @@ -473,8 +471,6 @@ class DrushLanguageCliService { /** * Helper function to check if a path is an absolute path. * - * TODO: This will need work for Drupal console compatibility. - * * @param string $path * The path to check. * -- 2.1.4