Example #1
0
 /**
  * {@inheritdoc}
  */
 public function buildOptionsForm(&$form, FormStateInterface $form_state)
 {
     parent::buildOptionsForm($form, $form_state);
     $options = array('' => t('- All -'));
     $options += JobItem::getStates();
     $form['state'] = array('#title' => t('Job item state'), '#description' => t('Count only job items of a certain state.'), '#type' => 'select', '#options' => $options, '#default_value' => $this->options['state']);
 }
Example #2
0
 /**
  * Overrides Drupal\Core\Entity\EntityForm::form().
  */
 public function form(array $form, FormStateInterface $form_state)
 {
     $form = parent::form($form, $form_state);
     $item = $this->entity;
     $form['#title'] = $this->t('Job item @source_label', array('@source_label' => $item->getSourceLabel()));
     $form['info'] = array('#type' => 'container', '#attributes' => array('class' => array('tmgmt-ui-job-info', 'clearfix')), '#weight' => 0);
     $url = $item->getSourceUrl();
     $form['info']['source'] = array('#type' => 'item', '#title' => t('Source'), '#markup' => $url ? \Drupal::l($item->getSourceLabel(), $url) : $item->getSourceLabel(), '#prefix' => '<div class="tmgmt-ui-source tmgmt-ui-info-item">', '#suffix' => '</div>');
     $form['info']['sourcetype'] = array('#type' => 'item', '#title' => t('Source type'), '#markup' => $item->getSourceType(), '#prefix' => '<div class="tmgmt-ui-source-type tmgmt-ui-info-item">', '#suffix' => '</div>');
     $form['info']['source_language'] = array('#type' => 'item', '#title' => t('Source language'), '#markup' => $item->getJob()->getSourceLanguage()->getName(), '#prefix' => '<div class="tmgmt-ui-source-language tmgmt-ui-info-item">', '#suffix' => '</div>');
     $form['info']['target_language'] = array('#type' => 'item', '#title' => t('Target language'), '#markup' => $item->getJob()->getTargetLanguage()->getName(), '#prefix' => '<div class="tmgmt-ui-target-language tmgmt-ui-info-item">', '#suffix' => '</div>');
     $form['info']['changed'] = array('#type' => 'item', '#title' => t('Last change'), '#value' => $item->getChangedTime(), '#markup' => format_date($item->getChangedTime()), '#prefix' => '<div class="tmgmt-ui-changed tmgmt-ui-info-item">', '#suffix' => '</div>');
     $states = JobItem::getStates();
     $form['info']['state'] = array('#type' => 'item', '#title' => t('State'), '#markup' => $states[$item->getState()], '#prefix' => '<div class="tmgmt-ui-item-state tmgmt-ui-info-item">', '#suffix' => '</div>', '#value' => $item->getState());
     $job = $item->getJob();
     $url = $job->urlInfo();
     $form['info']['job'] = array('#type' => 'item', '#title' => t('Job'), '#markup' => \Drupal::l($job->label(), $url), '#prefix' => '<div class="tmgmt-ui-job tmgmt-ui-info-item">', '#suffix' => '</div>');
     // Display selected translator for already submitted jobs.
     if (!$item->getJob()->isSubmittable()) {
         $form['info']['translator'] = array('#type' => 'item', '#title' => t('Provider'), '#markup' => $job->getTranslatorLabel(), '#prefix' => '<div class="tmgmt-ui-translator tmgmt-ui-info-item">', '#suffix' => '</div>');
     }
     // Actually build the review form elements...
     $form['review'] = array('#type' => 'container');
     // Build the review form.
     $data = $item->getData();
     $this->trackChangedSource(\Drupal::service('tmgmt.data')->flatten($data), $form_state);
     // Need to keep the first hierarchy. So flatten must take place inside
     // of the foreach loop.
     foreach (Element::children($data) as $key) {
         $review_element = $this->reviewFormElement($form_state, \Drupal::service('tmgmt.data')->flatten($data[$key], $key), $key);
         if ($review_element) {
             $form['review'][$key] = $review_element;
         }
     }
     if ($view = entity_load('view', 'tmgmt_job_item_messages')) {
         $form['messages'] = array('#type' => 'details', '#title' => $view->label(), '#open' => FALSE, '#weight' => 50);
         $form['messages']['view'] = $view->getExecutable()->preview('block', array($item->id()));
     }
     $form['#attached']['library'][] = 'tmgmt/admin';
     // The reject functionality has to be implement by the translator plugin as
     // that process is completely unique and custom for each translation service.
     // Give the source ui controller a chance to affect the review form.
     $source = $this->sourceManager->createUIInstance($item->getPlugin());
     $form = $source->reviewForm($form, $form_state, $item);
     // Give the translator ui controller a chance to affect the review form.
     if ($item->getTranslator()) {
         $plugin_ui = $this->translatorManager->createUIInstance($item->getTranslator()->getPluginId());
         $form = $plugin_ui->reviewForm($form, $form_state, $item);
     }
     $form['footer'] = tmgmt_color_review_legend();
     return $form;
 }
 /**
  * Test the basic translation workflow.
  */
 public function testBasicWorkflow()
 {
     $translator = Translator::load('local');
     /** @var FilterFormat $basic_html_format */
     $basic_html_format = FilterFormat::create(array('format' => 'basic_html', 'name' => 'Basic HTML'));
     $basic_html_format->save();
     // Create a job and request a local translation.
     $this->loginAsTranslator();
     $job = $this->createJob();
     $job->translator = $translator->id();
     $job->addItem('test_source', 'test', '1');
     \Drupal::state()->set('tmgmt.test_source_data', ['dummy' => ['deep_nesting' => ['#text' => file_get_contents(drupal_get_path('module', 'tmgmt') . '/tests/testing_html/sample.html'), '#label' => 'Label for job item with type test and id 2.', '#translate' => TRUE, '#format' => 'basic_html']], 'second' => ['#text' => 'second text', '#label' => 'Second label', '#translate' => TRUE], 'third' => ['#text' => 'third text', '#label' => 'Third label', '#translate' => TRUE]]);
     $job->addItem('test_source', 'test', '2');
     $job->save();
     // Make sure that the checkout page works as expected when there are no
     // roles.
     $this->drupalGet($job->toUrl());
     $this->assertText(t('@translator can not translate from @source to @target.', array('@translator' => 'Drupal user', '@source' => 'English', '@target' => 'German')));
     $xpath = $this->xpath('//*[@id="edit-translator"]')[0];
     $this->assertEqual($xpath->option[0], 'Drupal user (unsupported)');
     $this->assignee = $this->drupalCreateUser(array_merge($this->localTranslatorPermissions, [$basic_html_format->getPermissionName()]));
     // The same when there is a single role.
     $this->drupalGet($job->toUrl());
     $this->assertText(t('@translator can not translate from @source to @target.', array('@translator' => 'Drupal user', '@source' => 'English', '@target' => 'German')));
     // Create another local translator with the required abilities.
     $other_assignee_same = $this->drupalCreateUser($this->localTranslatorPermissions);
     // And test again with two roles but still no abilities.
     $this->drupalGet($job->toUrl());
     $this->assertText(t('@translator can not translate from @source to @target.', array('@translator' => 'Drupal user', '@source' => 'English', '@target' => 'German')));
     $this->drupalLogin($other_assignee_same);
     // Configure language abilities.
     $edit = array('tmgmt_translation_skills[0][language_from]' => 'en', 'tmgmt_translation_skills[0][language_to]' => 'de');
     $this->drupalPostForm('user/' . $other_assignee_same->id() . '/edit', $edit, t('Save'));
     // Check that the user is not listed in the translator selection form.
     $this->loginAsAdmin();
     $this->drupalGet($job->toUrl());
     $xpath = $this->xpath('//*[@id="edit-translator"]')[0];
     $this->assertEqual($xpath->option[0], 'Drupal user');
     $this->assertText(t('Assign job to'));
     $this->assertText($other_assignee_same->getUsername());
     $this->assertNoText($this->assignee->getUsername());
     $this->drupalLogin($this->assignee);
     // Configure language abilities.
     $edit = array('tmgmt_translation_skills[0][language_from]' => 'en', 'tmgmt_translation_skills[0][language_to]' => 'de');
     $this->drupalPostForm('user/' . $this->assignee->id() . '/edit', $edit, t('Save'));
     // Check that the translator is now listed.
     $this->loginAsAdmin();
     $this->drupalGet($job->toUrl());
     $this->assertText($this->assignee->getUsername());
     // Test assign task while submitting job.
     $job_comment = 'Dummy job comment';
     $edit = ['settings[translator]' => $this->assignee->id(), 'settings[job_comment]' => $job_comment];
     $this->drupalPostForm(NULL, $edit, t('Submit to provider'));
     $this->drupalLogin($this->assignee);
     $this->drupalGet('translate/pending');
     $this->assertText($job->label());
     $this->loginAsAdmin($this->localManagerPermissions);
     $this->drupalGet('manage-translate/assigned');
     $this->assertNoLink(t('Delete'));
     $this->clickLink(t('Unassign'));
     $this->drupalPostForm(NULL, [], t('Unassign'));
     // Test for job comment in the job checkout info pane.
     $this->drupalGet($job->toUrl());
     $this->assertText($job_comment);
     $this->drupalLogin($this->assignee);
     // Create a second local translator with different language abilities,
     // make sure that he does not see the task.
     $other_translator = $this->drupalCreateUser($this->localTranslatorPermissions);
     $this->drupalLogin($other_translator);
     // Configure language abilities.
     $edit = array('tmgmt_translation_skills[0][language_from]' => 'de', 'tmgmt_translation_skills[0][language_to]' => 'en');
     $this->drupalPostForm('user/' . $other_translator->id() . '/edit', $edit, t('Save'));
     $this->drupalGet('translate');
     $this->assertNoText($job->label());
     $this->drupalLogin($this->assignee);
     // Check the translate overview.
     $this->drupalGet('translate');
     $this->assertText($job->label());
     // @todo: Fails, encoding problem?
     // $this->assertText(t('@from => @to', array('@from' => 'en', '@to' => 'de')));
     // Test LocalTaskForm.
     $this->clickLink('View');
     $this->assertText('Unassigned');
     $xpath = $this->xpath('//*[@id="edit-status"]');
     $this->assertTrue(empty($xpath));
     $this->loginAsAdmin($this->localManagerPermissions);
     $this->drupalGet('translate');
     $this->clickLink('View');
     $xpath = $this->xpath('//*[@id="edit-tuid"]');
     $this->assertFalse(empty($xpath));
     $edit = array('tuid' => $this->assignee->id());
     $this->drupalPostForm(NULL, $edit, t('Save task'));
     $this->assertText(t('Assigned to user @assignee.', ['@assignee' => $this->assignee->getDisplayName()]));
     $this->drupalGet('manage-translate/assigned');
     $this->clickLink('View');
     $edit = array('tuid' => 0);
     $this->drupalPostForm(NULL, $edit, t('Save task'));
     $this->drupalLogin($this->assignee);
     $this->drupalGet('translate');
     // Assign to action not working yet.
     $edit = array('tmgmt_local_task_bulk_form[0]' => TRUE, 'action' => 'tmgmt_local_task_assign_to_me');
     $this->drupalPostForm(NULL, $edit, t('Apply'));
     $this->assertText(t('Assign to me was applied to 1 item.'));
     // Unassign again.
     $edit = array('tmgmt_local_task_bulk_form[0]' => TRUE, 'action' => 'tmgmt_local_task_unassign_multiple');
     $this->drupalPostForm(NULL, $edit, t('Apply'));
     $this->assertText(t('Unassign was applied to 1 item.'));
     // Now test the assign link.
     // @todo Action should not redirect to mine.
     $this->drupalGet('translate');
     $this->clickLink(t('Assign to me'));
     $this->assertText(t('The task has been assigned to you.'));
     // Assert created local task and task items.
     $this->drupalGet('translate/pending');
     $this->clickLink(t('View'));
     $this->assertTrue(preg_match('|translate/(\\d+)|', $this->getUrl(), $matches), 'Task found');
     /** @var \Drupal\tmgmt_local\Entity\LocalTask $task */
     $task = \Drupal::entityTypeManager()->getStorage('tmgmt_local_task')->load($matches[1]);
     $this->assertTrue($task->isPending());
     $items = $task->getItems();
     /** @var \Drupal\tmgmt_local\Entity\LocalTaskItem $first_task_item */
     $first_task_item = reset($items);
     $this->assertTrue($first_task_item->isPending());
     // Log in with the translator with the same abilities, make sure that he
     // does not see the assigned task.
     $this->drupalLogin($other_assignee_same);
     $this->drupalGet('translate');
     $this->assertNoText($job->label());
     $this->drupalGet('translate/items/' . $first_task_item->id());
     $this->assertResponse(403);
     $this->drupalLogin($this->assignee);
     // Translate the task.
     $this->drupalGet('translate/' . $task->id());
     $this->assertText('test_source:test:1');
     $this->assertText('test_source:test:2');
     // Translate the first item.
     $this->clickLink(t('Translate'));
     // Assert the breadcrumb.
     $this->assertLink(t('Home'));
     $this->assertLink(t('Local Tasks'));
     $this->assertText($job->label());
     // Assert the header.
     $this->assertLink($first_task_item->getJobItem()->getSourceLabel());
     $this->assertText($first_task_item->getJobItem()->getSourceType());
     $this->assertText($first_task_item->getJobItem()->getJob()->getSourceLanguage()->getName());
     $this->assertText($first_task_item->getJobItem()->getJob()->getTargetLanguage()->getName());
     $this->assertText(\Drupal::service('date.formatter')->format($first_task_item->getChangedTime()));
     $this->assertText($first_task_item->getStatus());
     $this->assertLink($first_task_item->getTask()->label());
     $this->assertText(t('Dummy'));
     // Check if Save as completed button is displayed.
     $elements = $this->xpath('//*[@id="edit-save-as-completed"]');
     $this->assertTrue(!empty($elements), "'Save as completed' button appears.");
     // Job comment is present in the translate tool as well.
     $this->assertText($job_comment);
     $this->assertText('test_source:test:1');
     // Try to complete a translation when translations are missing.
     $edit = array('dummy|deep_nesting[translation]' => '');
     $this->drupalPostForm(NULL, $edit, t('Save as completed'));
     $this->assertText(t('Missing translation.'));
     $edit = array('dummy|deep_nesting[translation]' => $translation1 = 'German translation of source 1');
     $this->drupalPostForm(NULL, $edit, t('Save as completed'));
     $this->assertRaw('tmgmt/icons/gray-check.svg" title="Translated"');
     $this->assertText('The translation for ' . $first_task_item->label() . ' has been saved as completed.');
     // Check that the source has not being modified.
     $this->clickLink(t('View'));
     /** @var \Drupal\tmgmt\JobItemInterface $job_item */
     $job_items = $job->getItems(['tjiid' => 1]);
     $job_item = reset($job_items);
     $source = $job_item->getData(['dummy', 'deep_nesting', '#text']);
     $this->assertText($source);
     // Review and accept the first item.
     \Drupal::entityTypeManager()->getStorage('tmgmt_job_item')->resetCache();
     drupal_static_reset('tmgmt_local_task_statistics_load');
     /** @var \Drupal\tmgmt\JobItemInterface $item1 */
     $item1 = JobItem::load(1);
     // The first item should be available for review.
     $this->assertTrue($item1->isNeedsReview(), 'Job item 1 needs review.');
     $item1->acceptTranslation();
     // The first item should be accepted now, the second still in progress.
     \Drupal::entityTypeManager()->getStorage('tmgmt_local_task_item')->resetCache();
     $this->drupalGet('translate/1');
     // Checking if the 'Save as completed' button is not displayed.
     $this->drupalGet('translate/items/1');
     $elements = $this->xpath('//*[@id="edit-save-as-completed"]');
     $this->assertTrue(empty($elements), "'Save as completed' button does not appear.");
     // Checking if the item status is not displayed.
     $this->assertNoRaw('title="Finish"');
     $this->assertNoRaw('title="Reject"');
     // We can go back to the Task from the item.
     $this->drupalGet('translate/items/1');
     $this->clickLink($task->label());
     // Let's check the task status.
     /** @var \Drupal\tmgmt_local\Entity\LocalTask $task */
     $task = entity_load('tmgmt_local_task', $task->id(), TRUE);
     $this->assertTrue($task->isPending());
     /** @var \Drupal\tmgmt_local\Entity\LocalTaskItem $second_task_item */
     list($first_task_item, $second_task_item) = array_values($task->getItems());
     $this->assertTrue($first_task_item->isClosed());
     // Assert that translator can provide translations for a "Dummy" field. An
     // empty text field should be displayed as translator does not have a
     // permission to use "full_html" text format.
     $second_task_item->updateData('dummy|deep_nesting', ['#format' => 'full_html']);
     $second_task_item->save();
     $this->clickLink(t('Translate'));
     $this->assertFieldByName('dummy|deep_nesting[translation]');
     $this->assertRaw('Save as completed" class="button button--primary js-form-submit form-submit"');
     $translation_field = $this->xpath('//*[@id="edit-dummydeep-nesting-translation"]')[0];
     $this->assertEqual($translation_field, '');
     // Translate the second item but do not mark as translated it yet.
     $second_task_item->updateData('dummy|deep_nesting', ['#format' => 'basic_html']);
     $second_task_item->save();
     $this->drupalGet('translate/items/' . $second_task_item->id());
     $xpath = $this->xpath('//*[@id="edit-dummydeep-nesting-translation-format-guidelines"]/div')[0];
     $this->assertEqual($xpath[0]->h4[0], t('Basic HTML'));
     // Assert the order of the displayed elements.
     $translate_elements = $this->xpath('//*[@id="edit-translation"]/table');
     $ids = [];
     foreach ($translate_elements as $translate_element) {
         $ids[] = (string) $translate_element['id'];
     }
     $this->assertEqual($ids[0], 'tmgmt-local-element-dummy-deep-nesting');
     $this->assertEqual($ids[1], 'tmgmt-local-element-second');
     $this->assertEqual($ids[2], 'tmgmt-local-element-third');
     $edit = array('dummy|deep_nesting[translation][value]' => $translation2 = 'German translation of source 2');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('The translation for ' . $second_task_item->label() . ' has been saved.');
     drupal_static_reset('tmgmt_local_task_statistics_load');
     /** @var \Drupal\tmgmt_local\Entity\LocalTask $task */
     $task = entity_load('tmgmt_local_task', $task->id(), TRUE);
     $this->assertTrue($task->isPending());
     // Mark the data item as translated but don't save the task item as
     // completed.
     $this->clickLink(t('Translate'));
     $this->drupalPostAjaxForm(NULL, [], 'finish-dummy|deep_nesting');
     $this->assertRaw('name="reject-dummy|deep_nesting"', "'✗' button appears.");
     $this->drupalGet('translate/' . $task->id());
     \Drupal::entityTypeManager()->getStorage('tmgmt_local_task_item')->resetCache();
     drupal_static_reset('tmgmt_local_task_statistics_load');
     /** @var \Drupal\tmgmt_local\Entity\LocalTask $task */
     $task = entity_load('tmgmt_local_task', $task->id(), TRUE);
     $this->assertTrue($task->isPending());
     list($first_task_item, $second_task_item) = array_values($task->getItems());
     $this->assertTrue($first_task_item->isClosed());
     $this->assertTrue($second_task_item->isPending());
     // Check the job data.
     \Drupal::entityTypeManager()->getStorage('tmgmt_job_item')->resetCache();
     /** @var \Drupal\tmgmt\JobInterface $job */
     $job = Job::load($job->id());
     /** @var \Drupal\tmgmt\JobItemInterface $item2 */
     list($item1, $item2) = array_values($job->getItems());
     $this->assertTrue($item1->isAccepted(), 'Job item 1 is accepted.');
     // The first item should be active.
     $this->assertTrue($item2->isActive(), 'Job item 2 is still active.');
     // Check the overview page, the task should still show in progress.
     $this->drupalGet('translate');
     $this->assertText(t('Pending'));
     // Mark the second item as completed now.
     $this->clickLink(t('View'));
     $this->clickLink(t('Translate'));
     $remaining_translations = ['second[translation]' => 'Third translation', 'third[translation]' => 'Third translation'];
     $this->drupalPostForm(NULL, $remaining_translations, t('Save as completed'));
     $this->assertText('The translation for ' . $second_task_item->label() . ' has been saved as completed.');
     $this->clickLink('View');
     // Review and accept the second item.
     \Drupal::entityTypeManager()->getStorage('tmgmt_job_item')->resetCache();
     drupal_static_reset('tmgmt_local_task_statistics_load');
     $item1 = JobItem::load(2);
     $item1->acceptTranslation();
     // Refresh the page.
     $this->drupalGet('translate');
     // We should have been redirect back to the overview, the task should be
     // completed now.
     $this->assertNoText($task->getJob()->label());
     $this->clickLink(t('Closed'));
     $this->assertText($task->getJob()->label());
     $this->assertText(t('Completed'));
     \Drupal::entityTypeManager()->getStorage('tmgmt_local_task_item')->resetCache();
     $task = tmgmt_local_task_load($task->id());
     $this->assertTrue($task->isClosed());
     list($first_task_item, $second_task_item) = array_values($task->getItems());
     $this->assertTrue($first_task_item->isClosed());
     $this->assertTrue($second_task_item->isClosed());
     \Drupal::entityTypeManager()->getStorage('tmgmt_job_item')->resetCache();
     $job = Job::load($job->id());
     list($item1, $item2) = array_values($job->getItems());
     // Job was accepted and finished automatically due to the default approve
     // setting.
     $this->assertTrue($job->isFinished());
     $this->assertEqual($item1->getData(array('dummy', 'deep_nesting', '#translation', '#text')), $translation1);
     $this->assertEqual($item2->getData(array('dummy', 'deep_nesting', '#translation', '#text')), $translation2);
     // Delete the job, make sure that the corresponding task and task items were
     // deleted.
     $job->delete();
     $this->assertFalse(tmgmt_local_task_item_load($task->id()));
     $this->assertFalse($task->getItems());
 }
 /**
  * {@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 the translation status render array with source and job item status.
  *
  * @param int $status
  *   The source status: original, missing, current or outofdate.
  * @param \Drupal\tmgmt\JobItemInterface|NULL $job_item
  *   The existing job item for the source.
  *
  * @return array
  *   The render array for displaying the status.
  */
 function buildTranslationStatus($status, JobItemInterface $job_item = NULL)
 {
     switch ($status) {
         case 'original':
             $label = t('Source language');
             $icon = 'core/misc/icons/bebebe/house.svg';
             break;
         case 'missing':
             $label = t('Not translated');
             $icon = 'core/misc/icons/bebebe/ex.svg';
             break;
         case 'outofdate':
             $label = t('Translation Outdated');
             $icon = drupal_get_path('module', 'tmgmt') . '/icons/outdated.svg';
             break;
         default:
             $label = t('Translation up to date');
             $icon = 'core/misc/icons/73b355/check.svg';
     }
     $build['source'] = ['#theme' => 'image', '#uri' => $icon, '#title' => $label, '#alt' => $label];
     // If we have an active job item, wrap it in a link.
     if ($job_item) {
         $states_labels = JobItem::getStates();
         $state_label = $states_labels[$job_item->getState()];
         $label = t('Active job item: @state', array('@state' => $state_label));
         $url = $job_item->toUrl();
         $job = $job_item->getJob();
         switch ($job_item->getState()) {
             case JobItem::STATE_ACTIVE:
                 if ($job->isUnprocessed()) {
                     $url = $job->toUrl();
                     $label = t('Active job item: @state', array('@state' => $state_label));
                 }
                 $icon = drupal_get_path('module', 'tmgmt') . '/icons/hourglass.svg';
                 break;
             case JobItem::STATE_REVIEW:
                 $icon = drupal_get_path('module', 'tmgmt') . '/icons/ready.svg';
                 break;
         }
         $url->setOption('query', \Drupal::destination()->getAsArray());
         $url->setOption('attributes', array('title' => $label));
         $item_icon = ['#theme' => 'image', '#uri' => $icon, '#title' => $label, '#alt' => $label];
         $build['job_item'] = ['#type' => 'link', '#url' => $url, '#title' => $item_icon];
     }
     return $build;
 }
