You are here

class LingotekConfigManagementForm in Lingotek Translation 8

Same name and namespace in other branches
  1. 8.2 src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  2. 4.0.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  3. 3.0.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  4. 3.1.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  5. 3.2.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  6. 3.3.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  7. 3.4.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  8. 3.5.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  9. 3.6.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  10. 3.7.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm
  11. 3.8.x src/Form/LingotekConfigManagementForm.php \Drupal\lingotek\Form\LingotekConfigManagementForm

Form for bulk management of content.

Hierarchy

Expanded class hierarchy of LingotekConfigManagementForm

1 string reference to 'LingotekConfigManagementForm'
lingotek.routing.yml in ./lingotek.routing.yml
lingotek.routing.yml

File

src/Form/LingotekConfigManagementForm.php, line 40
Contains \Drupal\Lingotek\Form\LingotekConfigManagementForm.

Namespace

Drupal\lingotek\Form
View source
class LingotekConfigManagementForm extends FormBase {
  use LingotekSetupTrait;

  /**
   * The language-locale mapper.
   *
   * @var \Drupal\lingotek\LanguageLocaleMapperInterface
   */
  protected $languageLocaleMapper;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * The Lingotek configuration service.
   *
   * @var \Drupal\lingotek\LingotekConfigurationServiceInterface
   */
  protected $lingotekConfiguration;

  /**
   * The Lingotek content translation service.
   *
   * @var \Drupal\lingotek\LingotekConfigTranslationServiceInterface $translation_service
   */
  protected $translationService;

  /**
   * The tempstore factory.
   *
   * @var \Drupal\user\PrivateTempStoreFactory
   */
  protected $tempStoreFactory;

  /**
   * A array of configuration mapper instances.
   *
   * @var \Drupal\config_translation\ConfigMapperInterface[]
   */
  protected $mappers;

  /**
   * The type of config to display.
   *
   * @var string
   */
  protected $filter;

