You are here

class TranslationStatusForm in Drupal 8

Same name and namespace in other branches
  1. 9 core/modules/locale/src/Form/TranslationStatusForm.php \Drupal\locale\Form\TranslationStatusForm

Provides a translation status form.

@internal

Hierarchy

Expanded class hierarchy of TranslationStatusForm

1 string reference to 'TranslationStatusForm'
locale.routing.yml in core/modules/locale/locale.routing.yml
core/modules/locale/locale.routing.yml

File

core/modules/locale/src/Form/TranslationStatusForm.php, line 17

Namespace

Drupal\locale\Form
View source
class TranslationStatusForm extends FormBase {

  /**
   * The module handler service.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * The Drupal state storage service.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('module_handler'), $container
      ->get('state'));
  }

  /**
   * Constructs a TranslationStatusForm object.
   *
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   A module handler.
   * @param \Drupal\Core\State\StateInterface $state
   *   The state service.
   */
  public function __construct(ModuleHandlerInterface $module_handler, StateInterface $state) {
    $this->moduleHandler = $module_handler;
    $this->state = $state;
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'locale_translation_status_form';
  }

  /**
   * Form builder for displaying the current translation status.
   *
   * @ingroup forms
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $languages = locale_translatable_language_list();
    $status = locale_translation_get_status();
    $options = [];
    $languages_update = [];
    $languages_not_found = [];
    $projects_update = [];

    // Prepare information about projects which have available translation
    // updates.
    if ($languages && $status) {
      $updates = $this
        ->prepareUpdateData($status);

      // Build data options for the select table.
      foreach ($updates as $langcode => $update) {
        $title = $languages[$langcode]
          ->getName();
        $locale_translation_update_info = [
          '#theme' => 'locale_translation_update_info',
        ];
        foreach ([
          'updates',
          'not_found',
        ] as $update_status) {
          if (isset($update[$update_status])) {
            $locale_translation_update_info['#' . $update_status] = $update[$update_status];
          }
        }
        $options[$langcode] = [
          'title' => [
            'data' => [
              '#title' => $title,
              '#plain_text' => $title,
            ],
          ],
          'status' => [
            'class' => [
              'description',
              'priority-low',
            ],
            'data' => $locale_translation_update_info,
          ],
        ];
        if (!empty($update['not_found'])) {
          $languages_not_found[$langcode] = $langcode;
        }
        if (!empty($update['updates'])) {
          $languages_update[$langcode] = $langcode;
        }
      }

      // Sort the table data on language name.
      uasort($options, function ($a, $b) {
        return strcasecmp($a['title']['data']['#title'], $b['title']['data']['#title']);
      });
      $languages_not_found = array_diff($languages_not_found, $languages_update);
    }
    $last_checked = $this->state
      ->get('locale.translation_last_checked');
    $form['last_checked'] = [
      '#theme' => 'locale_translation_last_check',
      '#last' => $last_checked,
    ];
    $header = [
      'title' => [
        'data' => $this
          ->t('Language'),
        'class' => [
          'title',
        ],
      ],
      'status' => [
        'data' => $this
          ->t('Status'),
        'class' => [
          'status',
          'priority-low',
        ],
      ],
    ];
    if (!$languages) {
      $empty = $this
        ->t('No translatable languages available. <a href=":add_language">Add a language</a> first.', [
        ':add_language' => Url::fromRoute('entity.configurable_language.collection')
          ->toString(),
      ]);
    }
    elseif ($status) {
      $empty = $this
        ->t('All translations up to date.');
    }
    else {
      $empty = $this
        ->t('No translation status available. <a href=":check">Check manually</a>.', [
        ':check' => Url::fromRoute('locale.check_translation')
          ->toString(),
      ]);
    }

    // The projects which require an update. Used by the _submit callback.
    $form['projects_update'] = [
      '#type' => 'value',
      '#value' => $projects_update,
    ];
    $form['langcodes'] = [
      '#type' => 'tableselect',
      '#header' => $header,
      '#options' => $options,
      '#default_value' => $languages_update,
      '#empty' => $empty,
      '#js_select' => TRUE,
      '#multiple' => TRUE,
      '#required' => TRUE,
      '#not_found' => $languages_not_found,
      '#after_build' => [
        'locale_translation_language_table',
      ],
    ];
    $form['#attached']['library'][] = 'locale/drupal.locale.admin';
    $form['actions'] = [
      '#type' => 'actions',
    ];
    if ($languages_update) {
      $form['actions']['submit'] = [
        '#type' => 'submit',
        '#value' => $this
          ->t('Update translations'),
      ];
    }
    return $form;
  }

  /**
   * Prepare information about projects with available translation updates.
   *
   * @param array $status
   *   Translation update status as an array keyed by Project ID and langcode.
   *
   * @return array
   *   Translation update status as an array keyed by language code and
   *   translation update status.
   */
  protected function prepareUpdateData(array $status) {
    $updates = [];

    // @todo Calling locale_translation_build_projects() is an expensive way to
    //   get a module name. In follow-up issue
    //   https://www.drupal.org/node/1842362 the project name will be stored to
    //   display use, like here.
    $this->moduleHandler
      ->loadInclude('locale', 'compare.inc');
    $project_data = locale_translation_build_projects();
    foreach ($status as $project_id => $project) {
      foreach ($project as $langcode => $project_info) {

        // No translation file found for this project-language combination.
        if (empty($project_info->type)) {
          $updates[$langcode]['not_found'][] = [
            'name' => $project_info->name == 'drupal' ? $this
              ->t('Drupal core') : $project_data[$project_info->name]->info['name'],
            'version' => $project_info->version,
            'info' => $this
              ->createInfoString($project_info),
          ];
        }
        elseif ($project_info->type == LOCALE_TRANSLATION_LOCAL || $project_info->type == LOCALE_TRANSLATION_REMOTE) {
          $local = isset($project_info->files[LOCALE_TRANSLATION_LOCAL]) ? $project_info->files[LOCALE_TRANSLATION_LOCAL] : NULL;
          $remote = isset($project_info->files[LOCALE_TRANSLATION_REMOTE]) ? $project_info->files[LOCALE_TRANSLATION_REMOTE] : NULL;
          $recent = _locale_translation_source_compare($local, $remote) == LOCALE_TRANSLATION_SOURCE_COMPARE_LT ? $remote : $local;
          $updates[$langcode]['updates'][] = [
            'name' => $project_info->name == 'drupal' ? $this
              ->t('Drupal core') : $project_data[$project_info->name]->info['name'],
            'version' => $project_info->version,
            'timestamp' => $recent->timestamp,
          ];
        }
      }
    }
    return $updates;
  }