Example #6
0
 /**
  * {@inheritdoc}
  */
 public function setState($state, $message = NULL, $variables = array(), $type = 'debug')
 {
     // Return TRUE if the state could be set. Return FALSE otherwise.
     if (array_key_exists($state, JobItem::getStates()) && $this->get('state')->value != $state) {
         $this->state = $state;
         $this->save();
         // If a message is attached to this state change add it now.
         if (!empty($message)) {
             $this->addMessage($message, $variables, $type);
         }
     }
     return $this->get('state')->value;
 }
Example #7
0
 /**
  * Custom form submit callback for tmgmt_cart_cart_form().
  */
 function submitRequestTranslation(array $form, FormStateInterface $form_state)
 {
     $target_languages = array_filter($form_state->getValue('target_language'));
     $enforced_source_language = NULL;
     if ($form_state->getValue('enforced_source_language')) {
         $enforced_source_language = $form_state->getValue('source_language');
     }
     $skipped_count = 0;
     $job_items_by_source_language = array();
     // Group the selected items by source language.
     foreach (JobItem::loadMultiple(array_filter($form_state->getValue('items'))) as $job_item) {
         $source_language = $enforced_source_language ? $enforced_source_language : $job_item->getSourceLangCode();
         if (in_array($source_language, $job_item->getExistingLangCodes())) {
             $job_items_by_source_language[$source_language][$job_item->id()] = $job_item;
         } else {
             $skipped_count++;
         }
     }
     $jobs = array();
     $remove_job_item_ids = array();
     // Loop over all target languages, create a job for each source and target
     // language combination add add the relevant job items to it.
     foreach ($target_languages as $target_language) {
         foreach ($job_items_by_source_language as $source_language => $job_items) {
             // Skip in case the source language is the same as the target language.
             if ($source_language == $target_language) {
                 continue;
             }
             $job = tmgmt_job_create($source_language, $target_language, $this->currentUser()->id());
             $job_empty = TRUE;
             /** @var \Drupal\tmgmt\JobItemInterface $job_item */
             foreach ($job_items as $id => $job_item) {
                 try {
                     // As the same item might be added to multiple jobs, we need to
                     // re-create them and delete the old ones, after removing them from
                     // the cart.
                     $job->addItem($job_item->getPlugin(), $job_item->getItemType(), $job_item->getItemId());
                     $remove_job_item_ids[$job_item->id()] = $job_item->id();
                     $job_empty = FALSE;
                 } catch (Exception $e) {
                     // If an item fails for one target language, then it is also going
                     // to fail for others, so remove it from the array.
                     unset($job_items_by_source_language[$source_language][$id]);
                     drupal_set_message($e->getMessage(), 'error');
                 }
             }
             if (!$job_empty) {
                 $jobs[] = $job;
             }
         }
     }
     // Remove job items from the cart.
     if ($remove_job_item_ids) {
         tmgmt_cart_get()->removeJobItems($remove_job_item_ids);
         entity_delete_multiple('tmgmt_job_item', $remove_job_item_ids);
     }
     // Start the checkout process if any jobs were created.
     if ($jobs) {
         if ($enforced_source_language) {
             drupal_set_message(t('You have enforced the job source language which most likely resulted in having a translation of your original content as the job source text. You should review the job translation received from the translator carefully to prevent the content quality loss.'), 'warning');
             if ($skipped_count) {
                 $languages = \Drupal::languageManager()->getLanguages();
                 drupal_set_message(\Drupal::translation()->formatPlural($skipped_count, 'One item skipped as for the language @language it was not possible to retrieve a translation.', '@count items skipped as for the language @language it was not possible to retrieve a translations.', array('@language' => $languages[$enforced_source_language]->getName())));
             }
         }
         tmgmt_job_checkout_and_redirect($form_state, $jobs);
     } else {
         drupal_set_message(t('From the selection you made it was not possible to create any translation job.'));
     }
 }
