public function testOverview()
 {
     $this->loginAsTranslator();
     $this->drupalGet('admin/tmgmt/sources/locale/default');
     $this->assertText('Hello World');
     $this->assertText('Example');
     $rows = $this->xpath('//tbody/tr');
     foreach ($rows as $row) {
         if ($row->td[1] == 'Hello World') {
             $this->assertEqual((string) $row->td[3]->img['title'], t('Translation up to date'));
             $this->assertEqual((string) $row->td[4]->img['title'], t('Not translated'));
         }
     }
     // Filter on the label.
     $edit = array('search[label]' => 'Hello');
     $this->drupalPostForm(NULL, $edit, t('Search'));
     $this->assertText('Hello World');
     $this->assertNoText('Example');
     $locale_object = db_query('SELECT * FROM {locales_source} WHERE source = :source LIMIT 1', array(':source' => 'Hello World'))->fetchObject();
     // First add source to the cart to test its functionality.
     $edit = array('items[' . $locale_object->lid . ']' => TRUE);
     $this->drupalPostForm(NULL, $edit, t('Add to cart'));
     $this->assertRaw(t('@count content source was added into the <a href=":url">cart</a>.', array('@count' => 1, ':url' => \Drupal::url('tmgmt.cart'))));
     $edit['target_language[]'] = array('gsw-berne');
     $this->drupalPostForm('admin/tmgmt/cart', $edit, t('Request translation'));
     // Assert that the job item is displayed.
     $this->assertText('Hello World');
     $this->assertText(t('Locale'));
     $this->assertText('2');
     $this->drupalPostForm(NULL, array('target_language' => 'gsw-berne'), t('Submit to provider'));
     // Test for the translation flag title.
     $this->drupalGet('admin/tmgmt/sources/locale/default');
     $this->assertRaw(t('Active job item: Needs review'));
     // Review and accept the job item.
     $job_items = tmgmt_job_item_load_latest('locale', 'default', $locale_object->lid, 'en');
     $this->drupalGet('admin/tmgmt/items/' . $job_items['gsw-berne']->id());
     $this->assertRaw('gsw-berne: Hello World');
     $this->drupalPostForm(NULL, array(), t('Save as completed'));
     $this->drupalGet('admin/tmgmt/sources/locale/default');
     $this->assertNoRaw(t('Active job item: Needs review'));
     $rows = $this->xpath('//tbody/tr');
     foreach ($rows as $row) {
         if ($row->td[1] == 'Hello World') {
             $this->assertEqual((string) $row->td[3]->img['title'], t('Translation up to date'));
             $this->assertEqual((string) $row->td[4]->img['title'], t('Translation up to date'));
         }
     }
     // Test the missing translation filter.
     $this->drupalGet('admin/tmgmt/sources/locale/default');
     // Check that the source language (en) has been removed from the target language
     // select box.
     $elements = $this->xpath('//select[@name=:name]//option[@value=:option]', array(':name' => 'search[target_language]', ':option' => 'en'));
     $this->assertTrue(empty($elements));
     // Filter on the "Not translated to".
     $edit = array('search[missing_target_language]' => 'gsw-berne');
     $this->drupalPostForm(NULL, $edit, t('Search'));
     // Hello world is translated to "gsw-berne" therefore it must not show up
     // in the list.
     $this->assertNoText('Hello World');
 }
 /**
  * {@inheritdoc}
  */
 function buildForm(array $form, FormStateInterface $form_state, array $build = NULL)
 {
     // Store the entity in the form state so we can easily create the job in the
     // submit handler.
     $form_state->set('entity', $build['#entity']);
     $overview = $build['content_translation_overview'];
     $form['#title'] = $this->t('Translations of @title', array('@title' => $build['#entity']->label()));
     $form['actions'] = array('#type' => 'details', '#title' => t('Operations'), '#open' => TRUE, '#attributes' => array('class' => array('tmgmt-source-operations-wrapper')));
     $form['actions']['request'] = array('#type' => 'submit', '#button_type' => 'primary', '#value' => $this->t('Request translation'), '#submit' => array('::submitForm'));
     tmgmt_add_cart_form($form['actions'], $form_state, 'content', $form_state->get('entity')->getEntityTypeId(), $form_state->get('entity')->id());
     // Inject our additional column into the header.
     array_splice($overview['#header'], -1, 0, array(t('Pending Translations')));
     // Make this a tableselect form.
     $form['languages'] = array('#type' => 'tableselect', '#header' => $overview['#header'], '#options' => array());
     $languages = \Drupal::languageManager()->getLanguages();
     // Check if there is a job / job item that references this translation.
     $entity_langcode = $form_state->get('entity')->language()->getId();
     $items = tmgmt_job_item_load_latest('content', $form_state->get('entity')->getEntityTypeId(), $form_state->get('entity')->id(), $entity_langcode);
     foreach ($languages as $langcode => $language) {
         if ($langcode == LanguageInterface::LANGCODE_DEFAULT) {
             // Never show language neutral on the overview.
             continue;
         }
         // Since the keys are numeric and in the same order we can shift one element
         // after the other from the original non-form rows.
         $option = array_shift($overview['#rows']);
         if ($langcode == $entity_langcode) {
             $additional = array('data' => array('#markup' => '<strong>' . t('Source') . '</strong>'));
             // This is the source object so we disable the checkbox for this row.
             $form['languages'][$langcode] = array('#type' => 'checkbox', '#disabled' => TRUE);
         } elseif (isset($items[$langcode])) {
             $item = $items[$langcode];
             $states = JobItem::getStates();
             $path = \Drupal::routeMatch()->getRouteName() ? Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath() : '';
             $destination = array('destination' => $path);
             $additional = \Drupal::l($states[$item->getState()], $item->urlInfo()->setOption('query', $destination));
             // Disable the checkbox for this row since there is already a translation
             // in progress that has not yet been finished. This way we make sure that
             // we don't stack multiple active translations for the same item on top
             // of each other.
             $form['languages'][$langcode] = array('#type' => 'checkbox', '#disabled' => TRUE);
         } else {
             // There is no translation job / job item for this target language.
             $additional = t('None');
         }
         // Inject the additional column into the array.
         // The generated form structure has changed, support both an additional
         // 'data' key (that is not supported by tableselect) and the old version
         // without.
         if (isset($option['data'])) {
             array_splice($option['data'], -1, 0, array($additional));
             // Append the current option array to the form.
             $form['languages']['#options'][$langcode] = $option['data'];
         } else {
             array_splice($option, -1, 0, array($additional));
             // Append the current option array to the form.
             $form['languages']['#options'][$langcode] = $option;
         }
     }
     return $form;
 }
 /**
  * Builds a table row for simple configuration.
  *
  * @param array $definition
  *   A definition.
  *
  * @return array
  *   A single table row for the overview.
  */
 public function overviewRowSimple(array $definition)
 {
     // Get current job items for the entity to determine translation statuses.
     $config_id = $definition['names'][0];
     $source_lang = \Drupal::config($definition['names'][0])->get('langcode') ?: 'en';
     $current_job_items = tmgmt_job_item_load_latest('config', ConfigSource::SIMPLE_CONFIG, $definition['id'], $source_lang);
     $row = array('id' => $definition['id'], 'title' => $definition['title']);
     // Load entity translation specific data.
     foreach (\Drupal::languageManager()->getLanguages() as $langcode => $language) {
         $translation_status = 'current';
         if ($langcode == $source_lang) {
             $translation_status = 'original';
         } elseif (!$this->isTranslated($langcode, $config_id)) {
             $translation_status = 'missing';
         }
         // @todo Find a way to support marking configuration translations as outdated.
         $build = $this->buildTranslationStatus($translation_status, isset($current_job_items[$langcode]) ? $current_job_items[$langcode] : NULL);
         $row['langcode-' . $langcode] = ['data' => \Drupal::service('renderer')->render($build), 'class' => array('langstatus-' . $langcode)];
     }
     return $row;
 }
 /**
  * Helper function to create translation data list for the sources page list.
  *
  * @param array $strings
  *   Result of the search query returned by tmgmt_i18n_string_get_strings().
  * @param string $type
  *   I18n object type.
  *
  * @return array
  *   Structured array with translation data.
  */
 protected function getTranslationData($strings, $type)
 {
     $objects = array();
     // Source language of locale strings is always english.
     $source_language = 'en';
     foreach ($strings as $string) {
         $id = $string->lid;
         // Get existing translations and current job items for the entity
         // to determine translation statuses
         $current_job_items = tmgmt_job_item_load_latest('locale', $type, $id, $source_language);
         $objects[$id] = array('id' => $id, 'object' => $string);
         // Load entity translation specific data.
         foreach ($this->getLanguages() as $langcode => $language) {
             $translation_status = 'current';
             if ($langcode == $source_language) {
                 $translation_status = 'original';
             } elseif ($string->{$langcode} === NULL) {
                 $translation_status = 'missing';
             }
             $objects[$id]['current_job_items'][$langcode] = isset($current_job_items[$langcode]) ? $current_job_items[$langcode] : NULL;
             $objects[$id]['translation_statuses'][$langcode] = $translation_status;
         }
     }
     return $objects;
 }
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state, array $build = NULL, $plugin_id = NULL)
 {
     // Store the entity in the form state so we can easily create the job in the
     // submit handler.
     $mapper_definition = \Drupal::service('plugin.manager.config_translation.mapper')->getDefinition($plugin_id);
     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
     $mapper = $this->configMapperManager->createInstance($plugin_id);
     $mapper->populateFromRouteMatch($this->routeMatch);
     $form_state->set('mapper', $mapper);
     if (!isset($mapper_definition['entity_type'])) {
         $form_state->set('item_type', ConfigSource::SIMPLE_CONFIG);
         $form_state->set('item_id', $mapper_definition['id']);
     } else {
         $id = $mapper->getConfigNames()[0];
         $form_state->set('id', $id);
         $form_state->set('item_type', $plugin_id);
         $form_state->set('item_id', $id);
     }
     $form['#title'] = $this->t('Translations of @title', array('@title' => $mapper->getTitle()));
     $overview = $build['languages'];
     $form['top_actions'] = array('#type' => 'details', '#title' => t('Operations'), '#open' => TRUE, '#attributes' => array('class' => array('tmgmt-source-operations-wrapper')));
     $form['top_actions']['request'] = array('#type' => 'submit', '#button_type' => 'primary', '#value' => $this->t('Request translation'), '#submit' => array('::submitForm'));
     tmgmt_add_cart_form($form['top_actions'], $form_state, 'config', $form_state->get('item_type'), $form_state->get('item_id'));
     // Inject our additional column into the header.
     array_splice($overview['#header'], -1, 0, array(t('Pending Translations')));
     // Make this a tableselect form.
     $form['languages'] = array('#type' => 'tableselect', '#header' => $overview['#header'], '#options' => array());
     $languages = \Drupal::languageManager()->getLanguages();
     // Check if there is a job / job item that references this translation.
     $items = tmgmt_job_item_load_latest('config', $form_state->get('item_type'), $form_state->get('item_id'), $mapper->getLangcode());
     foreach ($languages as $langcode => $language) {
         if ($langcode == LanguageInterface::LANGCODE_DEFAULT) {
             // Never show language neutral on the overview.
             continue;
         }
         // Since the keys are numeric and in the same order we can shift one element
         // after the other from the original non-form rows.
         $option = $overview[$langcode];
         if ($langcode == $mapper->getLangcode()) {
             $additional = array('data' => array('#markup' => '<strong>' . t('Source') . '</strong>'));
             // This is the source object so we disable the checkbox for this row.
             $form['languages'][$langcode] = array('#type' => 'checkbox', '#disabled' => TRUE);
         } elseif (isset($items[$langcode])) {
             $item = $items[$langcode];
             $states = JobItem::getStates();
             $additional = \Drupal::l($states[$item->getState()], $item->urlInfo()->setOption('query', array('destination' => Url::fromRoute('<current>')->getInternalPath())));
             // Disable the checkbox for this row since there is already a translation
             // in progress that has not yet been finished. This way we make sure that
             // we don't stack multiple active translations for the same item on top
             // of each other.
             $form['languages'][$langcode] = array('#type' => 'checkbox', '#disabled' => TRUE);
         } else {
             // There is no translation job / job item for this target language.
             $additional = t('None');
         }
         // Inject the additional column into the array.
         // The generated form structure has changed, support both an additional
         // 'data' key (that is not supported by tableselect) and the old version
         // without.
         if (isset($option['data'])) {
             array_splice($option['data'], -1, 0, array($additional));
             // Append the current option array to the form.
             $form['languages']['#options'][$langcode] = $option['data'];
         } else {
             array_splice($option, -1, 0, array($additional));
             // Append the current option array to the form.
             $form['languages']['#options'][$langcode] = array(drupal_render($option['language']), $additional, drupal_render($option['operations']));
         }
     }
     return $form;
 }
 /**
  * Builds a table row for overview form.
  *
  * @param array ContentEntityInterface $entity
  *   Data needed to build the list row.
  * @param array $bundles
  *   The array of bundles.
  *
  * @return array
  */
 public function overviewRow(ContentEntityInterface $entity, array $bundles)
 {
     $label = $entity->label() ?: $this->t('@type: @id', array('@type' => $entity->getEntityTypeId(), '@id' => $entity->id()));
     // Get existing translations and current job items for the entity
     // to determine translation statuses
     $translations = $entity->getTranslationLanguages();
     $source_lang = $entity->language()->getId();
     $current_job_items = tmgmt_job_item_load_latest('content', $entity->getEntityTypeId(), $entity->id(), $source_lang);
     $row = array('id' => $entity->id(), 'title' => $entity->hasLinkTemplate('canonical') ? $entity->toLink($label, 'canonical')->toString() : ($entity->label() ?: $entity->id()));
     if (count($bundles) > 1) {
         $row['bundle'] = isset($bundles[$entity->bundle()]) ? $bundles[$entity->bundle()] : t('Unknown');
     }
     // Load entity translation specific data.
     $manager = \Drupal::service('content_translation.manager');
     foreach (\Drupal::languageManager()->getLanguages() as $langcode => $language) {
         $translation_status = 'current';
         if ($langcode == $source_lang) {
             $translation_status = 'original';
         } elseif (!isset($translations[$langcode])) {
             $translation_status = 'missing';
         } elseif ($translation = $entity->getTranslation($langcode)) {
             $metadata = $manager->getTranslationMetadata($translation);
             if ($metadata->isOutdated()) {
                 $translation_status = 'outofdate';
             }
         }
         $build = $this->buildTranslationStatus($translation_status, isset($current_job_items[$langcode]) ? $current_job_items[$langcode] : NULL);
         $row['langcode-' . $langcode] = ['data' => \Drupal::service('renderer')->render($build), 'class' => array('langstatus-' . $langcode)];
     }
     return $row;
 }