/** * {@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']); }
/** * 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; }
/** * {@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; }
/** * {@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; }
/** * {@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; }
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')); }