Example #8
0
 /**
  * {@inheritdoc}
  */
 public function getMostRecentItem($plugin, $item_type, $item_id)
 {
     $query = \Drupal::entityQuery('tmgmt_job_item')->condition('tjid', $this->id())->condition('plugin', $plugin)->condition('item_type', $item_type)->condition('item_id', $item_id)->sort('tjiid', 'DESC')->range(0, 1);
     $result = $query->execute();
     if (!empty($result)) {
         return JobItem::load(reset($result));
     }
     return NULL;
 }
Example #9
0
 /**
  * Test the cart functionality.
  */
 function testCart()
 {
     $this->addLanguage('fr');
     $job_items = array();
     // Create a few job items and add them to the cart.
     for ($i = 1; $i < 6; $i++) {
         $job_item = tmgmt_job_item_create('test_source', 'test', $i);
         $job_item->save();
         $job_items[$i] = $job_item;
     }
     $this->loginAsTranslator();
     foreach ($job_items as $job_item) {
         $this->drupalGet('tmgmt-add-to-cart/' . $job_item->id());
     }
     // Check if the items are displayed in the cart.
     $this->drupalGet('admin/tmgmt/cart');
     foreach ($job_items as $job_item) {
         $this->assertText($job_item->label());
     }
     // Test the remove items from cart functionality.
     $this->drupalPostForm(NULL, ['items[1]' => TRUE, 'items[2]' => FALSE, 'items[3]' => FALSE, 'items[4]' => TRUE, 'items[5]' => FALSE], t('Remove selected'));
     $this->assertText($job_items[2]->label());
     $this->assertText($job_items[3]->label());
     $this->assertText($job_items[5]->label());
     $this->assertNoText($job_items[1]->label());
     $this->assertNoText($job_items[4]->label());
     $this->assertText(t('Job items were removed from the cart.'));
     // Test that removed job items from cart were deleted as well.
     $existing_items = JobItem::loadMultiple();
     $this->assertTrue(!isset($existing_items[$job_items[1]->id()]));
     $this->assertTrue(!isset($existing_items[$job_items[4]->id()]));
     $this->drupalPostForm(NULL, array(), t('Empty cart'));
     $this->assertNoText($job_items[2]->label());
     $this->assertNoText($job_items[3]->label());
     $this->assertNoText($job_items[5]->label());
     $this->assertText(t('All job items were removed from the cart.'));
     // No remaining job items.
     $existing_items = JobItem::loadMultiple();
     $this->assertTrue(empty($existing_items));
     $language_sequence = array('en', 'en', 'fr', 'fr', 'de', 'de');
     for ($i = 1; $i < 7; $i++) {
         $job_item = tmgmt_job_item_create('test_source', 'test', $i);
         $job_item->save();
         $job_items[$i] = $job_item;
         $languages[$job_items[$i]->id()] = $language_sequence[$i - 1];
     }
     \Drupal::state()->set('tmgmt.test_source_languages', $languages);
     foreach ($job_items as $job_item) {
         $this->drupalGet('tmgmt-add-to-cart/' . $job_item->id());
     }
     $this->drupalPostForm('admin/tmgmt/cart', array('items[' . $job_items[1]->id() . ']' => TRUE, 'items[' . $job_items[2]->id() . ']' => TRUE, 'items[' . $job_items[3]->id() . ']' => TRUE, 'items[' . $job_items[4]->id() . ']' => TRUE, 'items[' . $job_items[5]->id() . ']' => TRUE, 'items[' . $job_items[6]->id() . ']' => FALSE, 'target_language[]' => array('en', 'de')), t('Request translation'));
     $this->assertText(t('@count jobs need to be checked out.', array('@count' => 4)));
     // We should have four jobs with following language combinations:
     // [fr, fr] => [en]
     // [de] => [en]
     // [en, en] => [de]
     // [fr, fr] => [de]
     $jobs = entity_load_multiple_by_properties('tmgmt_job', array('source_language' => 'fr', 'target_language' => 'en'));
     $job = reset($jobs);
     $this->assertEqual(count($job->getItems()), 2);
     $jobs = entity_load_multiple_by_properties('tmgmt_job', array('source_language' => 'de', 'target_language' => 'en'));
     $job = reset($jobs);
     $this->assertEqual(count($job->getItems()), 1);
     $jobs = entity_load_multiple_by_properties('tmgmt_job', array('source_language' => 'en', 'target_language' => 'de'));
     $job = reset($jobs);
     $this->assertEqual(count($job->getItems()), 2);
     $jobs = entity_load_multiple_by_properties('tmgmt_job', array('source_language' => 'fr', 'target_language' => 'de'));
     $job = reset($jobs);
     $this->assertEqual(count($job->getItems()), 2);
     $this->drupalGet('admin/tmgmt/cart');
     // Both fr and one de items must be gone.
     $this->assertNoText($job_items[1]->label());
     $this->assertNoText($job_items[2]->label());
     $this->assertNoText($job_items[3]->label());
     $this->assertNoText($job_items[4]->label());
     $this->assertNoText($job_items[5]->label());
     // One de item is in the cart as it was not selected for checkout.
     $this->assertText($job_items[6]->label());
     // Check to see if no items are selected and the error message pops up.
     $this->drupalPostForm('admin/tmgmt/cart', ['items[' . $job_items[6]->id() . ']' => FALSE], t('Request translation'));
     $this->assertUniqueText(t("You didn't select any source items."));
 }
 /**
  * Test for simple configuration translation.
  */
 function testSimpleConfigTranslation()
 {
     $this->loginAsTranslator(array('translate configuration'));
     // Go to the translate tab.
     $this->drupalGet('admin/tmgmt/sources/config/_simple_config');
     // Assert some basic strings on that page.
     $this->assertText(t('Simple configuration overview (Config Entity)'));
     // Request a translation for Site information settings.
     $edit = array('items[system.site_information_settings]' => TRUE);
     $this->drupalPostForm(NULL, $edit, t('Request translation'));
     // Verify that we are on the translate tab.
     $this->assertText(t('One job needs to be checked out.'));
     $this->assertText('System information (English to ?, Unprocessed)');
     // Submit.
     $this->drupalPostForm(NULL, array(), t('Submit to provider'));
     // Make sure that we're back on the originally defined destination URL.
     $this->assertUrl('admin/tmgmt/sources/config/_simple_config');
     $overview_url = Url::fromRoute('tmgmt.source_overview', array('plugin' => 'config', 'item_type' => '_simple_config'))->toString();
     // Translated languages should now be listed as Needs review.
     $this->assertRaw(SafeMarkup::format('href=":url" title="Active job item: Needs review"', array(':url' => JobItem::load(1)->urlInfo()->setOption('query', ['destination' => $overview_url])->toString())));
     $this->assertText(t('Test translation created.'));
     $this->assertText('The translation of System information to German is finished and can now be reviewed.');
     // Verify that the pending translation is shown.
     $review = $this->xpath('//table[@id="edit-items"]/tbody/tr[@class="even"][1]/td[@class="langstatus-de"]/a/@href');
     $destination = $this->getAbsoluteUrl($review[0]['href']);
     $this->drupalGet($destination);
     $this->drupalPostForm(NULL, array(), t('Save'));
     // Request a translation for Account settings
     $edit = array('items[entity.user.admin_form]' => TRUE);
     $this->drupalPostForm(NULL, $edit, t('Request translation'));
     // Verify that we are on the checkout page.
     $this->assertText(t('One job needs to be checked out.'));
     $this->assertText('Account settings (English to ?, Unprocessed)');
     $this->drupalPostForm(NULL, array(), t('Submit to provider'));
     // Make sure that we're back on the originally defined destination URL.
     $this->assertUrl('admin/tmgmt/sources/config/_simple_config');
     // Translated languages should now be listed as Needs review.
     $links = $this->xpath('//table[@id="edit-items"]/tbody/tr/td/a/@href');
     $counter = 0;
     foreach ($links as $subarray) {
         $counter += count($subarray);
     }
     $this->assertEqual($counter, 2);
     // Save one translation.
     $this->drupalPostForm('admin/tmgmt/items/1', array(), t('Save as completed'));
     // Test if the filter works.
     $filters = array('search[name]' => 'system');
     $this->drupalPostForm('admin/tmgmt/sources/config/_simple_config', $filters, t('Search'));
     // Check if the list has 2 rows.
     $this->assertEqual(count($this->xpath('//tbody/tr')), 2);
     $filters = array('search[target_language]' => 'de', 'search[target_status]' => 'translated');
     $this->drupalPostForm('admin/tmgmt/sources/config/_simple_config', $filters, t('Search'));
     // Just 1 simple configuration was translated.
     $this->assertEqual(count($this->xpath('//tbody/tr')), 1);
     // Filter with name and target_status.
     $filters = array('search[name]' => 'settings', 'search[target_language]' => 'de', 'search[target_status]' => 'untranslated');
     $this->drupalPostForm('admin/tmgmt/sources/config/_simple_config', $filters, t('Search'));
     // There is 1 simple configuration untranslated with name 'settings'.
     $this->assertEqual(count($this->xpath('//tbody/tr')), 1);
     $filters = array('search[name]' => 'sys', 'search[target_language]' => 'de', 'search[target_status]' => 'translated');
     $this->drupalPostForm('admin/tmgmt/sources/config/_simple_config', $filters, t('Search'));
     // There are 2 simple configurations with name 'sys' but just 1 is translated.
     $this->assertEqual(count($this->xpath('//tbody/tr')), 1);
 }
