| Code Coverage | ||||||||||
| Classes and Traits | Functions and Methods | Lines | ||||||||
| Total |  | 0.00% | 0 / 1 |  | 0.00% | 0 / 4 | CRAP |  | 0.00% | 0 / 166 | 
| TranslateEditForm |  | 0.00% | 0 / 1 |  | 0.00% | 0 / 4 | 992 |  | 0.00% | 0 / 166 | 
| getFormId |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 2 | |||
| buildForm |  | 0.00% | 0 / 1 | 182 |  | 0.00% | 0 / 109 | |||
| validateForm |  | 0.00% | 0 / 1 | 20 |  | 0.00% | 0 / 11 | |||
| submitForm |  | 0.00% | 0 / 1 | 182 |  | 0.00% | 0 / 44 | |||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\locale\Form\TranslateEditForm. | |
| */ | |
| namespace Drupal\locale\Form; | |
| use Drupal\Core\Form\FormStateInterface; | |
| use Drupal\Core\Render\Element; | |
| use Drupal\locale\SourceString; | |
| /** | |
| * Defines a translation edit form. | |
| */ | |
| class TranslateEditForm extends TranslateFormBase { | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getFormId() { | |
| return 'locale_translate_edit_form'; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function buildForm(array $form, FormStateInterface $form_state) { | |
| $filter_values = $this->translateFilterValues(); | |
| $langcode = $filter_values['langcode']; | |
| $this->languageManager->reset(); | |
| $languages = $this->languageManager->getLanguages(); | |
| $langname = isset($langcode) ? $languages[$langcode]->getName() : "- None -"; | |
| $form['#attached']['library'][] = 'locale/drupal.locale.admin'; | |
| $form['langcode'] = array( | |
| '#type' => 'value', | |
| '#value' => $filter_values['langcode'], | |
| ); | |
| $form['strings'] = array( | |
| '#type' => 'table', | |
| '#tree' => TRUE, | |
| '#language' => $langname, | |
| '#header' => [ | |
| $this->t('Source string'), | |
| $this->t('Translation for @language', ['@language' => $langname]), | |
| ], | |
| '#empty' => $this->t('No strings available.'), | |
| '#attributes' => ['class' => ['locale-translate-edit-table']], | |
| ); | |
| if (isset($langcode)) { | |
| $strings = $this->translateFilterLoadStrings(); | |
| $plurals = $this->getNumberOfPlurals($langcode); | |
| foreach ($strings as $string) { | |
| // Cast into source string, will do for our purposes. | |
| $source = new SourceString($string); | |
| // Split source to work with plural values. | |
| $source_array = $source->getPlurals(); | |
| $translation_array = $string->getPlurals(); | |
| if (count($source_array) == 1) { | |
| // Add original string value and mark as non-plural. | |
| $plural = FALSE; | |
| $form['strings'][$string->lid]['original'] = array( | |
| '#type' => 'item', | |
| '#title' => $this->t('Source string (@language)', array('@language' => $this->t('Built-in English'))), | |
| '#title_display' => 'invisible', | |
| '#plain_text' => $source_array[0], | |
| '#preffix' => '<span lang="en">', | |
| '#suffix' => '</span>', | |
| ); | |
| } | |
| else { | |
| // Add original string value and mark as plural. | |
| $plural = TRUE; | |
| $original_singular = [ | |
| '#type' => 'item', | |
| '#title' => $this->t('Singular form'), | |
| '#plain_text' => $source_array[0], | |
| '#prefix' => '<span class="visually-hidden">' . $this->t('Source string (@language)', array('@language' => $this->t('Built-in English'))) . '</span><span lang="en">', | |
| '#suffix' => '</span>', | |
| ]; | |
| $original_plural = [ | |
| '#type' => 'item', | |
| '#title' => $this->t('Plural form'), | |
| '#plain_text' => $source_array[1], | |
| '#preffix' => '<span lang="en">', | |
| '#suffix' => '</span>', | |
| ]; | |
| $form['strings'][$string->lid]['original'] = [ | |
| $original_singular, | |
| ['#markup' => '<br>'], | |
| $original_plural, | |
| ]; | |
| } | |
| if (!empty($string->context)) { | |
| $form['strings'][$string->lid]['original'][] = [ | |
| '#type' => 'inline_template', | |
| '#template' => '<br><small>{{ context_title }}: <span lang="en">{{ context }}</span></small>', | |
| '#context' => [ | |
| 'context_title' => $this->t('In Context'), | |
| 'context' => $string->context, | |
| ], | |
| ]; | |
| } | |
| // Approximate the number of rows to use in the default textarea. | |
| $rows = min(ceil(str_word_count($source_array[0]) / 12), 10); | |
| if (!$plural) { | |
| $form['strings'][$string->lid]['translations'][0] = array( | |
| '#type' => 'textarea', | |
| '#title' => $this->t('Translated string (@language)', array('@language' => $langname)), | |
| '#title_display' => 'invisible', | |
| '#rows' => $rows, | |
| '#default_value' => $translation_array[0], | |
| '#attributes' => array('lang' => $langcode), | |
| ); | |
| } | |
| else { | |
| // Add a textarea for each plural variant. | |
| for ($i = 0; $i < $plurals; $i++) { | |
| $form['strings'][$string->lid]['translations'][$i] = array( | |
| '#type' => 'textarea', | |
| // @todo Should use better labels https://www.drupal.org/node/2499639 | |
| '#title' => ($i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form')), | |
| '#rows' => $rows, | |
| '#default_value' => isset($translation_array[$i]) ? $translation_array[$i] : '', | |
| '#attributes' => array('lang' => $langcode), | |
| '#prefix' => $i == 0 ? ('<span class="visually-hidden">' . $this->t('Translated string (@language)', array('@language' => $langname)) . '</span>') : '', | |
| ); | |
| } | |
| if ($plurals == 2) { | |
| // Simplify interface text for the most common case. | |
| $form['strings'][$string->lid]['translations'][1]['#title'] = $this->t('Plural form'); | |
| } | |
| } | |
| } | |
| if (count(Element::children($form['strings']))) { | |
| $form['actions'] = array('#type' => 'actions'); | |
| $form['actions']['submit'] = array( | |
| '#type' => 'submit', | |
| '#value' => $this->t('Save translations'), | |
| ); | |
| } | |
| } | |
| $form['pager']['#type'] = 'pager'; | |
| return $form; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function validateForm(array &$form, FormStateInterface $form_state) { | |
| $langcode = $form_state->getValue('langcode'); | |
| foreach ($form_state->getValue('strings') as $lid => $translations) { | |
| foreach ($translations['translations'] as $key => $value) { | |
| if (!locale_string_is_safe($value)) { | |
| $form_state->setErrorByName("strings][$lid][translations][$key", $this->t('The submitted string contains disallowed HTML: %string', array('%string' => $value))); | |
| $form_state->setErrorByName("translations][$langcode][$key", $this->t('The submitted string contains disallowed HTML: %string', array('%string' => $value))); | |
| $this->logger('locale')->warning('Attempted submission of a translation string with disallowed HTML: %string', array('%string' => $value)); | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function submitForm(array &$form, FormStateInterface $form_state) { | |
| $langcode = $form_state->getValue('langcode'); | |
| $updated = array(); | |
| // Preload all translations for strings in the form. | |
| $lids = array_keys($form_state->getValue('strings')); | |
| $existing_translation_objects = array(); | |
| foreach ($this->localeStorage->getTranslations(array('lid' => $lids, 'language' => $langcode, 'translated' => TRUE)) as $existing_translation_object) { | |
| $existing_translation_objects[$existing_translation_object->lid] = $existing_translation_object; | |
| } | |
| foreach ($form_state->getValue('strings') as $lid => $new_translation) { | |
| $existing_translation = isset($existing_translation_objects[$lid]); | |
| // Plural translations are saved in a delimited string. To be able to | |
| // compare the new strings with the existing strings a string in the same | |
| // format is created. | |
| $new_translation_string_delimited = implode(LOCALE_PLURAL_DELIMITER, $new_translation['translations']); | |
| // Generate an imploded string without delimiter, to be able to run | |
| // empty() on it. | |
| $new_translation_string = implode('', $new_translation['translations']); | |
| $is_changed = FALSE; | |
| if ($existing_translation && $existing_translation_objects[$lid]->translation != $new_translation_string_delimited) { | |
| // If there is an existing translation in the DB and the new translation | |
| // is not the same as the existing one. | |
| $is_changed = TRUE; | |
| } | |
| elseif (!$existing_translation && !empty($new_translation_string)) { | |
| // Newly entered translation. | |
| $is_changed = TRUE; | |
| } | |
| if ($is_changed) { | |
| // Only update or insert if we have a value to use. | |
| $target = isset($existing_translation_objects[$lid]) ? $existing_translation_objects[$lid] : $this->localeStorage->createTranslation(array('lid' => $lid, 'language' => $langcode)); | |
| $target->setPlurals($new_translation['translations']) | |
| ->setCustomized() | |
| ->save(); | |
| $updated[] = $target->getId(); | |
| } | |
| if (empty($new_translation_string) && isset($existing_translation_objects[$lid])) { | |
| // Empty new translation entered: remove existing entry from database. | |
| $existing_translation_objects[$lid]->delete(); | |
| $updated[] = $lid; | |
| } | |
| } | |
| drupal_set_message($this->t('The strings have been saved.')); | |
| // Keep the user on the current pager page. | |
| $page = $this->getRequest()->query->get('page'); | |
| if (isset($page)) { | |
| $form_state->setRedirect( | |
| 'locale.translate_page', | |
| array(), | |
| array('page' => $page) | |
| ); | |
| } | |
| if ($updated) { | |
| // Clear cache and force refresh of JavaScript translations. | |
| _locale_refresh_translations(array($langcode), $updated); | |
| _locale_refresh_configuration(array($langcode), $updated); | |
| } | |
| } | |
| } |