  /**
   * Provides debug info for projects in case translation files are not found.
   *
   * Translations files are being fetched either from Drupal translation server
   * and local files or only from the local filesystem depending on the
   * "Translation source" setting at admin/config/regional/translate/settings.
   * This method will produce debug information including the respective path(s)
   * based on this setting.
   *
   * @param array $project_info
   *   An array which is the project information of the source.
   *
   * @return string
   *   The string which contains debug information.
   */
  protected function createInfoString($project_info) {
    $remote_path = isset($project_info->files['remote']->uri) ? $project_info->files['remote']->uri : FALSE;
    $local_path = isset($project_info->files['local']->uri) ? $project_info->files['local']->uri : FALSE;
    if (locale_translation_use_remote_source() && $remote_path && $local_path) {
      return $this
        ->t('File not found at %remote_path nor at %local_path', [
        '%remote_path' => $remote_path,
        '%local_path' => $local_path,
      ]);
    }
    elseif ($local_path) {
      return $this
        ->t('File not found at %local_path', [
        '%local_path' => $local_path,
      ]);
    }
    return $this
      ->t('Translation file location could not be determined.');
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {

    // Check if a language has been selected. 'tableselect' doesn't.
    if (!array_filter($form_state
      ->getValue('langcodes'))) {
      $form_state
        ->setErrorByName('', $this
        ->t('Select a language to update.'));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->moduleHandler
      ->loadInclude('locale', 'fetch.inc');
    $this->moduleHandler
      ->loadInclude('locale', 'bulk.inc');
    $langcodes = array_filter($form_state
      ->getValue('langcodes'));
    $projects = array_filter($form_state
      ->getValue('projects_update'));

    // Set the translation import options. This determines if existing
    // translations will be overwritten by imported strings.
    $options = _locale_translation_default_update_options();

    // If the status was updated recently we can immediately start fetching the
    // translation updates. If the status is expired we clear it an run a batch to
    // update the status and then fetch the translation updates.
    $last_checked = $this->state
      ->get('locale.translation_last_checked');
    if ($last_checked < REQUEST_TIME - LOCALE_TRANSLATION_STATUS_TTL) {
      locale_translation_clear_status();
      $batch = locale_translation_batch_update_build([], $langcodes, $options);
      batch_set($batch);
    }
    else {

      // Set a batch to download and import translations.
      $batch = locale_translation_batch_fetch_build($projects, $langcodes, $options);
      batch_set($batch);

      // Set a batch to update configuration as well.
      if ($batch = locale_config_batch_update_components($options, $langcodes)) {
        batch_set($batch);
      }
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FormBase::$configFactory protected property The config factory. 1
FormBase::$requestStack protected property The request stack. 1
FormBase::$routeMatch protected property The route match.
FormBase::config protected function Retrieves a configuration object.
FormBase::configFactory protected function Gets the config factory for this form. 1
FormBase::container private function Returns the service container.
FormBase::currentUser protected function Gets the current user.
FormBase::getRequest protected function Gets the request object.
FormBase::getRouteMatch protected function Gets the route match.
FormBase::logger protected function Gets the logger for a specific channel.
FormBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
FormBase::resetConfigFactory public function Resets the configuration factory.
FormBase::setConfigFactory public function Sets the config factory for this form.
FormBase::setRequestStack public function Sets the request stack object to use.
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
TranslationStatusForm::$moduleHandler protected property The module handler service.
TranslationStatusForm::$state protected property The Drupal state storage service.
TranslationStatusForm::buildForm public function Form builder for displaying the current translation status. Overrides FormInterface::buildForm
TranslationStatusForm::create public static function Instantiates a new instance of this class. Overrides FormBase::create
TranslationStatusForm::createInfoString protected function Provides debug info for projects in case translation files are not found.
TranslationStatusForm::getFormId public function Returns a unique string identifying the form. Overrides FormInterface::getFormId
TranslationStatusForm::prepareUpdateData protected function Prepare information about projects with available translation updates.
TranslationStatusForm::submitForm public function Form submission handler. Overrides FormInterface::submitForm
TranslationStatusForm::validateForm public function Form validation handler. Overrides FormBase::validateForm
TranslationStatusForm::__construct public function Constructs a TranslationStatusForm object.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.