Example #11
0
 /**
  * {@inheritdoc}
  */
 public function validateImport($imported_file, $is_file = TRUE)
 {
     // Validates imported XLIFF file.
     // Checks:
     // - Job ID
     // - Target ans source languages
     // - Content integrity.
     $xml = $this->getImportedXML($imported_file, $is_file);
     if ($xml === FALSE) {
         drupal_set_message(t('The imported file is not a valid XML.'), 'error');
         return FALSE;
     }
     // Check if our phase information is there.
     $phase = $xml->xpath("//xliff:phase[@phase-name='extraction']");
     if ($phase) {
         $phase = reset($phase);
     } else {
         drupal_set_message(t('The imported file is missing required XLIFF phase information.'), 'error');
         return FALSE;
     }
     // Check if the job has a valid job reference.
     if (!isset($phase['job-id'])) {
         drupal_set_message(t('The imported file does not contain a job reference.'), 'error');
         return FALSE;
     }
     // Attempt to load the job if none passed.
     $job = Job::load((int) $phase['job-id']);
     if (empty($job)) {
         drupal_set_message(t('The imported file job id @file_tjid is not available.', array('@file_tjid' => $phase['job-id'])), 'error');
         return FALSE;
     }
     // Compare source language.
     if (!isset($xml->file['source-language']) || $job->getRemoteSourceLanguage() != $xml->file['source-language']) {
         $job->addMessage('The imported file source language @file_language does not match the job source language @job_language.', array('@file_language' => empty($xml->file['source-language']) ? t('none') : $xml->file['source-language'], '@job_language' => $job->source_language), 'error');
         return FALSE;
     }
     // Compare target language.
     if (!isset($xml->file['target-language']) || $job->getRemoteTargetLanguage() != $xml->file['target-language']) {
         $job->addMessage('The imported file target language @file_language does not match the job target language @job_language.', array('@file_language' => empty($xml->file['target-language']) ? t('none') : $xml->file['target-language'], '@job_language' => $job->target_language), 'error');
         return FALSE;
     }
     $targets = $this->getImportedTargets($job);
     if (empty($targets)) {
         $job->addMessage('The imported file seems to be missing translation.', 'error');
         return FALSE;
     }
     // In case we do not do xliff processing we cannot do the elements
     // count validation.
     if (!$job->getSetting('xliff_processing')) {
         return $job;
     }
     $reader = new \XMLReader();
     $xliff_validation = $job->getSetting('xliff_validation');
     foreach ($targets as $id => $target) {
         $array_key = \Drupal::service('tmgmt.data')->ensureArrayKey($id);
         $job_item = JobItem::load(array_shift($array_key));
         $count = 0;
         $reader->XML('<translation>' . $target['#text'] . '</translation>');
         while ($reader->read()) {
             if (in_array($reader->name, array('translation', '#text'))) {
                 continue;
             }
             $count++;
         }
         if (!isset($xliff_validation[$id]) || $xliff_validation[$id] != $count) {
             $job_item->addMessage('Failed to validate semantic integrity of %key element. Please check also the HTML code of the element in the review process.', array('%key' => \Drupal::service('tmgmt.data')->ensureStringKey($array_key)));
         }
     }
     // Validation successful.
     return $job;
 }
