/** * {@inheritdoc} */ public function getFormElement(DataDefinitionInterface $definition, LanguageInterface $language, $value) { // Estimate a comfortable size of the input textarea. $rows_words = ceil(str_word_count($value) / 5); $rows_newlines = substr_count($value, "\n") + 1; $rows = max($rows_words, $rows_newlines); return array('#type' => 'textarea', '#default_value' => $value, '#title' => $this->t($definition->getLabel()) . '<span class="visually-hidden"> (' . $language->getName() . ')</span>', '#rows' => $rows, '#attributes' => array('lang' => $language->getId())); }
/** * {@inheritdoc} */ protected function getTranslationElement(LanguageInterface $translation_language, $source_config, $translation_config) { $plurals = $this->getNumberOfPlurals($translation_language->getId()); $values = explode(LOCALE_PLURAL_DELIMITER, $translation_config); $element = array('#type' => 'fieldset', '#title' => SafeMarkup::format('@label <span class="visually-hidden">(@translation_language)</span>', array('@label' => $this->t($this->definition->getLabel()), '@translation_language' => $translation_language->getName())), '#tree' => TRUE); for ($i = 0; $i < $plurals; $i++) { $element[$i] = array('#type' => 'textfield', '#title' => $i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form'), '#default_value' => isset($values[$i]) ? $values[$i] : '', '#attributes' => array('lang' => $translation_language->getId())); } return $element; }
/** * Formats configuration schema as a form tree. * * @param \Drupal\Core\Config\Schema\Element $schema * Schema definition of configuration. * @param array|string $config_data * Configuration object of requested language, a string when done traversing * the data building each sub-structure for the form. * @param array|string $base_config_data * Configuration object of base language, a string when done traversing * the data building each sub-structure for the form. * @param bool $open * (optional) Whether or not the details element of the form should be open. * Defaults to TRUE. * @param string|null $base_key * (optional) Base configuration key. Defaults to an empty string. * * @return array * An associative array containing the structure of the form. */ protected function buildConfigForm(Element $schema, $config_data, $base_config_data, $open = TRUE, $base_key = '') { $build = array(); foreach ($schema as $key => $element) { // Make the specific element key, "$base_key.$key". $element_key = implode('.', array_filter(array($base_key, $key))); $definition = $element->getDataDefinition(); if (!$definition->getLabel()) { $definition->setLabel($this->t('N/A')); } if ($element instanceof Element) { // Build sub-structure and include it with a wrapper in the form // if there are any translatable elements there. $sub_build = $this->buildConfigForm($element, $config_data[$key], $base_config_data[$key], FALSE, $element_key); if (!empty($sub_build)) { // For some configuration elements the same element structure can // repeat multiple times, (like views displays, filters, etc.). // So try to find a more usable title for the details summary. First // check if there is an element which is called title or label, then // check if there is an element which contains these words. $title = ''; if (isset($sub_build['title']['source'])) { $title = $sub_build['title']['source']['#markup']; } elseif (isset($sub_build['label']['source'])) { $title = $sub_build['label']['source']['#markup']; } else { foreach (array_keys($sub_build) as $title_key) { if (isset($sub_build[$title_key]['source']) && (strpos($title_key, 'title') !== FALSE || strpos($title_key, 'label') !== FALSE)) { $title = $sub_build[$title_key]['source']['#markup']; break; } } } $build[$key] = array('#type' => 'details', '#title' => (!empty($title) ? strip_tags($title) . ' ' : '') . $this->t($definition['label']), '#open' => $open) + $sub_build; } } else { $definition = $element->getDataDefinition(); // Create form element only for translatable items. if (!isset($definition['translatable']) || !isset($definition['type'])) { continue; } $value = $config_data[$key]; $build[$element_key] = array('#theme' => 'config_translation_manage_form_element'); $build[$element_key]['source'] = array('#markup' => $base_config_data[$key] ? '<span lang="' . $this->sourceLanguage->getId() . '">' . nl2br($base_config_data[$key] . '</span>') : t('(Empty)'), '#title' => $this->t('!label <span class="visually-hidden">(!source_language)</span>', array('!label' => $this->t($definition['label']), '!source_language' => $this->sourceLanguage->getName())), '#type' => 'item'); if (!isset($definition['form_element_class'])) { $definition['form_element_class'] = '\\Drupal\\config_translation\\FormElement\\Textfield'; } /** @var \Drupal\config_translation\FormElement\ElementInterface $form_element */ $form_element = new $definition['form_element_class'](); $build[$element_key]['translation'] = $form_element->getFormElement($definition, $this->language, $value); } } return $build; }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { foreach ($this->mapper->getConfigNames() as $name) { $this->languageManager->getLanguageConfigOverride($this->language->getId(), $name)->delete(); } // Flush all persistent caches. $this->moduleHandler->invokeAll('cache_flush'); foreach (Cache::getBins() as $cache_backend) { $cache_backend->deleteAll(); } drupal_set_message($this->t('@language translation of %label was deleted', array('%label' => $this->mapper->getTitle(), '@language' => $this->language->getName()))); $form_state->setRedirectUrl($this->getCancelUrl()); }
/** * Returns the translation form element for a given configuration definition. * * For complex data structures (such as mappings) that are translatable * wholesale but contain non-translatable properties, the form element is * responsible for checking access to the source value of those properties. In * case of formatted text, for example, access to the source text format must * be checked. If the translator does not have access to the text format, the * textarea must be disabled and the translator may not be able to translate * this particular configuration element. If the translator does have access * to the text format, the element must be locked down to that particular text * format; in other words, the format may not be changed by the translator * (because the text format property is not itself translatable). * * In addition, the form element is responsible for checking whether the * value of such non-translatable properties in the translated configuration * is equal to the corresponding source values. If not, that means that the * source value has changed after the translation was added. In this case - * again - the translation of this element must be disabled if the translator * does not have access to the source value of the non-translatable property. * For example, if a formatted text element, whose source format was plain * text when it was first translated, gets changed to the Full HTML format, * simply changing the format of the translation would lead to an XSS * vulnerability as the translated text, that was intended to be escaped, * would now be displayed unescaped. Thus, if the translator does not have * access to the Full HTML format, the translation for this particular element * may not be updated at all (the textarea must be disabled). Only if access * to the Full HTML format is granted, an explicit translation taking into * account the updated source value(s) may be submitted. * * In the specific case of formatted text this logic is implemented by * utilizing a form element of type 'text_format' and its #format and * #allowed_formats properties. The access logic explained above is then * handled by the 'text_format' element itself, specifically by * filter_process_format(). In case such a rich element is not available for * translation of complex data, similar access logic must be implemented * manually. * * @param \Drupal\Core\Language\LanguageInterface $translation_language * The language to display the translation form for. * @param mixed $source_config * The configuration value of the element in the source language. * @param mixed $translation_config * The configuration value of the element in the language to translate to. * * @return array * Form API array to represent the form element. * * @see \Drupal\config_translation\FormElement\TextFormat * @see filter_process_format() */ protected function getTranslationElement(LanguageInterface $translation_language, $source_config, $translation_config) { // Add basic properties that apply to all form elements. return array('#title' => $this->t('@label <span class="visually-hidden">(@source_language)</span>', array('@label' => $this->definition['label'], '@source_language' => $translation_language->getName())), '#default_value' => $translation_config, '#attributes' => array('lang' => $translation_language->getId())); }
/** * {@inheritdoc} */ public function getFormElement(DataDefinitionInterface $definition, LanguageInterface $language, $value) { return array('#type' => 'textfield', '#default_value' => $value, '#title' => $this->t($definition->getLabel()) . '<span class="visually-hidden"> (' . $language->getName() . ')</span>', '#attributes' => array('lang' => $language->getId())); }
/** * {@inheritdoc} */ public function getQuestion() { return $this->t('Are you sure you want to delete the @language translation of %label?', array('@language' => $this->language->getName(), '%label' => $this->entity->label())); }
/** * Returns the translation form element for a given configuration definition. * * For complex data structures (such as mappings) that are translatable * wholesale but contain non-translatable properties, the form element is * responsible for checking access to the source value of those properties. In * case of formatted text, for example, access to the source text format must * be checked. If the translator does not have access to the text format, the * textarea must be disabled and the translator may not be able to translate * this particular configuration element. If the translator does have access * to the text format, the element must be locked down to that particular text * format; in other words, the format may not be changed by the translator * (because the text format property is not itself translatable). * * In addition, the form element is responsible for checking whether the * value of such non-translatable properties in the translated configuration * is equal to the corresponding source values. If not, that means that the * source value has changed after the translation was added. In this case - * again - the translation of this element must be disabled if the translator * does not have access to the source value of the non-translatable property. * For example, if a formatted text element, whose source format was plain * text when it was first translated, gets changed to the Full HTML format, * simply changing the format of the translation would lead to an XSS * vulnerability as the translated text, that was intended to be escaped, * would now be displayed unescaped. Thus, if the translator does not have * access to the Full HTML format, the translation for this particular element * may not be updated at all (the textarea must be disabled). Only if access * to the Full HTML format is granted, an explicit translation taking into * account the updated source value(s) may be submitted. * * In the specific case of formatted text this logic is implemented by * utilizing a form element of type 'text_format' and its #format and * #allowed_formats properties. The access logic explained above is then * handled by the 'text_format' element itself, specifically by * filter_process_format(). In case such a rich element is not available for * translation of complex data, similar access logic must be implemented * manually. * * @param \Drupal\Core\Language\LanguageInterface $translation_language * The language to display the translation form for. * @param mixed $source_config * The configuration value of the element in the source language. * @param mixed $translation_config * The configuration value of the element in the language to translate to. * * @return array * Form API array to represent the form element. * * @see \Drupal\config_translation\FormElement\TextFormat * @see filter_process_format() */ protected function getTranslationElement(LanguageInterface $translation_language, $source_config, $translation_config) { // Add basic properties that apply to all form elements. // @todo Should support singular+plurals https://www.drupal.org/node/2454829 return array('#title' => $this->t('!label <span class="visually-hidden">(!source_language)</span>', array('!label' => $this->t($this->definition['label']), '!source_language' => $translation_language->getName())), '#default_value' => $translation_config, '#attributes' => array('lang' => $translation_language->getId())); }
/** * {@inheritdoc} */ public function getFormElement(DataDefinitionInterface $definition, LanguageInterface $language, $value) { $description = $this->t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://php.net/manual/function.date.php')); $format = $this->t('Displayed as %date_format', array('%date_format' => \Drupal::service('date.formatter')->format(REQUEST_TIME, 'custom', $value))); return array('#type' => 'textfield', '#title' => $this->t($definition->getLabel()) . '<span class="visually-hidden"> (' . $language->getName() . ')</span>', '#description' => $description, '#default_value' => $value, '#attributes' => array('lang' => $language->getId()), '#field_suffix' => ' <div class="edit-date-format-suffix"><small id="edit-date-format-suffix">' . $format . '</small></div>', '#ajax' => array('callback' => 'Drupal\\config_translation\\FormElement\\DateFormat::ajaxSample', 'event' => 'keyup', 'progress' => array('type' => 'throbber', 'message' => NULL))); }