  /**
   * Constructs a new LingotekManagementForm object.
   *
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   * @param \Drupal\lingotek\LingotekConfigurationServiceInterface $lingotek_configuration
   *   The Lingotek configuration service.
   * @param \Drupal\lingotek\LanguageLocaleMapperInterface $language_locale_mapper
   *  The language-locale mapper.
   * @param \Drupal\lingotek\LingotekConfigTranslationServiceInterface $translation_service
   *   The Lingotek config translation service.
   * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
   *   The factory for the temp store object.
   * @param string $entity_type_id
   *   The entity type id.
   */
  public function __construct(LanguageManagerInterface $language_manager, LingotekConfigurationServiceInterface $lingotek_configuration, LanguageLocaleMapperInterface $language_locale_mapper, LingotekConfigTranslationServiceInterface $translation_service, PrivateTempStoreFactory $temp_store_factory, array $mappers) {
    $this->languageManager = $language_manager;
    $this->translationService = $translation_service;
    $this->tempStoreFactory = $temp_store_factory;
    $this->lingotek = \Drupal::service('lingotek');
    $this->lingotekConfiguration = $lingotek_configuration;
    $this->languageLocaleMapper = $language_locale_mapper;
    $this->mappers = $mappers;
    $this->filter = 'config';
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('language_manager'), $container
      ->get('lingotek.configuration'), $container
      ->get('lingotek.language_locale_mapper'), $container
      ->get('lingotek.config_translation'), $container
      ->get('user.private_tempstore'), $container
      ->get('plugin.manager.config_translation.mapper')
      ->getMappers());
  }

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    if ($redirect = $this
      ->checkSetup()) {
      return $redirect;
    }
    $showingFields = FALSE;
    $this->filter = $this
      ->getFilter();

    // ToDo: Find a better filter?
    if ($this->filter === 'config') {
      $mappers = array_filter($this->mappers, function ($mapper) {
        return $mapper instanceof ConfigNamesMapper && !$mapper instanceof ConfigEntityMapper && !$mapper instanceof ConfigFieldMapper;
      });
    }
    elseif (substr($this->filter, -7) == '_fields') {
      $showingFields = TRUE;
      $mapper = $this->mappers[$this->filter];
      $base_entity_type = $mapper
        ->getPluginDefinition()['base_entity_type'];
      $ids = \Drupal::entityQuery('field_config')
        ->condition('id', $base_entity_type . '.', 'STARTS_WITH')
        ->execute();
      $fields = FieldConfig::loadMultiple($ids);
      $mappers = [];
      foreach ($fields as $id => $field) {
        $new_mapper = clone $mapper;
        $new_mapper
          ->setEntity($field);
        $mappers[$field
          ->id()] = $new_mapper;
      }
    }
    else {
      $mapper = $this->mappers[$this->filter];
      $ids = \Drupal::entityQuery($this->filter)
        ->execute();
      $entities = \Drupal::entityManager()
        ->getStorage($this->filter)
        ->loadMultiple($ids);

      /** @var ConfigEntityMapper $mapper  */
      $mappers = [];
      foreach ($entities as $entity) {
        $new_mapper = clone $mapper;
        $new_mapper
          ->setEntity($entity);
        $mappers[$entity
          ->id()] = $new_mapper;
      }
    }
    $rows = [];
    foreach ($mappers as $mapper_id => $mapper) {
      $is_config_entity = $mapper instanceof ConfigEntityMapper;
      $source = $this
        ->getSourceStatus($mapper);
      $translations = $this
        ->getTranslationsStatuses($mapper);
      $profile = $is_config_entity ? $this->lingotekConfiguration
        ->getConfigEntityProfile($mapper
        ->getEntity(), FALSE) : $this->lingotekConfiguration
        ->getConfigProfile($mapper_id, FALSE);
      $form['table'][$mapper_id] = [
        '#type' => 'checkbox',
        '#value' => $mapper_id,
      ];
      $rows[$mapper_id] = [];
      $rows[$mapper_id] += [
        'title' => $mapper
          ->getTitle(),
        'source' => $source,
        'translations' => $translations,
        'profile' => $profile ? $profile
          ->label() : '',
      ];
      if ($showingFields) {
        $entity_type_id = $mapper
          ->getEntity()
          ->get('entity_type');
        $bundle = $mapper
          ->getEntity()
          ->get('bundle');
        $bundle_info = \Drupal::service('entity_type.bundle.info')
          ->getBundleInfo($entity_type_id);
        if (isset($bundle_info[$bundle])) {
          $rows[$mapper_id]['bundle'] = $bundle_info[$bundle]['label'];
        }
        else {
          $rows[$mapper_id]['bundle'] = $bundle;
        }
      }
    }

    // Add filters.
    $form['filters'] = array(
      '#type' => 'details',
      '#title' => $this
        ->t('Select config bundle'),
      '#open' => TRUE,
      '#weight' => 5,
      '#tree' => TRUE,
    );
    $form['filters']['wrapper'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'form--inline',
          'clearfix',
        ),
      ),
    );
    $form['filters']['wrapper']['bundle'] = array(
      '#type' => 'select',
      '#title' => $this
        ->t('Filter'),
      '#options' => [
        'config' => $this
          ->t('Config'),
      ] + $this
        ->getAllBundles(),
      '#default_value' => $this->filter,
      '#attributes' => array(
        'class' => array(
          'form-item',
        ),
      ),
    );
    $form['filters']['actions'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'clearfix',
        ),
      ),
    );
    $form['filters']['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this
        ->t('Filter'),
      '#submit' => array(
        '::filterForm',
      ),
    );

    // If we are showing field config instances, we need to show bundles for
    // a better UX.
    $headers = $showingFields ? [
      'bundle' => $this
        ->t('Bundle'),
    ] : [];
    $headers += [
      'title' => $this
        ->t('Entity'),
      'source' => $this
        ->t('Source'),
      'translations' => $this
        ->t('Translations'),
      'profile' => $this
        ->t('Profile'),
    ];

    // Build an 'Update options' form.
    $form['options'] = array(
      '#type' => 'details',
      '#title' => $this
        ->t('Bulk document management'),
      '#open' => TRUE,
      '#attributes' => array(
        'class' => array(
          'container-inline',
        ),
      ),
      '#weight' => 10,
    );
    $form['options']['operation'] = array(
      '#type' => 'select',
      '#title' => $this
        ->t('Action'),
      '#title_display' => 'invisible',
      '#options' => $this
        ->generateBulkOptions(),
    );
    $form['options']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this
        ->t('Execute'),
    );
    $form['table'] = [
      '#header' => $headers,
      '#options' => $rows,
      '#empty' => $this
        ->t('No content available'),
      '#type' => 'tableselect',
      '#weight' => 30,
    ];
    $form['pager'] = [
      '#type' => 'pager',
      '#weight' => 50,
    ];
    $form['#attached']['library'][] = 'lingotek/lingotek';
    return $form;
  }

  /**
   * Gets the filter to be applied. By default will be 'config'.
   *
   * @return string
   */
  protected function getFilter() {

    /** @var PrivateTempStore $temp_store */
    $temp_store = $this->tempStoreFactory
      ->get('lingotek.config_management.filter');
    $value = $temp_store
      ->get('bundle');
    if (!$value) {
      $value = 'config';
    }
    return $value;
  }

  /**
   * Form submission handler for filtering.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function filterForm(array &$form, FormStateInterface $form_state) {
    $value = $form_state
      ->getValue([
      'filters',
      'wrapper',
      'bundle',
    ]);

    /** @var PrivateTempStore $temp_store */
    $temp_store = $this->tempStoreFactory
      ->get('lingotek.config_management.filter');
    $temp_store
      ->set('bundle', $value);
    $this->filter = $value;

    // If we apply any filters, we need to go to the first page again.
    $form_state
      ->setRedirect('<current>');
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $operation = $form_state
      ->getValue('operation');
    $values = array_keys(array_filter($form_state
      ->getValue([
      'table',
    ], function ($key, $value) {
      return $value;
    })));
    $processed = FALSE;
    switch ($operation) {
      case 'debug.export':
        $this
          ->createDebugExportBatch($values);
        $processed = TRUE;
        break;
      case 'upload':
        $this
          ->createUploadBatch($values);
        $processed = TRUE;
        break;
      case 'check_upload':
        $this
          ->createUploadCheckStatusBatch($values);
        $processed = TRUE;
        break;
      case 'request_translations':
        $this
          ->createRequestTranslationsBatch($values);
        $processed = TRUE;
        break;
      case 'check_translations':
        $this
          ->createTranslationCheckStatusBatch($values);
        $processed = TRUE;
        break;
      case 'download':
        $this
          ->createDownloadBatch($values);
        $processed = TRUE;
        break;
      case 'disassociate':
        $this
          ->createDisassociateBatch($values);
        $processed = TRUE;
        break;
      case 'delete_nodes':
        $this
          ->redirectToDeleteMultipleNodesForm($values, $form_state);
        $processed = TRUE;
        break;
    }
    if (!$processed) {
      if (0 === strpos($operation, 'request_translation:')) {
        list($operation, $language) = explode(':', $operation);
        $this
          ->createLanguageRequestTranslationBatch($values, $language);
        $processed = TRUE;
      }
      if (0 === strpos($operation, 'check_translation:')) {
        list($operation, $language) = explode(':', $operation);
        $this
          ->createLanguageTranslationCheckStatusBatch($values, $language);
        $processed = TRUE;
      }
      if (0 === strpos($operation, 'download:')) {
        list($operation, $language) = explode(':', $operation);
        $this
          ->createLanguageDownloadBatch($values, $language);
        $processed = TRUE;
      }
    }
  }
  protected function getAllBundles() {
    $mappers = array_filter($this->mappers, function ($mapper) {

      // Filter config entity mappers and config field mappers.
      return $mapper instanceof ConfigEntityMapper;
    });
    $bundles = [];
    foreach ($mappers as $bundle => $mapper) {

      /** @var ConfigEntityMapper $mapper */
      $bundles[$bundle] = $mapper
        ->getTypeLabel();
    }
    return $bundles;
  }

  /**
   * Performs an operation to several values in a batch.
   *
   * @param string $operation
   *   The method in this object we need to call.
   * @param array $values
   *   Array of ids to process.
   * @param string $title
   *   The title for the batch progress.
   * @param string $language
   *   The language code for the request. NULL if is not applicable.
   */
  protected function createBatch($operation, $values, $title, $language = NULL) {
    $operations = $this
      ->generateOperations($operation, $values, $language);
    $batch = array(
      'title' => $title,
      'operations' => $operations,
      'finished' => [
        $this,
        'batchFinished',
      ],
      'progressive' => TRUE,
    );
    batch_set($batch);
  }
  public function batchFinished($success, $results, $operations) {
    if ($success) {
      drupal_set_message('Operations completed.');
    }
  }

  /**
   * Create and set an upload batch.
   *
   * @param array $values
   *   Array of ids to upload.
   */
  protected function createUploadBatch($values) {
    $this
      ->createBatch('uploadDocument', $values, $this
      ->t('Uploading content to Lingotek service'));
  }

  /**
   * Create and set an export batch.
   *
   * @param array $values
   *   Array of ids to upload.
   */
  protected function createDebugExportBatch($values) {
    $operations = $this
      ->generateOperations('debugExport', $values, NULL);
    $batch = array(
      'title' => $this
        ->t('Exporting config entities (debugging purposes)'),
      'operations' => $operations,
      'finished' => [
        $this,
        'debugExportFinished',
      ],
      'progressive' => TRUE,
    );
    batch_set($batch);
  }
  public function debugExportFinished($success, $results, $operations) {
    if ($success) {
      $links = [];
      foreach ($results['exported'] as $result) {
        $links[] = [
          '#theme' => 'file_link',
          '#file' => File::load($result),
        ];
      }
      $build = [
        '#theme' => 'item_list',
        '#items' => $links,
      ];
      drupal_set_message($this
        ->t('Exports available at: @exports', [
        '@exports' => drupal_render($build),
      ]));
    }
  }

  /**
   * Create and set a check upload status batch.
   *
   * @param array $values
   *   Array of ids to upload.
   */
  protected function createUploadCheckStatusBatch($values) {
    $this
      ->createBatch('checkDocumentUploadStatus', $values, $this
      ->t('Checking content upload status with the Lingotek service'));
  }

  /**
   * Create and set a request translations batch for all languages.
   *
   * @param array $values
   *   Array of ids to upload.
   */
  protected function createRequestTranslationsBatch($values) {
    $this
      ->createBatch('requestTranslations', $values, $this
      ->t('Requesting translations to Lingotek service.'));
  }

  /**
   * Create and set a request translations batch for all languages.
   *
   * @param array $values
   *   Array of ids to upload.
   * @param string $language
   *   Language code for the request.
   */
  protected function createLanguageRequestTranslationBatch($values, $language) {
    $this
      ->createBatch('requestTranslation', $values, $this
      ->t('Requesting translations to Lingotek service.'), $language);
  }

  /**
   * Create and set a check translation status batch for all languages.
   *
   * @param array $values
   *   Array of ids to upload.
   */
  protected function createTranslationCheckStatusBatch($values) {
    $this
      ->createBatch('checkTranslationStatuses', $values, $this
      ->t('Checking translations status from the Lingotek service.'));
  }

  /**
   * Create and set a check translation status batch for a given language.
   *
   * @param array $values
   *   Array of ids to upload.
   * @param string $language
   *   Language code for the request.
   */
  protected function createLanguageTranslationCheckStatusBatch($values, $language) {
    $this
      ->createBatch('checkTranslationStatus', $values, $this
      ->t('Checking translations status from the Lingotek service.'), $language);
  }

  /**
   * Create and set a request target and download batch for all languages.
   *
   * @param array $values
   *   Array of ids to upload.
   */
  protected function createDownloadBatch($values) {
    $this
      ->createBatch('downloadTranslations', $values, $this
      ->t('Downloading translations from the Lingotek service.'));
  }

  /**
   * Create and set a request target and download batch for a given language.
   *
   * @param array $values
   *   Array of ids to upload.
   * @param string $language
   *   Language code for the request.
   */
  protected function createLanguageDownloadBatch($values, $language) {
    $this
      ->createBatch('downloadTranslation', $values, $this
      ->t('Requesting translations to Lingotek service'), $language);
  }

  /**
   * Create and set a disassociate batch.
   *
   * @param array $values
   *   Array of ids to disassociate.
   */
  protected function createDisassociateBatch($values) {
    $this
      ->createBatch('disassociate', $values, $this
      ->t('Disassociating content from Lingotek service'));
  }

  /**
   * Export source for debugging purposes.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   */
  public function debugExport(ConfigMapperInterface $mapper, $language, &$context) {
    $context['message'] = $this
      ->t('Exporting %label.', [
      '%label' => $mapper
        ->getTitle(),
    ]);
    if ($profile = $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE) or TRUE) {
      $data = $this->translationService
        ->getConfigSourceData($mapper);
      $data['_debug'] = [
        'title' => trim($mapper
          ->getPluginId() . ' (config): ' . $mapper
          ->getTitle()),
        'profile' => $profile ? $profile
          ->id() : '<null>',
        'source_locale' => $this->translationService
          ->getConfigSourceLocale($mapper),
      ];
      $filename = 'config.' . $mapper
        ->getPluginId() . '.json';
      $plugin_definition = $mapper
        ->getPluginDefinition();
      if (isset($plugin_definition['entity_type']) && 'field_config' === $plugin_definition['entity_type']) {
        $entity = $mapper
          ->getEntity();
        $data['_debug']['title'] = $entity
          ->id() . ' (config): ' . $entity
          ->label();
        $filename = 'config.' . $entity
          ->id() . '.json';
      }
      $source_data = json_encode($data);
      $file = File::create([
        'uid' => 1,
        'filename' => $filename,
        'uri' => 'public://' . $filename,
        'filemime' => 'text/plain',
        'created' => REQUEST_TIME,
        'changed' => REQUEST_TIME,
      ]);
      file_put_contents($file
        ->getFileUri(), $source_data);
      $file
        ->save();
      $context['results']['exported'][] = $file
        ->id();
    }
    else {
      drupal_set_message($this
        ->t('The %label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Upload source for translation.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   */
  public function uploadDocument(ConfigMapperInterface $mapper, $language, &$context) {
    $context['message'] = $this
      ->t('Uploading %label.', [
      '%label' => $mapper
        ->getTitle(),
    ]);

    /** @var ConfigEntityInterface $entity */
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);
    $document_id = $mapper instanceof ConfigEntityMapper ? $this->translationService
      ->getDocumentId($entity) : $this->translationService
      ->getConfigDocumentId($mapper);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      if ($mapper instanceof ConfigEntityMapper) {
        try {
          $this->translationService
            ->uploadDocument($entity);
        } catch (LingotekApiException $e) {
          $this->translationService
            ->setSourceStatus($entity, Lingotek::STATUS_ERROR);
          if ($document_id) {
            drupal_set_message($this
              ->t('%label update failed. Please try again.', [
              '%label' => $entity
                ->label(),
            ]), 'error');
          }
          else {
            drupal_set_message($this
              ->t('%label upload failed. Please try again.', [
              '%label' => $entity
                ->label(),
            ]), 'error');
          }
        }
      }
      else {
        try {
          $this->translationService
            ->uploadConfig($mapper
            ->getPluginId());
        } catch (LingotekApiException $e) {
          $this->translationService
            ->setConfigSourceStatus($mapper, Lingotek::STATUS_ERROR);
          if ($document_id) {
            drupal_set_message($this
              ->t('%label update failed. Please try again.', [
              '%label' => $mapper
                ->getTitle(),
            ]), 'error');
          }
          else {
            drupal_set_message($this
              ->t('%label upload failed. Please try again.', [
              '%label' => $mapper
                ->getTitle(),
            ]), 'error');
          }
        }
      }
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Check document upload status for a given content.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   */
  public function checkDocumentUploadStatus(ConfigMapperInterface $mapper, $language, &$context) {
    $context['message'] = $this
      ->t('Checking status of %label.', [
      '%label' => $mapper
        ->getTitle(),
    ]);
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      if ($mapper instanceof ConfigEntityMapper) {
        try {
          $this->translationService
            ->checkSourceStatus($entity);
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label upload failed. Please try again.', [
            '%label' => $entity
              ->label(),
          ]), 'error');
        }
      }
      else {
        try {
          $this->translationService
            ->checkConfigSourceStatus($mapper
            ->getPluginId());
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label upload failed. Please try again.', [
            '%label' => $mapper
              ->getTitle(),
          ]), 'error');
        }
      }
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Request all translations for a given content.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   */
  public function requestTranslations(ConfigMapperInterface $mapper, $language, &$context) {
    $result = NULL;
    $context['message'] = $this
      ->t('Requesting translations for %label.', [
      '%label' => $mapper
        ->getTitle(),
    ]);
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      if ($mapper instanceof ConfigEntityMapper) {
        try {
          $result = $this->translationService
            ->requestTranslations($entity);
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label translations request failed. Please try again.', [
            '%label' => $entity
              ->label(),
          ]), 'error');
        }
      }
      else {
        try {
          $result = $this->translationService
            ->requestConfigTranslations($mapper
            ->getPluginId());
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label translations request failed. Please try again.', [
            '%label' => $mapper
              ->getTitle(),
          ]), 'error');
        }
      }
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
    return $result;
  }

  /**
   * Checks all translations statuses for a given content.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   */
  public function checkTranslationStatuses(ConfigMapperInterface $mapper, $language, &$context) {
    $context['message'] = $this
      ->t('Checking translation status for %label.', [
      '%label' => $mapper
        ->getTitle(),
    ]);
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      if ($mapper instanceof ConfigEntityMapper) {
        try {
          $this->translationService
            ->checkTargetStatuses($entity);
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label translation statuses check failed. Please try again.', [
            '%label' => $entity
              ->label(),
          ]), 'error');
        }
      }
      else {
        try {
          $this->translationService
            ->checkConfigTargetStatuses($mapper
            ->getPluginId());
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label translation statuses check failed. Please try again.', [
            '%label' => $mapper
              ->getTitle(),
          ]), 'error');
        }
      }
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Checks translation status for a given content in a given language.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   * @param string $langcode
   *   The language to check.
   */
  public function checkTranslationStatus(ConfigMapperInterface $mapper, $langcode, &$context) {
    $context['message'] = $this
      ->t('Checking translation status for %label to language @language.', [
      '%label' => $mapper
        ->getTitle(),
      '@language' => $langcode,
    ]);
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);
    $locale = $this->languageLocaleMapper
      ->getLocaleForLangcode($langcode);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      if ($mapper instanceof ConfigEntityMapper) {
        try {
          $this->translationService
            ->checkTargetStatus($entity, $locale);
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label @locale translation status check failed. Please try again.', [
            '%label' => $entity
              ->label(),
            '@locale' => $locale,
          ]), 'error');
        }
      }
      else {
        try {
          $this->translationService
            ->checkConfigTargetStatus($mapper
            ->getPluginId(), $locale);
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label @locale translation status check failed. Please try again.', [
            '%label' => $mapper
              ->getTitle(),
            '@locale' => $locale,
          ]), 'error');
        }
      }
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Request translations for a given content in a given language.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   * @param string $langcode
   *   The language to download.
   */
  public function requestTranslation(ConfigMapperInterface $mapper, $langcode, &$context) {
    $context['message'] = $this
      ->t('Requesting translation for %label to language @language.', [
      '%label' => $mapper
        ->getTitle(),
      '@language' => $langcode,
    ]);
    $locale = $this->languageLocaleMapper
      ->getLocaleForLangcode($langcode);
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      if ($mapper instanceof ConfigEntityMapper) {
        try {
          $this->translationService
            ->addTarget($entity, $locale);
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label @locale translation request failed. Please try again.', [
            '%label' => $entity
              ->label(),
            '@locale' => $locale,
          ]), 'error');
        }
      }
      else {
        try {
          $this->translationService
            ->addConfigTarget($mapper
            ->getPluginId(), $locale);
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label @locale translation request failed. Please try again.', [
            '%label' => $mapper
              ->getTitle(),
            '@locale' => $locale,
          ]), 'error');
        }
      }
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Download translation for a given content in a given language.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   * @param string $langcode
   *   The language to download.
   */
  public function downloadTranslation(ConfigMapperInterface $mapper, $langcode, &$context) {
    $context['message'] = $this
      ->t('Downloading translation for %label in language @language.', [
      '%label' => $mapper
        ->getTitle(),
      '@language' => $langcode,
    ]);
    $locale = $this->languageLocaleMapper
      ->getLocaleForLangcode($langcode);
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      $this
        ->performTranslationDownload($mapper, $entity, $locale);
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Download translations for a given content in all enabled languages.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   */
  public function downloadTranslations(ConfigMapperInterface $mapper, $langcode, &$context) {
    $context['message'] = $this
      ->t('Downloading all translations for %label.', [
      '%label' => $mapper
        ->getTitle(),
    ]);
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      $languages = $this->languageManager
        ->getLanguages();
      foreach ($languages as $langcode => $language) {
        if ($langcode !== $mapper
          ->getLangcode()) {
          $locale = $this->languageLocaleMapper
            ->getLocaleForLangcode($langcode);
          $this
            ->performTranslationDownload($mapper, $entity, $locale);
        }
      }
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Disassociate the content from Lingotek.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   */
  public function disassociate(ConfigMapperInterface $mapper, $langcode, &$context) {
    $context['message'] = $this
      ->t('Disassociating all translations for %label.', [
      '%label' => $mapper
        ->getTitle(),
    ]);
    $entity = $mapper instanceof ConfigEntityMapper ? $mapper
      ->getEntity() : NULL;
    $profile = $mapper instanceof ConfigEntityMapper ? $this->lingotekConfiguration
      ->getConfigEntityProfile($entity, FALSE) : $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE);

    // If there is no entity, it's a config object and we don't abort based on
    // the profile.
    if ($entity === NULL || $profile !== NULL) {
      if ($mapper instanceof ConfigEntityMapper) {
        try {
          $this->translationService
            ->deleteMetadata($entity);
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label deletion failed. Please try again.', [
            '%label' => $entity
              ->label(),
          ]), 'error');
        }
      }
      else {
        try {
          $this->translationService
            ->deleteConfigMetadata($mapper
            ->getPluginId());
        } catch (LingotekApiException $e) {
          drupal_set_message($this
            ->t('%label deletion failed. Please try again.', [
            '%label' => $mapper
              ->getTitle(),
          ]), 'error');
        }
      }
    }
    elseif ($profile = $this->lingotekConfiguration
      ->getConfigProfile($mapper
      ->getPluginId(), FALSE) or TRUE) {
      try {
        $this->translationService
          ->deleteConfigMetadata($mapper
          ->getPluginId());
      } catch (LingotekApiException $e) {
        drupal_set_message($this
          ->t('%label deletion failed. Please try again.', [
          '%label' => $mapper
            ->getTitle(),
        ]), 'error');
      }
    }
    else {
      drupal_set_message($this
        ->t('%label has no profile assigned so it was not processed.', [
        '%label' => $mapper
          ->getTitle(),
      ]), 'warning');
    }
  }

  /**
   * Gets the source status of an config in a format ready to display.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   *
   * @return array
   *   A render array.
   */
  protected function getSourceStatus(ConfigMapperInterface $mapper) {
    $is_config_entity = $mapper instanceof ConfigEntityMapper;
    $entity = $is_config_entity ? $mapper
      ->getEntity() : NULL;
    $language_source = $this->languageLocaleMapper
      ->getConfigurableLanguageForLocale($is_config_entity ? $this->translationService
      ->getSourceLocale($entity) : $this->translationService
      ->getConfigSourceLocale($mapper));
    $source_status = $is_config_entity ? $this->translationService
      ->getSourceStatus($entity) : $this->translationService
      ->getConfigSourceStatus($mapper);
    $data = array(
      'data' => array(
        '#type' => 'inline_template',
        '#template' => '<span class="language-icon source-{{status}}" title="{{status_title}}">{% if url %}<a href="{{url}}">{%endif%}{{language}}{%if url %}</a>{%endif%}</span>',
        '#context' => array(
          'language' => strtoupper($language_source
            ->id()),
          'status' => strtolower($source_status),
          'status_title' => $this
            ->getSourceStatusText($mapper, $source_status),
          'url' => $this
            ->getSourceActionUrl($mapper, $source_status),
        ),
      ),
    );
    if ($source_status == Lingotek::STATUS_EDITED && !$this->translationService
      ->getConfigDocumentId($mapper)) {
      $data['data']['#context']['status'] = strtolower(Lingotek::STATUS_REQUEST);
    }
    return $data;
  }
  protected function getSourceStatusText(ConfigMapperInterface $mapper, $status) {
    $is_config_entity = $mapper instanceof ConfigEntityMapper;
    $entity = $is_config_entity ? $mapper
      ->getEntity() : NULL;
    switch ($status) {
      case Lingotek::STATUS_UNTRACKED:
      case Lingotek::STATUS_REQUEST:
        return $this
          ->t('Upload');
      case Lingotek::STATUS_DISABLED:
        return $this
          ->t('Disabled, cannot request translation');
      case Lingotek::STATUS_EDITED:
        return $is_config_entity ? $this->translationService
          ->getDocumentId($entity) : $this->translationService
          ->getConfigDocumentId($mapper) ? $this
          ->t('Re-upload (content has changed since last upload)') : $this
          ->t('Upload');
      case Lingotek::STATUS_IMPORTING:
        return $this
          ->t('Source importing');
      case Lingotek::STATUS_CURRENT:
        return $this
          ->t('Source uploaded');
      case Lingotek::STATUS_ERROR:
        return $this
          ->t('Error');
      default:
        return ucfirst(strtolower($status));
    }
  }
  protected function getTargetStatusText(ConfigMapperInterface $mapper, $status, $langcode) {
    $language = ConfigurableLanguage::load($langcode);
    if ($language) {
      switch ($status) {
        case Lingotek::STATUS_UNTRACKED:
          return $language
            ->label() . ' - ' . $this
            ->t('Translation exists, but it is not being tracked by Lingotek');
        case Lingotek::STATUS_REQUEST:
          return $language
            ->label() . ' - ' . $this
            ->t('Request translation');
        case Lingotek::STATUS_PENDING:
          return $language
            ->label() . ' - ' . $this
            ->t('In-progress');
        case Lingotek::STATUS_READY:
          return $language
            ->label() . ' - ' . $this
            ->t('Ready for Download');
        case Lingotek::STATUS_CURRENT:
          return $language
            ->label() . ' - ' . $this
            ->t('Current');
        case Lingotek::STATUS_EDITED:
          return $language
            ->label() . ' - ' . $this
            ->t('Not current');
        case Lingotek::STATUS_INTERMEDIATE:
          return $language
            ->label() . ' - ' . $this
            ->t('In-progress (interim translation downloaded)');
        default:
          return $language
            ->label() . ' - ' . ucfirst(strtolower($status));
      }
    }
  }

  /**
   * Gets the translation status of an entity in a format ready to display.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   *
   * @return array
   *   A render array.
   */
  protected function getTranslationsStatuses(ConfigMapperInterface &$mapper) {
    $is_config_entity = $mapper instanceof ConfigEntityMapper;
    $translations = [];
    $languages = $this->languageManager
      ->getLanguages();
    $languages = array_filter($languages, function (LanguageInterface $language) {
      $configLanguage = ConfigurableLanguage::load($language
        ->getId());
      return $this->lingotekConfiguration
        ->isLanguageEnabled($configLanguage);
    });
    $document_id = $is_config_entity ? $this->translationService
      ->getDocumentId($mapper
      ->getEntity()) : $this->translationService
      ->getConfigDocumentId($mapper);
    $entity = $is_config_entity ? $mapper
      ->getEntity() : NULL;
    if ($document_id) {
      $translations_statuses = $mapper instanceof ConfigEntityMapper ? $this->translationService
        ->getTargetStatuses($entity) : $this->translationService
        ->getConfigTargetStatuses($mapper);
      foreach ($translations_statuses as $langcode => $status) {
        if (isset($languages[$langcode]) && $langcode !== $mapper
          ->getLangcode() && key_exists($langcode, $languages)) {
          if ($mapper
            ->hasTranslation($languages[$langcode]) && $status == Lingotek::STATUS_REQUEST) {
            $translations[$langcode] = [
              'status' => Lingotek::STATUS_UNTRACKED,
              'url' => $this
                ->getTargetActionUrl($mapper, Lingotek::STATUS_UNTRACKED, $langcode),
              'new_window' => $status == Lingotek::STATUS_CURRENT,
            ];
          }
          else {
            $translations[$langcode] = [
              'status' => $status,
              'url' => $this
                ->getTargetActionUrl($mapper, $status, $langcode),
              'new_window' => $status == Lingotek::STATUS_CURRENT,
            ];
          }
        }
      }
      array_walk($languages, function ($language, $langcode) use ($mapper, &$translations) {
        if (!isset($translations[$langcode]) && $langcode !== $mapper
          ->getLangcode()) {
          $translations[$langcode] = [
            'status' => Lingotek::STATUS_REQUEST,
            'url' => $this
              ->getTargetActionUrl($mapper, Lingotek::STATUS_REQUEST, $langcode),
            'new_window' => false,
          ];
        }
      });
    }
    else {
      foreach ($languages as $langcode => $language) {

        // Show the untracked translations in the bulk management form, unless it's the
        // source one.
        if ($mapper
          ->hasTranslation($language) && $mapper
          ->getLangcode() !== $langcode) {
          $translations[$langcode] = [
            'status' => Lingotek::STATUS_UNTRACKED,
            'url' => NULL,
            'new_window' => false,
          ];
        }
      }
    }
    ksort($translations);
    return $this
      ->formatTranslations($mapper, $translations);
  }

  /**
   * Formats the translation statuses for display.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   * @param array $translations
   *   Pairs of language - status.
   *
   * @return array
   *   A render array.
   */
  protected function formatTranslations(ConfigMapperInterface $mapper, array $translations) {
    $languages = [];
    foreach ($translations as $langcode => $data) {
      if ($this->languageManager
        ->getLanguage($langcode)) {
        $languages[] = [
          'language' => strtoupper($langcode),
          'status' => strtolower($data['status']),
          'status_text' => $this
            ->getTargetStatusText($mapper, $data['status'], $langcode),
          'url' => $data['url'],
          'new_window' => $data['new_window'],
        ];
      }
    }
    return array(
      'data' => array(
        '#type' => 'inline_template',
        '#template' => '{% for language in languages %}{% if language.url %}<a href="{{ language.url }}" {%if language.new_window%}target="_blank"{%endif%}{%else%}<span {%endif%} class="language-icon target-{{language.status}}" title="{{language.status_text}}">{{language.language}}{%if language.url%}</a>{%else%}</span>{%endif%}{% endfor %}',
        '#context' => array(
          'languages' => $languages,
        ),
      ),
    );
  }

  /**
   * Gets all the languages as options.
   *
   * @return array
   *   The languages as a valid options array.
   */
  protected function getAllLanguages() {
    $languages = $this->languageManager
      ->getLanguages();
    $options = [];
    foreach ($languages as $id => $language) {
      $options[$id] = $language
        ->getName();
    }
    return $options;
  }

  /**
   * Get the bulk operations for the management form.
   *
   * @return array
   *   Array with the bulk operations.
   */
  public function generateBulkOptions() {
    $operations = [];
    $operations['upload'] = $this
      ->t('Upload source for translation');
    $operations['check_upload'] = $this
      ->t('Check upload progress');
    $operations[(string) $this
      ->t('Request translations')]['request_translations'] = $this
      ->t('Request all translations');
    $operations[(string) $this
      ->t('Check translation progress')]['check_translations'] = $this
      ->t('Check progress of all translations');
    $operations[(string) $this
      ->t('Download')]['download'] = $this
      ->t('Download all translations');
    $operations['disassociate'] = $this
      ->t('Disassociate content');
    foreach ($this->languageManager
      ->getLanguages() as $langcode => $language) {
      $operations[(string) $this
        ->t('Request translations')]['request_translation:' . $langcode] = $this
        ->t('Request @language translation', [
        '@language' => $language
          ->getName() . ' (' . $language
          ->getId() . ')',
      ]);
      $operations[(string) $this
        ->t('Check translation progress')]['check_translation:' . $langcode] = $this
        ->t('Check progress of @language translation', [
        '@language' => $language
          ->getName() . ' (' . $language
          ->getId() . ')',
      ]);
      $operations[(string) $this
        ->t('Download')]['download:' . $langcode] = $this
        ->t('Download @language translation', [
        '@language' => $language
          ->getName(),
      ]);
    }
    $debug_enabled = \Drupal::state()
      ->get('lingotek.enable_debug_utilities', FALSE);
    if ($debug_enabled) {
      $operations['debug']['debug.export'] = $this
        ->t('Debug: Export sources as JSON');
    }
    return $operations;
  }
  protected function getActionUrlArguments(ConfigMapperInterface &$mapper) {
    $args = [
      'entity_type' => $mapper
        ->getPluginId(),
      'entity_id' => $mapper
        ->getPluginId(),
    ];
    if ($mapper instanceof ConfigEntityMapper && !$mapper instanceof ConfigFieldMapper) {
      $args['entity_id'] = $mapper
        ->getEntity()
        ->id();
    }
    else {
      if ($mapper instanceof ConfigFieldMapper) {
        $args['entity_type'] = $mapper
          ->getType();
        $args['entity_id'] = $mapper
          ->getEntity()
          ->id();
      }
    }
    return $args;
  }

  /**
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper.
   * @param String $source_status
   *
   * @return \Drupal\Core\Url
   */
  protected function getSourceActionUrl(ConfigMapperInterface &$mapper, $source_status) {
    $url = NULL;
    $args = $this
      ->getActionUrlArguments($mapper);
    $document_id = $mapper instanceof ConfigEntityMapper ? $this->translationService
      ->getDocumentId($mapper
      ->getEntity()) : $this->translationService
      ->getConfigDocumentId($mapper);
    if ($source_status == Lingotek::STATUS_IMPORTING) {
      $url = Url::fromRoute('lingotek.config.check_upload', $args, [
        'query' => $this
          ->getDestinationArray(),
      ]);
    }
    if ($source_status == Lingotek::STATUS_EDITED || $source_status == Lingotek::STATUS_UNTRACKED || $source_status == Lingotek::STATUS_ERROR) {
      if ($document_id) {
        $url = Url::fromRoute('lingotek.config.update', $args, [
          'query' => $this
            ->getDestinationArray(),
        ]);
      }
      else {
        $url = Url::fromRoute('lingotek.config.upload', $args, [
          'query' => $this
            ->getDestinationArray(),
        ]);
      }
    }
    return $url;
  }
  protected function getTargetActionUrl(ConfigMapperInterface &$mapper, $target_status, $langcode) {
    $url = NULL;
    $args = $this
      ->getActionUrlArguments($mapper);
    $document_id = $mapper instanceof ConfigEntityMapper ? $this->translationService
      ->getDocumentId($mapper
      ->getEntity()) : $this->translationService
      ->getConfigDocumentId($mapper);
    $locale = $this->languageLocaleMapper
      ->getLocaleForLangcode($langcode);
    if ($locale) {
      if ($target_status == Lingotek::STATUS_REQUEST || $target_status == Lingotek::STATUS_UNTRACKED) {
        $url = Url::fromRoute('lingotek.config.request', $args + [
          'locale' => $locale,
        ], [
          'query' => $this
            ->getDestinationArray(),
        ]);
      }
      if ($target_status == Lingotek::STATUS_PENDING) {
        $url = Url::fromRoute('lingotek.config.check_download', $args + [
          'locale' => $locale,
        ], [
          'query' => $this
            ->getDestinationArray(),
        ]);
      }
      if ($target_status == Lingotek::STATUS_READY) {
        $url = Url::fromRoute('lingotek.config.download', $args + [
          'locale' => $locale,
        ], [
          'query' => $this
            ->getDestinationArray(),
        ]);
      }
      if ($target_status == Lingotek::STATUS_CURRENT || $target_status == Lingotek::STATUS_INTERMEDIATE || $target_status == Lingotek::STATUS_EDITED) {
        $url = Url::fromRoute('lingotek.workbench', [
          'doc_id' => $document_id,
          'locale' => $locale,
        ]);
      }
    }
    return $url;
  }

  /**
   * Generates an array of operations to be performed in a batch.
   *
   * @param string $operation
   *   The operation (method of this object) to be executed.
   * @param array $values
   *   The mappers this operation will be applied to.
   * @param $language
   *   The language to be passed to that operation.
   * @return array
   *   An array of operations suitable for a batch.
   */
  protected function generateOperations($operation, $values, $language) {
    $operations = [];
    $mappers = [];
    if ($this->filter === 'config') {
      foreach ($values as $value) {
        $mappers[$value] = $this->mappers[$value];
      }
    }
    elseif (substr($this->filter, -7) == '_fields') {
      $mapper = $this->mappers[$this->filter];
      $ids = \Drupal::entityQuery('field_config')
        ->condition('id', $values)
        ->execute();
      $fields = FieldConfig::loadMultiple($ids);
      $mappers = [];
      foreach ($fields as $id => $field) {
        $new_mapper = clone $mapper;
        $new_mapper
          ->setEntity($field);
        $mappers[$field
          ->id()] = $new_mapper;
      }
    }
    else {
      $entities = \Drupal::entityManager()
        ->getStorage($this->filter)
        ->loadMultiple($values);
      foreach ($entities as $entity) {
        $mapper = clone $this->mappers[$this->filter];
        $mapper
          ->setEntity($entity);
        $mappers[$entity
          ->id()] = $mapper;
      }
    }
    foreach ($mappers as $mapper) {
      $operations[] = [
        [
          $this,
          $operation,
        ],
        [
          $mapper,
          $language,
        ],
      ];
    }
    return $operations;
  }

  /**
   * Actually performs the translation download.
   *
   * @param \Drupal\config_translation\ConfigMapperInterface $mapper
   *   The mapper to be used.
   * @param $entity
   *   The entity (in case it is a config entity mapper).
   * @param $locale
   *   The locale to be downloaded.
   */
  protected function performTranslationDownload(ConfigMapperInterface $mapper, $entity, $locale) {
    if ($mapper instanceof ConfigEntityMapper) {
      try {
        $this->translationService
          ->downloadDocument($entity, $locale);
      } catch (LingotekApiException $e) {
        drupal_set_message($this
          ->t('%label @locale translation download failed. Please try again.', [
          '%label' => $entity
            ->label(),
          '@locale' => $locale,
        ]), 'error');
      }
    }
    else {
      try {
        $this->translationService
          ->downloadConfig($mapper
          ->getPluginId(), $locale);
      } catch (LingotekApiException $e) {
        drupal_set_message($this
          ->t('%label @locale translation download failed. Please try again.', [
          '%label' => $mapper
            ->getTitle(),
          '@locale' => $locale,
        ]), 'error');
      }
    }
  }

}

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.
FormBase::validateForm public function Form validation handler. Overrides FormInterface::validateForm 62
LingotekConfigManagementForm::$filter protected property The type of config to display.
LingotekConfigManagementForm::$languageLocaleMapper protected property The language-locale mapper.
LingotekConfigManagementForm::$languageManager protected property The language manager.
LingotekConfigManagementForm::$lingotekConfiguration protected property The Lingotek configuration service.
LingotekConfigManagementForm::$mappers protected property A array of configuration mapper instances.
LingotekConfigManagementForm::$tempStoreFactory protected property The tempstore factory.
LingotekConfigManagementForm::$translationService protected property The Lingotek content translation service.
LingotekConfigManagementForm::batchFinished public function
LingotekConfigManagementForm::buildForm public function Form constructor. Overrides FormInterface::buildForm
LingotekConfigManagementForm::checkDocumentUploadStatus public function Check document upload status for a given content.
LingotekConfigManagementForm::checkTranslationStatus public function Checks translation status for a given content in a given language.
LingotekConfigManagementForm::checkTranslationStatuses public function Checks all translations statuses for a given content.
LingotekConfigManagementForm::create public static function Instantiates a new instance of this class. Overrides FormBase::create
LingotekConfigManagementForm::createBatch protected function Performs an operation to several values in a batch.
LingotekConfigManagementForm::createDebugExportBatch protected function Create and set an export batch.
LingotekConfigManagementForm::createDisassociateBatch protected function Create and set a disassociate batch.
LingotekConfigManagementForm::createDownloadBatch protected function Create and set a request target and download batch for all languages.
LingotekConfigManagementForm::createLanguageDownloadBatch protected function Create and set a request target and download batch for a given language.
LingotekConfigManagementForm::createLanguageRequestTranslationBatch protected function Create and set a request translations batch for all languages.
LingotekConfigManagementForm::createLanguageTranslationCheckStatusBatch protected function Create and set a check translation status batch for a given language.
LingotekConfigManagementForm::createRequestTranslationsBatch protected function Create and set a request translations batch for all languages.
LingotekConfigManagementForm::createTranslationCheckStatusBatch protected function Create and set a check translation status batch for all languages.
LingotekConfigManagementForm::createUploadBatch protected function Create and set an upload batch.
LingotekConfigManagementForm::createUploadCheckStatusBatch protected function Create and set a check upload status batch.
LingotekConfigManagementForm::debugExport public function Export source for debugging purposes.
LingotekConfigManagementForm::debugExportFinished public function
LingotekConfigManagementForm::disassociate public function Disassociate the content from Lingotek.
LingotekConfigManagementForm::downloadTranslation public function Download translation for a given content in a given language.
LingotekConfigManagementForm::downloadTranslations public function Download translations for a given content in all enabled languages.
LingotekConfigManagementForm::filterForm public function Form submission handler for filtering.
LingotekConfigManagementForm::formatTranslations protected function Formats the translation statuses for display.
LingotekConfigManagementForm::generateBulkOptions public function Get the bulk operations for the management form.
LingotekConfigManagementForm::generateOperations protected function Generates an array of operations to be performed in a batch.
LingotekConfigManagementForm::getActionUrlArguments protected function
LingotekConfigManagementForm::getAllBundles protected function
LingotekConfigManagementForm::getAllLanguages protected function Gets all the languages as options.
LingotekConfigManagementForm::getFilter protected function Gets the filter to be applied. By default will be 'config'.
LingotekConfigManagementForm::getFormId public function Returns a unique string identifying the form. Overrides FormInterface::getFormId
LingotekConfigManagementForm::getSourceActionUrl protected function
LingotekConfigManagementForm::getSourceStatus protected function Gets the source status of an config in a format ready to display.
LingotekConfigManagementForm::getSourceStatusText protected function
LingotekConfigManagementForm::getTargetActionUrl protected function
LingotekConfigManagementForm::getTargetStatusText protected function
LingotekConfigManagementForm::getTranslationsStatuses protected function Gets the translation status of an entity in a format ready to display.
LingotekConfigManagementForm::performTranslationDownload protected function Actually performs the translation download.
LingotekConfigManagementForm::requestTranslation public function Request translations for a given content in a given language.
LingotekConfigManagementForm::requestTranslations public function Request all translations for a given content.
LingotekConfigManagementForm::submitForm public function Form submission handler. Overrides FormInterface::submitForm
LingotekConfigManagementForm::uploadDocument public function Upload source for translation.
LingotekConfigManagementForm::__construct public function Constructs a new LingotekManagementForm object.
LingotekSetupTrait::$lingotek protected property A lingotek connector object
LingotekSetupTrait::checkSetup protected function Verify the Lingotek Translation module has been properly initialized.
LingotekSetupTrait::setupCompleted public function Checks if Lingotek module is completely set up.
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.
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.