Example #12
0
 /**
  * Tests of the job item review process.
  */
 public function testReview()
 {
     $job = $this->createJob();
     $job->translator = $this->default_translator->id();
     $job->settings = array();
     $job->save();
     $item = $job->addItem('test_source', 'test', 1);
     // The test expects the item to be active.
     $item->active();
     $data = \Drupal::service('tmgmt.data')->flatten($item->getData());
     $keys = array_keys($data);
     $key = $keys[0];
     $this->drupalGet('admin/tmgmt/items/' . $item->id());
     // Test that source and target languages are displayed.
     $this->assertText($item->getJob()->getSourceLanguage()->getName());
     $this->assertText($item->getJob()->getTargetLanguage()->getName());
     // Testing the title of the preview page.
     $this->assertText(t('Job item @source_label', array('@source_label' => $job->label())));
     // Testing the result of the
     // TMGMTTranslatorUIControllerInterface::reviewDataItemElement()
     $this->assertText(t('Testing output of review data item element @key from the testing provider.', array('@key' => $key)));
     // Test the review tool source textarea.
     $this->assertFieldByName('dummy|deep_nesting[source]', $data[$key]['#text']);
     // Save translation.
     $this->drupalPostForm(NULL, array('dummy|deep_nesting[translation]' => $data[$key]['#text'] . 'translated'), t('Save'));
     // Test review data item.
     $this->drupalGet('admin/tmgmt/items/' . $item->id());
     $this->drupalPostAjaxForm(NULL, [], 'reviewed-dummy|deep_nesting');
     $this->assertRaw('icons/gray-check.svg" alt="Reviewed"');
     \Drupal::entityTypeManager()->getStorage('tmgmt_job')->resetCache();
     \Drupal::entityTypeManager()->getStorage('tmgmt_job_item')->resetCache();
     /** @var JobItem $item */
     $item = JobItem::load($item->id());
     $this->assertEqual($item->getCountReviewed(), 1, 'Item reviewed correctly.');
     // Check if translation has been saved.
     $this->assertFieldByName('dummy|deep_nesting[translation]', $data[$key]['#text'] . 'translated');
     // Tests for the minimum height of the textareas.
     $rows = $this->xpath('//textarea[@name="dummy|deep_nesting[source]"]');
     $this->assertEqual((string) $rows[0]['rows'], 3);
     $rows2 = $this->xpath('//textarea[@name="dummy|deep_nesting[translation]"]');
     $this->assertEqual((string) $rows2[0]['rows'], 3);
     // Test data item status when content changes.
     $this->drupalPostForm(NULL, array(), t('Save'));
     $this->drupalGet('admin/tmgmt/items/' . $item->id());
     $this->assertRaw('icons/gray-check.svg" alt="Reviewed"');
     $edit = ['dummy|deep_nesting[translation]' => 'New text for job item'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->drupalGet('admin/tmgmt/items/' . $item->id());
     $this->assertRaw('icons/gray-check.svg" alt="Reviewed"');
     $this->assertFieldByName('dummy|deep_nesting[translation]', 'New text for job item');
     // Test for the dynamical height of the source textarea.
     \Drupal::state()->set('tmgmt.test_source_data', array('dummy' => array('deep_nesting' => array('#text' => str_repeat('Text for job item', 20), '#label' => 'Label'))));
     $item2 = $job->addItem('test_source', 'test', 2);
     $this->drupalGet('admin/tmgmt/items/' . $item2->id());
     $rows3 = $this->xpath('//textarea[@name="dummy|deep_nesting[source]"]');
     $this->assertEqual((string) $rows3[0]['rows'], 4);
     // Test for the maximum height of the source textarea.
     \Drupal::state()->set('tmgmt.test_source_data', array('dummy' => array('deep_nesting' => array('#text' => str_repeat('Text for job item', 100), '#label' => 'Label'))));
     $item3 = $job->addItem('test_source', 'test', 3);
     $this->drupalGet('admin/tmgmt/items/' . $item3->id());
     $rows4 = $this->xpath('//textarea[@name="dummy|deep_nesting[source]"]');
     $this->assertEqual((string) $rows4[0]['rows'], 15);
     // Tests the HTML tags validation.
     \Drupal::state()->set('tmgmt.test_source_data', array('title' => array('deep_nesting' => array('#text' => '<p><em><strong>Source text bold and Italic</strong></em></p>', '#label' => 'Title')), 'body' => array('deep_nesting' => array('#text' => '<p><em><strong>Source body bold and Italic</strong></em></p>', '#label' => 'Body'))));
     $item4 = $job->addItem('test_source', 'test', 4);
     $this->drupalGet('admin/tmgmt/items/' . $item4->id());
     // Drop <strong> tag in translated text.
     $edit = array('title|deep_nesting[translation]' => '<em>Translated italic text missing paragraph</em>');
     $this->drupalPostForm(NULL, $edit, t('Validate HTML tags'));
     $this->assertText(t('Expected tags @tags not found.', array('@tags' => '<p>,<strong>,</strong>,</p>')));
     $this->assertText(t('@tag expected 1, found 0.', array('@tag' => '<p>')));
     $this->assertText(t('@tag expected 1, found 0.', array('@tag' => '<strong>')));
     $this->assertText(t('@tag expected 1, found 0.', array('@tag' => '</strong>')));
     $this->assertText(t('@tag expected 1, found 0.', array('@tag' => '</p>')));
     $this->assertText(t('HTML tag validation failed for 1 field(s).'));
     // Change the order of HTML tags.
     $edit = array('title|deep_nesting[translation]' => '<p><strong><em>Translated text Italic and bold</em></strong></p>');
     $this->drupalPostForm(NULL, $edit, t('Validate HTML tags'));
     $this->assertText(t('Order of the HTML tags are incorrect.'));
     $this->assertText(t('HTML tag validation failed for 1 field(s).'));
     // Add multiple tags incorrectly.
     $edit = array('title|deep_nesting[translation]' => '<p><p><p><p><strong><em><em>Translated text Italic and bold, many tags</em></strong></strong></strong></p>');
     $this->drupalPostForm(NULL, $edit, t('Validate HTML tags'));
     $this->assertText(t('@tag expected 1, found 4.', array('@tag' => '<p>')));
     $this->assertText(t('@tag expected 1, found 2.', array('@tag' => '<em>')));
     $this->assertText(t('@tag expected 1, found 3.', array('@tag' => '</strong>')));
     $this->assertText(t('HTML tag validation failed for 1 field(s).'));
     // Check validation errors for two fields.
     $edit = array('title|deep_nesting[translation]' => '<p><p><p><p><strong><em><em>Translated text Italic and bold, many tags</em></strong></strong></strong></p>', 'body|deep_nesting[translation]' => '<p>Source body bold and Italic</strong></em></p>');
     $this->drupalPostForm(NULL, $edit, t('Validate HTML tags'));
     $this->assertText(t('HTML tag validation failed for 2 field(s).'));
     // Tests that there is always a title.
     $text = '<p><em><strong>Source text bold and Italic</strong></em></p>';
     \Drupal::state()->set('tmgmt.test_source_data', ['title' => [['value' => ['#text' => $text, '#label' => 'Title', '#translate' => TRUE, '#format' => 'filtered_html']]], 'body' => ['deep_nesting' => ['#text' => $text, '#label' => 'Body', '#translate' => TRUE, '#format' => 'filtered_html']]]);
     $item5 = $job->addItem('test_source', 'test', 4);
     $this->drupalPostForm('admin/tmgmt/items/' . $item5->id(), [], t('Validate'));
     $this->assertText(t('The field is empty.'));
     // Test review just one data item.
     $edit = ['title|0|value[translation][value]' => $text . 'translated', 'body|deep_nesting[translation][value]' => $text . 'no save'];
     $this->drupalPostAjaxForm('admin/tmgmt/items/' . $item5->id(), $edit, 'reviewed-title|0|value');
     // Check if translation has been saved.
     $this->drupalGet('admin/tmgmt/items/' . $item5->id());
     $this->assertFieldByName('title|0|value[translation][value]', $text . 'translated');
     $this->assertNoFieldByName('body|deep_nesting[translation][value]', $text . 'no save');
     // Tests field is less than max_length.
     \Drupal::state()->set('tmgmt.test_source_data', ['title' => [['value' => ['#text' => $text, '#label' => 'Title', '#translate' => TRUE, '#max_length' => 10]]], 'body' => ['deep_nesting' => ['#text' => $text, '#label' => 'Body', '#translate' => TRUE, '#max_length' => 20]]]);
     $item5 = $job->addItem('test_source', 'test', 4);
     $this->drupalPostForm('admin/tmgmt/items/' . $item5->id(), ['title|0|value[translation]' => $text, 'body|deep_nesting[translation]' => $text], t('Save'));
     $this->assertText(t('The field has @size characters while the limit is @limit.', ['@size' => strlen($text), '@limit' => 10]));
     $this->assertText(t('The field has @size characters while the limit is @limit.', ['@size' => strlen($text), '@limit' => 20]));
     // Test if the validation is properly done.
     $this->drupalPostAjaxForm(NULL, [], 'reviewed-body|deep_nesting');
     $this->assertUniqueText(t('The field has @size characters while the limit is @limit.', ['@size' => strlen($text), '@limit' => 10]));
     // Test for the text with format set.
     \Drupal::state()->set('tmgmt.test_source_data', array('dummy' => array('deep_nesting' => array('#text' => 'Text for job item', '#label' => 'Label', '#format' => 'filtered_html'))));
     $item5 = $job->addItem('test_source', 'test', 5);
     $item5->active();
     $this->drupalGet('admin/tmgmt/jobs/' . $job->id());
     $this->assertText('The translation of test_source:test:1 to German is finished and can now be reviewed.');
     $this->clickLink(t('reviewed'));
     $this->assertText('Needs review');
     $this->assertText('Job item test_source:test:1');
     $edit = array('target_language' => 'de', 'settings[action]' => 'submit');
     $this->drupalPostForm('admin/tmgmt/jobs/' . $job->id(), $edit, t('Submit to provider'));
     $this->drupalGet('admin/tmgmt/items/' . $item5->id());
     $xpath = $this->xpath('//*[@id="edit-dummydeep-nesting-translation-format-guidelines"]/div')[0];
     $this->assertEqual($xpath[0]->h4[0], t('Filtered HTML'));
     $rows5 = $this->xpath('//textarea[@name="dummy|deep_nesting[source][value]"]');
     $this->assertEqual((string) $rows5[0]['rows'], 3);
     $this->drupalPostForm(NULL, [], t('Save'));
     $this->assertNoText('has been saved successfully.');
     $this->drupalGet('admin/tmgmt/items/' . $item5->id());
     $this->assertText('In progress');
     $edit = array('dummy|deep_nesting[translation][value]' => 'Translated text for job item');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('The translation for ' . trim($item5->label()) . ' has been saved successfully.');
     $this->drupalGet('admin/tmgmt/items/' . $item5->id());
     $this->assertText('Translated text for job item');
     $this->drupalPostForm(NULL, $edit, t('Save as completed'));
     $this->assertEqual(\Drupal::state()->get('tmgmt_test_saved_translation_' . $item5->getItemType() . '_' . $item5->getItemId())['dummy']['deep_nesting']['#translation']['#text'], 'Translated text for job item');
     // Test if the icons are displayed.
     $this->assertRaw('views-field-progress">Accepted');
     $this->assertRaw('icons/ready.svg" title="Needs review"');
     $this->loginAsAdmin();
     // Create two translators.
     $translator1 = $this->createTranslator();
     $translator2 = $this->createTranslator();
     $this->drupalGet('admin/tmgmt/jobs');
     // Assert that translators are in dropdown list.
     $this->assertOption('edit-translator', $translator1->id());
     $this->assertOption('edit-translator', $translator2->id());
     // Assign each job to a translator.
     $job1 = $this->createJob();
     $this->drupalGet('admin/tmgmt/jobs');
     $label = trim((string) $this->xpath('//table[@class="views-table views-view-table cols-10"]/tbody/tr')[0]->td[1]);
     $job2 = $this->createJob();
     $this->drupalGet('admin/tmgmt/jobs');
     $this->assertTrue($label, trim((string) $this->xpath('//table[@class="views-table views-view-table cols-10"]/tbody/tr')[0]->td[1]));
     $job1->set('translator', $translator1->id())->save();
     $job2->set('translator', $translator2->id())->save();
     // Test that progress bar is being displayed.
     $this->assertRaw('class="tmgmt-progress-pending" style="width: 50%"');
     // Filter jobs by translator and assert values.
     $this->drupalGet('admin/tmgmt/jobs', array('query' => array('translator' => $translator1->id())));
     $label = trim((string) $this->xpath('//table[@class="views-table views-view-table cols-10"]/tbody/tr')[0]->td[4]);
     $this->assertEqual($label, $translator1->label(), 'Found provider label in table');
     $this->assertNotEqual($label, $translator2->label(), "Providers filtered in table");
     $this->drupalGet('admin/tmgmt/jobs', array('query' => array('translator' => $translator2->id())));
     $label = trim((string) $this->xpath('//table[@class="views-table views-view-table cols-10"]/tbody/tr')[0]->td[4]);
     $this->assertEqual($label, $translator2->label(), 'Found provider label in table');
     $this->assertNotEqual($label, $translator1->label(), "Providers filtered in table");
     $edit = array('dummy|deep_nesting[translation]' => '');
     $this->drupalGet('admin/tmgmt/items/' . $item->id());
     $this->drupalPostForm(NULL, $edit, t('Validate'));
     $this->assertText(t('The field is empty.'));
     $this->drupalPostForm(NULL, [], t('Save'));
     $this->assertNoText(t('The field is empty.'));
     $this->drupalGet('admin/tmgmt/items/' . $item->id());
     $this->drupalPostForm(NULL, [], t('Save as completed'));
     $this->assertText(t('The field is empty.'));
     // Test validation message for 'Validate' button.
     $this->drupalGet('admin/tmgmt/items/' . $item->id());
     $translation_field = $this->randomMachineName();
     $edit = array('dummy|deep_nesting[translation]' => $translation_field);
     $this->drupalPostForm(NULL, $edit, t('Validate'));
     $this->assertText(t('Validation completed successfully.'), 'Message is correctly displayed.');
     // Test validation message for 'Validate HTML tags' button.
     $this->drupalPostForm(NULL, $edit, t('Validate HTML tags'));
     $this->assertText(t('Validation completed successfully.'), 'Message is correctly displayed.');
     // Test that normal job item are shown in job items overview.
     $this->drupalGet('admin/tmgmt/job_items', array('query' => array('state' => 'All')));
     $this->assertNoText($job1->label(), 'Normal job item is displayed on job items overview.');
     // Test that the legend is being displayed.
     $this->assertRaw('class="tmgmt-color-legend clearfix"');
     // Test that progress bar is being displayed.
     $this->assertRaw('class="tmgmt-progress-reviewed" style="width: 100%"');
 }
 /**
  * {@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;
 }
Example #14
0
 /**
  * Create a Suggestion-Table entry based on a Job and a title.
  *
  * @param array $result
  *   Suggestion array with the keys job_item, reason and from_item.
  *
  * @return array
  *   Options-Entry for a tableselect array.
  */
 function addSuggestionItem(array $result)
 {
     $item = $result['job_item'];
     $reason = isset($result['reason']) ? $result['reason'] : NULL;
     $option = array('title' => $item->label(), 'type' => $item->getSourceType(), 'words' => $item->getWordCount(), 'tags' => $item->getTagsCount(), 'reason' => $reason);
     if (!empty($result['from_item'])) {
         $from_item = JobItem::load($result['from_item']);
         if ($from_item) {
             $option['reason'] = t('%reason in %job', array('%reason' => $option['reason'], '%job' => $from_item->label()));
         }
     }
     return $option;
 }
 function testTranslationStatuses()
 {
     // Test statuses: Source, Missing.
     $this->drupalGet('admin/tmgmt/sources/content/node');
     $langstatus_en = $this->xpath('//table[@id="edit-items"]/tbody/tr[1]/td[@class="langstatus-en"]/img/@title');
     $langstatus_de = $this->xpath('//table[@id="edit-items"]/tbody/tr[1]/td[@class="langstatus-de"]/img/@title');
     $this->assertEqual($langstatus_en[0]['title'], t('Source language'));
     $this->assertEqual($langstatus_de[0]['title'], t('Not translated'));
     // Test status: Active job item.
     $job = $this->createJob('en', 'de');
     $job->translator = $this->default_translator->id();
     $job->settings = array();
     $job->save();
     $job->addItem('content', 'node', $this->nodes['article']['en'][0]->id());
     $job->requestTranslation();
     $this->drupalGet('admin/tmgmt/sources/content/node');
     $langstatus_de = $this->xpath('//table[@id="edit-items"]/tbody/tr[1]/td[@class="langstatus-de"]/a');
     $items = $job->getItems();
     $states = JobItem::getStates();
     $label = t('Active job item: @state', array('@state' => $states[reset($items)->getState()]));
     $this->assertEqual((string) $langstatus_de[0]['title'], $label);
     // Test status: Current
     foreach ($job->getItems() as $job_item) {
         $job_item->acceptTranslation();
     }
     $this->drupalGet('admin/tmgmt/sources/content/node');
     $langstatus_de = $this->xpath('//table[@id="edit-items"]/tbody/tr[1]/td[@class="langstatus-de"]/img/@title');
     $this->assertEqual($langstatus_de[0]['title'], t('Translation up to date'));
 }