diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php index e039341..5298c35 100644 --- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php @@ -122,25 +122,25 @@ function testUILanguageNegotiation() { 'string' => $default_string, 'langcode' => $langcode_browser_fallback, ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $textarea = current($this->xpath('//textarea')); $lid = (string) $textarea[0]['name']; $edit = array( $lid => $language_browser_fallback_string, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); $search = array( 'string' => $default_string, 'langcode' => $langcode, ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $textarea = current($this->xpath('//textarea')); $lid = (string) $textarea[0]['name']; $edit = array( $lid => $language_string, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); // Configure URL language rewrite. variable_set('language_negotiation_url_type', Language::TYPE_INTERFACE); diff --git a/core/modules/locale/lib/Drupal/locale/Controller/LocaleController.php b/core/modules/locale/lib/Drupal/locale/Controller/LocaleController.php index 71bbd6c..72b9ba6 100644 --- a/core/modules/locale/lib/Drupal/locale/Controller/LocaleController.php +++ b/core/modules/locale/lib/Drupal/locale/Controller/LocaleController.php @@ -9,8 +9,11 @@ use Drupal\Core\Controller\ControllerInterface; use Drupal\Core\Routing\UrlGeneratorInterface; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\locale\Form\TranslateEditForm; +use Drupal\locale\Form\TranslateFilterForm; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; + /** * Return response for manual check translations. */ @@ -24,14 +27,26 @@ class LocaleController implements ControllerInterface { protected $moduleHandler; /** + * The container. + * + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + protected $container; + + /** * Constructs a \Drupal\locale\Controller\LocaleController object. * * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. + * @param \Drupal\Core\Routing\PathBasedGeneratorInterface $url_generator + * The URL generator service. + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * The service container this object should use. */ public function __construct(ModuleHandlerInterface $module_handler, UrlGeneratorInterface $url_generator) { $this->moduleHandler = $module_handler; $this->urlGenerator = $url_generator; + $this->container = $container; } /** @@ -40,7 +55,8 @@ public function __construct(ModuleHandlerInterface $module_handler, UrlGenerator public static function create(ContainerInterface $container) { return new static( $container->get('module_handler'), - $container->get('url_generator') + $container->get('url_generator'), + $container ); } @@ -69,4 +85,16 @@ public function checkTranslation() { return new RedirectResponse($this->urlGenerator->generateFromPath('admin/reports/translations', array('absolute' => TRUE))); } + + /** + * Shows the string search screen. + * + * @see locale_menu() + */ + public function translatePage() { + return array( + 'filter' => drupal_get_form(TranslateFilterForm::create($this->container)), + 'form' => drupal_get_form(TranslateEditForm::create($this->container)), + ); + } } diff --git a/core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php b/core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php new file mode 100644 index 0000000..15541fe --- /dev/null +++ b/core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php @@ -0,0 +1,308 @@ +state = $state; + } + + /** + * Instantiates a new instance of this form. + * + * This is a factory method that returns a new instance of this object. The + * factory should pass any needed dependencies into the constructor of this + * object, but not the container itself. Every call to this method must return + * a new instance of this object; that is, it may not implement a singleton. + * + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * The service container this object should use. + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('locale.storage'), + $container->get('request'), + $container->get('string_translation'), + $container->get('keyvalue')->get('state') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormID() { + return 'locale_translate_edit_form'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $filter_values = $this->translateFilterValues($this->request); + $langcode = $filter_values['langcode']; + + drupal_static_reset('language_list'); + $languages = language_list(); + + $langname = isset($langcode) ? $languages[$langcode]->name : "- None -"; + + $path = drupal_get_path('module', 'locale'); + $form['#attached']['css'] = array( + $path . '/css/locale.admin.css', + ); + $form['#attached']['library'][] = array('locale', 'drupal.locale.admin'); + + $form['langcode'] = array( + '#type' => 'value', + '#value' => $filter_values['langcode'], + ); + + $form['strings'] = array( + '#type' => 'item', + '#tree' => TRUE, + '#language' => $langname, + '#theme' => 'locale_translate_edit_form_strings', + ); + + if (isset($langcode)) { + $strings = $this->translateFilterLoadStrings($this->request); + + $plural_formulas = $this->state->get('locale.translation.plurals') ?: array(); + + 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. + $form['strings'][$string->lid]['plural'] = array( + '#type' => 'value', + '#value' => 0, + ); + $form['strings'][$string->lid]['original'] = array( + '#type' => 'item', + '#title' => $this->translationManager->translate('Source string (@language)', array('@language' => $this->translationManager->translate('Built-in English'))), + '#title_display' => 'invisible', + '#markup' => '' . String::checkPlain($source_array[0]) . '', + ); + } + else { + // Add original string value and mark as plural. + $form['strings'][$string->lid]['plural'] = array( + '#type' => 'value', + '#value' => 1, + ); + $form['strings'][$string->lid]['original_singular'] = array( + '#type' => 'item', + '#title' => $this->translationManager->translate('Singular form'), + '#markup' => '' . String::checkPlain($source_array[0]) . '', + '#prefix' => '' . $this->translationManager->translate('Source string (@language)', array('@language' => $this->translationManager->translate('Built-in English'))) . '' + ); + $form['strings'][$string->lid]['original_plural'] = array( + '#type' => 'item', + '#title' => $this->translationManager->translate('Plural form'), + '#markup' => '' . String::checkPlain($source_array[1]) . '', + ); + } + if (!empty($string->context)) { + $form['strings'][$string->lid]['context'] = array( + '#type' => 'value', + '#value' => '' . String::checkPlain($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 (empty($form['strings'][$string->lid]['plural']['#value'])) { + $form['strings'][$string->lid]['translations'][0] = array( + '#type' => 'textarea', + '#title' => $this->translationManager->translate('Translated string (@language)', array('@language' => $langname)), + '#title_display' => 'invisible', + '#rows' => $rows, + '#default_value' => $translation_array[0], + '#attributes' => array('lang' => $langcode), + ); + } + else { + // Dealing with plural strings. + if (isset($plural_formulas[$langcode]['plurals']) && $plural_formulas[$langcode]['plurals'] > 2) { + // Add a textarea for each plural variant. + for ($i = 0; $i < $plural_formulas[$langcode]['plurals']; $i++) { + $form['strings'][$string->lid]['translations'][$i] = array( + '#type' => 'textarea', + '#title' => ($i == 0 ? $this->translationManager->translate('Singular form') : format_plural($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 ? ('' . $this->translationManager->translate('Translated string (@language)', array('@language' => $langname)) . '') : '', + ); + } + } + else { + // Fallback for unknown number of plurals. + $form['strings'][$string->lid]['translations'][0] = array( + '#type' => 'textarea', + '#title' => $this->translationManager->translate('Singular form'), + '#rows' => $rows, + '#default_value' => $translation_array[0], + '#attributes' => array('lang' => $langcode), + '#prefix' => '' . $this->translationManager->translate('Translated string (@language)', array('@language' => $langname)) . '', + ); + $form['strings'][$string->lid]['translations'][1] = array( + '#type' => 'textarea', + '#title' => $this->translationManager->translate('Plural form'), + '#rows' => $rows, + '#default_value' => isset($translation_array[1]) ? $translation_array[1] : '', + '#attributes' => array('lang' => $langcode), + ); + } + } + } + if (count(element_children($form['strings']))) { + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => $this->translationManager->translate('Save translations'), + ); + } + } + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + $langcode = $form_state['values']['langcode']; + foreach ($form_state['values']['strings'] as $lid => $translations) { + foreach ($translations['translations'] as $key => $value) { + if (!locale_string_is_safe($value)) { + form_set_error("strings][$lid][translations][$key", $this->translationManager->translate('The submitted string contains disallowed HTML: %string', array('%string' => $value))); + form_set_error("translations][$langcode][$key", $this->translationManager->translate('The submitted string contains disallowed HTML: %string', array('%string' => $value))); + watchdog('locale', 'Attempted submission of a translation string with disallowed HTML: %string', array('%string' => $value), WATCHDOG_WARNING); + } + } + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state, Request $request = NULL) { + $langcode = $form_state['values']['langcode']; + $updated = array(); + + // Preload all translations for strings in the form. + $lids = array_keys($form_state['values']['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['values']['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->translationManager->translate('The strings have been saved.')); + + // Keep the user on the current pager page. + $page = $this->request->query->get('page'); + if (isset($page)) { + $form_state['redirect'] = array('admin/config/regional/translate', array('query' => 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); + } + } + +} diff --git a/core/modules/locale/lib/Drupal/locale/Form/TranslateFilterForm.php b/core/modules/locale/lib/Drupal/locale/Form/TranslateFilterForm.php new file mode 100644 index 0000000..07ed4d7 --- /dev/null +++ b/core/modules/locale/lib/Drupal/locale/Form/TranslateFilterForm.php @@ -0,0 +1,112 @@ +translateFilters(); + $filter_values = $this->translateFilterValues($this->request); + + $form['#attached']['css'] = array( + drupal_get_path('module', 'locale') . '/css/locale.admin.css', + ); + + $form['filters'] = array( + '#type' => 'details', + '#title' => t('Filter translatable strings'), + '#collapsed' => FALSE, + ); + foreach ($filters as $key => $filter) { + // Special case for 'string' filter. + if ($key == 'string') { + $form['filters']['status']['string'] = array( + '#type' => 'search', + '#title' => $filter['title'], + '#description' => $filter['description'], + '#default_value' => $filter_values[$key], + ); + } + else { + $empty_option = isset($filter['options'][$filter['default']]) ? $filter['options'][$filter['default']] : '- None -'; + $form['filters']['status'][$key] = array( + '#title' => $filter['title'], + '#type' => 'select', + '#empty_value' => $filter['default'], + '#empty_option' => $empty_option, + '#size' => 0, + '#options' => $filter['options'], + '#default_value' => $filter_values[$key], + ); + if (isset($filter['states'])) { + $form['filters']['status'][$key]['#states'] = $filter['states']; + } + } + } + + $form['filters']['actions'] = array( + '#type' => 'actions', + '#attributes' => array('class' => array('container-inline')), + ); + $form['filters']['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Filter'), + ); + if (!empty($_SESSION['locale_translate_filter'])) { + $form['filters']['actions']['reset'] = array( + '#type' => 'submit', + '#value' => t('Reset'), + ); + } + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $op = $form_state['values']['op']; + $filters = $this->translateFilters(); + switch ($op) { + case $this->translationManager->translate('Filter'): + foreach ($filters as $name => $filter) { + if (isset($form_state['values'][$name])) { + $_SESSION['locale_translate_filter'][$name] = $form_state['values'][$name]; + } + } + break; + + case $this->translationManager->translate('Reset'): + $_SESSION['locale_translate_filter'] = array(); + break; + } + + $form_state['redirect'] = 'admin/config/regional/translate'; + } + +} diff --git a/core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php b/core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php new file mode 100644 index 0000000..dabac99 --- /dev/null +++ b/core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php @@ -0,0 +1,232 @@ +localeStorage = $locale_storage; + $this->request = $request; + $this->translationManager = $translation_manager; + } + + /** + * Instantiates a new instance of this form. + * + * This is a factory method that returns a new instance of this object. The + * factory should pass any needed dependencies into the constructor of this + * object, but not the container itself. Every call to this method must return + * a new instance of this object; that is, it may not implement a singleton. + * + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * The service container this object should use. + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('locale.storage'), + $container->get('request'), + $container->get('string_translation') + ); + } + + /** + * Builds a string search query and returns an array of string objects. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request object. + * + * @return array + * Array of \Drupal\locale\TranslationString objects. + */ + protected function translateFilterLoadStrings(Request $request) { + $filter_values = $this->translateFilterValues($request); + + // Language is sanitized to be one of the possible options in + // translateFilterValues(). + $conditions = array('language' => $filter_values['langcode']); + $options = array('pager limit' => 30, 'translated' => TRUE, 'untranslated' => TRUE); + + // Add translation status conditions and options. + switch ($filter_values['translation']) { + case 'translated': + $conditions['translated'] = TRUE; + if ($filter_values['customized'] != 'all') { + $conditions['customized'] = $filter_values['customized']; + } + break; + + case 'untranslated': + $conditions['translated'] = FALSE; + break; + + } + + if (!empty($filter_values['string'])) { + $options['filters']['source'] = $filter_values['string']; + if ($options['translated']) { + $options['filters']['translation'] = $filter_values['string']; + } + } + + return $this->localeStorage->getTranslations($conditions, $options); + } + + /** + * Builds an array out of search criteria specified in request variables. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request object. + * + * @return array $filter_values + * The filter values. + */ + protected function translateFilterValues(Request $request, $reset=FALSE) { + if (!$reset && static::$filter_values) { + return static::$filter_values; + } + + $filter_values = array(); + $filters = $this->translateFilters(); + foreach ($filters as $key => $filter) { + $filter_values[$key] = $filter['default']; + // Let the filter defaults be overwritten by parameters in the URL. + if ($request->query->has($key)) { + // Only allow this value if it was among the options, or + // if there were no fixed options to filter for. + $value = $request->query->get($key); + if (!isset($filter['options']) || isset($filter['options'][$value])) { + $filter_values[$key] = $value; + } + } + elseif (isset($_SESSION['locale_translate_filter'][$key])) { + // Only allow this value if it was among the options, or + // if there were no fixed options to filter for. + if (!isset($filter['options']) || isset($filter['options'][$_SESSION['locale_translate_filter'][$key]])) { + $filter_values[$key] = $_SESSION['locale_translate_filter'][$key]; + } + } + } + + return static::$filter_values = $filter_values; + } + + /** + * List locale translation filters that can be applied. + */ + protected function translateFilters() { + $filters = array(); + + // Get all languages, except English. + drupal_static_reset('language_list'); + $languages = language_list(); + $language_options = array(); + foreach ($languages as $langcode => $language) { + if ($langcode != 'en' || locale_translate_english()) { + $language_options[$langcode] = $language->name; + } + } + + // Pick the current interface language code for the filter. + $default_langcode = language(Language::TYPE_INTERFACE)->id; + if (!isset($language_options[$default_langcode])) { + $available_langcodes = array_keys($language_options); + $default_langcode = array_shift($available_langcodes); + } + + $filters['string'] = array( + 'title' => $this->translationManager->translate('String contains'), + 'description' => $this->translationManager->translate('Leave blank to show all strings. The search is case sensitive.'), + 'default' => '', + ); + + $filters['langcode'] = array( + 'title' => $this->translationManager->translate('Translation language'), + 'options' => $language_options, + 'default' => $default_langcode, + ); + + $filters['translation'] = array( + 'title' => $this->translationManager->translate('Search in'), + 'options' => array( + 'all' => $this->translationManager->translate('Both translated and untranslated strings'), + 'translated' => $this->translationManager->translate('Only translated strings'), + 'untranslated' => $this->translationManager->translate('Only untranslated strings'), + ), + 'default' => 'all', + ); + + $filters['customized'] = array( + 'title' => $this->translationManager->translate('Translation type'), + 'options' => array( + 'all' => $this->translationManager->translate('All'), + LOCALE_NOT_CUSTOMIZED => $this->translationManager->translate('Non-customized translation'), + LOCALE_CUSTOMIZED => $this->translationManager->translate('Customized translation'), + ), + 'states' => array( + 'visible' => array( + ':input[name=translation]' => array('value' => 'translated'), + ), + ), + 'default' => 'all', + ); + + return $filters; + } + +} diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php index aa53fbb..8b825d0 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php @@ -69,14 +69,14 @@ function testConfigTranslation() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $textareas = $this->xpath('//textarea'); $textarea = current($textareas); $lid = (string) $textarea[0]['name']; $edit = array( $lid => $site_name, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); $wrapper = $this->container->get('locale.config.typed')->get('system.site'); @@ -115,13 +115,13 @@ function testConfigTranslation() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $textarea = current($this->xpath('//textarea')); $lid = (string) $textarea[0]['name']; $edit = array( $lid => $image_style_label, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); // Check the right single translation has been created. $translations = $this->storage->getTranslations(array('language' => $langcode, 'type' => 'configuration', 'name' => 'image.style.medium')); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php index f8fb4c4..c301fef 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php @@ -111,7 +111,7 @@ function testStandalonePoFile() { 'langcode' => 'fr', 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), 'String not overwritten by imported string.'); // This import should not have changed number of plural forms. @@ -133,7 +133,7 @@ function testStandalonePoFile() { 'langcode' => 'fr', 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertNoText(t('No strings available.'), 'String overwritten by imported string.'); // This import should have changed number of plural forms. $locale_plurals = \Drupal::state()->get('locale.translation.plurals') ?: array(); @@ -169,7 +169,7 @@ function testStandalonePoFile() { 'langcode' => 'fr', 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), 'Customized string not overwritten by imported string.'); // Try importing a .po file with overriding strings, and ensure existing @@ -188,7 +188,7 @@ function testStandalonePoFile() { 'langcode' => 'fr', 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertNoText(t('No strings available.'), 'Customized string overwritten by imported string.'); } @@ -233,7 +233,7 @@ function testEmptyMsgstr() { 'langcode' => $langcode, 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText($str, 'Search found the string as untranslated.'); } @@ -287,7 +287,7 @@ function testConfigPoFile() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText($config_string[1], format_string('Translation of @string found.', array('@string' => $config_string[0]))); } diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php index 15a1c55..25b6922 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php @@ -198,7 +198,7 @@ function testPluralEditExport() { $search = array( 'langcode' => 'fr', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); // Plural values for the langcode fr. $this->assertText('@count heure'); $this->assertText('@count heures'); @@ -221,7 +221,7 @@ function testPluralEditExport() { 'string' => '1 day', 'langcode' => 'fr', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); // Save complete translations for the string in langcode fr. $edit = array( @@ -235,7 +235,7 @@ function testPluralEditExport() { 'string' => '1 day', 'langcode' => 'hr', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $edit = array( "strings[$lid][translations][0]" => '@count dan', diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php index e391022..9527adc 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationUiTest.php @@ -39,7 +39,7 @@ function testEnglishTranslation() { $this->drupalLogin($admin_user); $this->drupalPost('admin/config/regional/language/edit/en', array('locale_translate_english' => TRUE), t('Save language')); - $this->assertLinkByHref('/admin/config/regional/translate/translate?langcode=en', 0, 'Enabled interface translation to English.'); + $this->assertLinkByHref('/admin/config/regional/translate?langcode=en', 0, 'Enabled interface translation to English.'); } /** @@ -87,7 +87,7 @@ function testStringTranslation() { 'langcode' => $langcode, 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText($name, 'Search found the string as untranslated.'); // Assume this is the only result, given the random name. @@ -105,7 +105,7 @@ function testStringTranslation() { $this->drupalPost('admin/config/regional/language/edit/en', array('locale_translate_english' => TRUE), t('Save language')); $this->drupalLogout(); $this->drupalLogin($translate_user); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText($name, 'Search found the string as untranslated.'); // Assume this is the only result, given the random name. @@ -114,15 +114,15 @@ function testStringTranslation() { $edit = array( $lid => $translation, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); $this->assertText(t('The strings have been saved.'), 'The strings have been saved.'); - $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), 'Correct page redirection.'); + $this->assertEqual($this->getUrl(), url('admin/config/regional/translate', array('absolute' => TRUE)), 'Correct page redirection.'); $search = array( 'string' => $name, 'langcode' => $langcode, 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertRaw($translation, 'Non-English translation properly saved.'); @@ -131,19 +131,19 @@ function testStringTranslation() { 'langcode' => 'en', 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $textarea = current($this->xpath('//textarea')); $lid = (string) $textarea[0]['name']; $edit = array( $lid => $translation_to_en, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); $search = array( 'string' => $name, 'langcode' => 'en', 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertRaw($translation_to_en, 'English translation properly saved.'); // Reset the tag cache on the tester side in order to pick up the call to @@ -164,7 +164,7 @@ function testStringTranslation() { 'langcode' => 'en', 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), 'String is translated.'); $this->drupalLogout(); @@ -190,14 +190,14 @@ function testStringTranslation() { 'langcode' => 'en', 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); // Assume this is the only result, given the random name. $textarea = current($this->xpath('//textarea')); $lid = (string) $textarea[0]['name']; $edit = array( $lid => '', ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); $this->assertRaw($name, 'The strings have been saved.'); $this->drupalLogin($translate_user); $search = array( @@ -205,7 +205,7 @@ function testStringTranslation() { 'langcode' => 'en', 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertNoText(t('No strings available.'), 'The translation has been removed'); } @@ -248,14 +248,14 @@ function testJavaScriptTranslation() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $textarea = current($this->xpath('//textarea')); $lid = (string) $textarea[0]['name']; $edit = array( $lid => $this->randomName(), ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); // Trigger JavaScript translation parsing and building. _locale_rebuild_js($langcode); @@ -311,7 +311,7 @@ function testStringValidation() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); // Find the edit path. $textarea = current($this->xpath('//textarea')); @@ -320,7 +320,7 @@ function testStringValidation() { $edit = array( $lid => $translation, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); // Check for a form error on the textarea. $form_class = $this->xpath('//form[@id="locale-translate-edit-form"]//textarea/@class'); $this->assertNotIdentical(FALSE, strpos($form_class[0], 'error'), 'The string was rejected as unsafe.'); @@ -380,7 +380,7 @@ function testStringSearch() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); // assertText() seems to remove the input field where $name always could be // found, so this is not a false assert. See how assertNoText succeeds // later. @@ -393,7 +393,7 @@ function testStringSearch() { 'langcode' => $langcode, 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), "Search didn't find the string."); // Ensure untranslated string appears if searching on 'only untranslated @@ -403,7 +403,7 @@ function testStringSearch() { 'langcode' => $langcode, 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertNoText(t('No strings available.'), 'Search found the string.'); // Add translation. @@ -414,7 +414,7 @@ function testStringSearch() { $edit = array( $lid => $translation, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); // Ensure translated string does appear if searching on 'only // translated strings'. @@ -423,7 +423,7 @@ function testStringSearch() { 'langcode' => $langcode, 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertNoText(t('No strings available.'), 'Search found the translation.'); // Ensure translated source string doesn't appear if searching on 'only @@ -433,7 +433,7 @@ function testStringSearch() { 'langcode' => $langcode, 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), "Search didn't find the source string."); // Ensure translated string doesn't appear if searching on 'only @@ -443,7 +443,7 @@ function testStringSearch() { 'langcode' => $langcode, 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), "Search didn't find the translation."); // Ensure translated string does appear if searching on the custom language. @@ -452,7 +452,7 @@ function testStringSearch() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertNoText(t('No strings available.'), 'Search found the translation.'); // Ensure translated string doesn't appear if searching in System (English). @@ -461,7 +461,7 @@ function testStringSearch() { 'langcode' => 'yy', 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), "Search didn't find the translation."); // Search for a string that isn't in the system. @@ -471,7 +471,7 @@ function testStringSearch() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), "Search didn't find the invalid string."); } @@ -508,7 +508,7 @@ function testUICustomizedStrings(){ 'translation' => 'translated', 'customized' => '0', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $source = $this->assertText($translation->getString(), 'Translation is found in search result.'); @@ -518,7 +518,7 @@ function testUICustomizedStrings(){ $edit = array( $lid => $translation->getString(), ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); // Ensure unchanged translation string does appear if searching non-customized translation. $search = array( @@ -527,7 +527,7 @@ function testUICustomizedStrings(){ 'translation' => 'translated', 'customized' => '0', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $source = $this->assertText($string->getString(), 'Translation is not marked as customized.'); // Submit the translations with a new translation. @@ -536,7 +536,7 @@ function testUICustomizedStrings(){ $edit = array( $lid => $this->randomName(100), ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); // Ensure changed translation string does appear if searching customized translation. $search = array( @@ -545,7 +545,7 @@ function testUICustomizedStrings(){ 'translation' => 'translated', 'customized' => '1', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText($string->getString(), "Translation is marked as customized."); } } diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php index 1cfb538..cf36a06 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php @@ -78,7 +78,7 @@ function testUninstallProcess() { // Build the JavaScript translation file for French. $user = $this->drupalCreateUser(array('translate interface', 'access administration pages')); $this->drupalLogin($user); - $this->drupalGet('admin/config/regional/translate/translate'); + $this->drupalGet('admin/config/regional/translate'); // Get any of the javascript strings to translate. $js_strings = $this->container->get('locale.storage')->getStrings(array('type' => 'javascript')); $string = reset($js_strings); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php index 9f55abc..9c24d4f 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php @@ -452,7 +452,7 @@ function testEnableCustomLanguage() { 'langcode' => $langcode, 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertNoText(t('No strings available.'), 'String successfully imported.'); // Ensure the multiline string was imported. @@ -461,7 +461,7 @@ function testEnableCustomLanguage() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText('Multiline translation string to make sure that import works with it.', 'String successfully imported.'); // Ensure 'Allowed HTML source string' was imported but the translation for @@ -472,7 +472,7 @@ function testEnableCustomLanguage() { 'langcode' => $langcode, 'translation' => 'all', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); $this->assertText('Allowed HTML source string', 'String successfully imported.'); $this->assertNoText('Another allowed HTML source string', 'String with disallowed translation not imported.'); } diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module index 9819f18..601bd83 100644 --- a/core/modules/locale/locale.module +++ b/core/modules/locale/locale.module @@ -173,9 +173,7 @@ function locale_menu() { $items['admin/config/regional/translate'] = array( 'title' => 'User interface translation', 'description' => 'Translate the built-in user interface.', - 'page callback' => 'locale_translate_page', - 'access arguments' => array('translate interface'), - 'file' => 'locale.pages.inc', + 'route_name' => 'locale_translate_page', 'weight' => -5, ); $items['admin/config/regional/translate/translate'] = array( @@ -741,7 +739,7 @@ function locale_form_language_admin_overview_form_alter(&$form, &$form_state) { '@total' => $total_strings, '@ratio' => $stats[$langcode]['ratio'], )), - 'admin/config/regional/translate/translate', + 'admin/config/regional/translate', array('query' => array('langcode' => $langcode)) ), ); diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc index 15fefb6..9df236b 100644 --- a/core/modules/locale/locale.pages.inc +++ b/core/modules/locale/locale.pages.inc @@ -12,460 +12,27 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** - * Page callback: Shows the string search screen. + * Page callback: Checks for translation updates and displays the status. * - * @see locale_menu() - */ -function locale_translate_page() { - return array( - 'filter' => drupal_get_form('locale_translate_filter_form'), - 'form' => drupal_get_form('locale_translate_edit_form'), - ); -} - -/** - * Builds a string search query and returns an array of string objects. - * - * @return array - * Array of Drupal\locale\TranslationString objects. - */ -function locale_translate_filter_load_strings() { - $filter_values = locale_translate_filter_values(); - - // Language is sanitized to be one of the possible options in - // locale_translate_filter_values(). - $conditions = array('language' => $filter_values['langcode']); - $options = array('pager limit' => 30, 'translated' => TRUE, 'untranslated' => TRUE); - - // Add translation status conditions and options. - switch ($filter_values['translation']) { - case 'translated': - $conditions['translated'] = TRUE; - if ($filter_values['customized'] != 'all') { - $conditions['customized'] = $filter_values['customized']; - } - break; - - case 'untranslated': - $conditions['translated'] = FALSE; - break; - - } - - if (!empty($filter_values['string'])) { - $options['filters']['source'] = $filter_values['string']; - if ($options['translated']) { - $options['filters']['translation'] = $filter_values['string']; - } - } - - return Drupal::service('locale.storage')->getTranslations($conditions, $options); -} - -/** - * Build array out of search criteria specified in request variables. - */ -function locale_translate_filter_values() { - $filter_values = &drupal_static(__FUNCTION__); - if (!isset($filter_values)) { - $filter_values = array(); - $filters = locale_translate_filters(); - foreach ($filters as $key => $filter) { - $filter_values[$key] = $filter['default']; - // Let the filter defaults be overwritten by parameters in the URL. - if (isset($_GET[$key])) { - // Only allow this value if it was among the options, or - // if there were no fixed options to filter for. - if (!isset($filter['options']) || isset($filter['options'][$_GET[$key]])) { - $filter_values[$key] = $_GET[$key]; - } - } - elseif (isset($_SESSION['locale_translate_filter'][$key])) { - // Only allow this value if it was among the options, or - // if there were no fixed options to filter for. - if (!isset($filter['options']) || isset($filter['options'][$_SESSION['locale_translate_filter'][$key]])) { - $filter_values[$key] = $_SESSION['locale_translate_filter'][$key]; - } - } - } - } - return $filter_values; -} - -/** - * List locale translation filters that can be applied. - */ -function locale_translate_filters() { - $filters = array(); - - // Get all languages, except English. - drupal_static_reset('language_list'); - $languages = language_list(); - $language_options = array(); - foreach ($languages as $langcode => $language) { - if ($langcode != 'en' || locale_translate_english()) { - $language_options[$langcode] = $language->name; - } - } - - // Pick the current interface language code for the filter. - $default_langcode = language(Language::TYPE_INTERFACE)->id; - if (!isset($language_options[$default_langcode])) { - $available_langcodes = array_keys($language_options); - $default_langcode = array_shift($available_langcodes); - } - - $filters['string'] = array( - 'title' => t('String contains'), - 'description' => t('Leave blank to show all strings. The search is case sensitive.'), - 'default' => '', - ); - - $filters['langcode'] = array( - 'title' => t('Translation language'), - 'options' => $language_options, - 'default' => $default_langcode, - ); - - $filters['translation'] = array( - 'title' => t('Search in'), - 'options' => array( - 'all' => t('Both translated and untranslated strings'), - 'translated' => t('Only translated strings'), - 'untranslated' => t('Only untranslated strings'), - ), - 'default' => 'all', - ); - - $filters['customized'] = array( - 'title' => t('Translation type'), - 'options' => array( - 'all' => t('All'), - LOCALE_NOT_CUSTOMIZED => t('Non-customized translation'), - LOCALE_CUSTOMIZED => t('Customized translation'), - ), - 'states' => array( - 'visible' => array( - ':input[name=translation]' => array('value' => 'translated'), - ), - ), - 'default' => 'all', - ); - - return $filters; -} - -/** - * Return form for locale translation filters. - * - * @ingroup forms - */ -function locale_translate_filter_form($form, &$form_state) { - $filters = locale_translate_filters(); - $filter_values = locale_translate_filter_values(); - - $form['#attached']['css'] = array( - drupal_get_path('module', 'locale') . '/css/locale.admin.css', - ); - - $form['filters'] = array( - '#type' => 'details', - '#title' => t('Filter translatable strings'), - '#collapsed' => FALSE, - ); - foreach ($filters as $key => $filter) { - // Special case for 'string' filter. - if ($key == 'string') { - $form['filters']['status']['string'] = array( - '#type' => 'search', - '#title' => $filter['title'], - '#description' => $filter['description'], - '#default_value' => $filter_values[$key], - ); - } - else { - $empty_option = isset($filter['options'][$filter['default']]) ? $filter['options'][$filter['default']] : '- None -'; - $form['filters']['status'][$key] = array( - '#title' => $filter['title'], - '#type' => 'select', - '#empty_value' => $filter['default'], - '#empty_option' => $empty_option, - '#size' => 0, - '#options' => $filter['options'], - '#default_value' => $filter_values[$key], - ); - if (isset($filter['states'])) { - $form['filters']['status'][$key]['#states'] = $filter['states']; - } - } - } - - $form['filters']['actions'] = array( - '#type' => 'actions', - '#attributes' => array('class' => array('container-inline')), - ); - $form['filters']['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Filter'), - ); - if (!empty($_SESSION['locale_translate_filter'])) { - $form['filters']['actions']['reset'] = array( - '#type' => 'submit', - '#value' => t('Reset'), - ); - } - - return $form; -} - -/** - * Process result from locale translation filter form. - */ -function locale_translate_filter_form_submit($form, &$form_state) { - $op = $form_state['values']['op']; - $filters = locale_translate_filters(); - switch ($op) { - case t('Filter'): - foreach ($filters as $name => $filter) { - if (isset($form_state['values'][$name])) { - $_SESSION['locale_translate_filter'][$name] = $form_state['values'][$name]; - } - } - break; - - case t('Reset'): - $_SESSION['locale_translate_filter'] = array(); - break; - - } - - $form_state['redirect'] = 'admin/config/regional/translate/translate'; -} - -/** - * Form constructor for the string editing form. + * Manually checks the translation status without the use of cron. * * @see locale_menu() - * @see locale_translate_edit_form_validate() - * @see locale_translate_edit_form_submit() - * - * @ingroup forms */ -function locale_translate_edit_form($form, &$form_state) { - $filter_values = locale_translate_filter_values(); - $langcode = $filter_values['langcode']; - - drupal_static_reset('language_list'); - $languages = language_list(); - - $langname = isset($langcode) ? $languages[$langcode]->name : "- None -"; - - $path = drupal_get_path('module', 'locale'); - $form['#attached']['css'] = array( - $path . '/css/locale.admin.css', - ); - $form['#attached']['library'][] = array('locale', 'drupal.locale.admin'); - - $form['langcode'] = array( - '#type' => 'value', - '#value' => $filter_values['langcode'], - ); - - $form['strings'] = array( - '#type' => 'item', - '#tree' => TRUE, - '#language' => $langname, - '#theme' => 'locale_translate_edit_form_strings', - ); - - if (isset($langcode)) { - $strings = locale_translate_filter_load_strings(); - - $plural_formulas = Drupal::state()->get('locale.translation.plurals') ?: array(); - - 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. - $form['strings'][$string->lid]['plural'] = array( - '#type' => 'value', - '#value' => 0, - ); - $form['strings'][$string->lid]['original'] = array( - '#type' => 'item', - '#title' => t('Source string (@language)', array('@language' => t('Built-in English'))), - '#title_display' => 'invisible', - '#markup' => '' . check_plain($source_array[0]) . '', - ); - } - else { - // Add original string value and mark as plural. - $form['strings'][$string->lid]['plural'] = array( - '#type' => 'value', - '#value' => 1, - ); - $form['strings'][$string->lid]['original_singular'] = array( - '#type' => 'item', - '#title' => t('Singular form'), - '#markup' => '' . check_plain($source_array[0]) . '', - '#prefix' => '' . t('Source string (@language)', array('@language' => t('Built-in English'))) . '', - ); - $form['strings'][$string->lid]['original_plural'] = array( - '#type' => 'item', - '#title' => t('Plural form'), - '#markup' => '' . check_plain($source_array[1]) . '', - ); - } - if (!empty($string->context)) { - $form['strings'][$string->lid]['context'] = array( - '#type' => 'value', - '#value' => '' . check_plain($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 (empty($form['strings'][$string->lid]['plural']['#value'])) { - $form['strings'][$string->lid]['translations'][0] = array( - '#type' => 'textarea', - '#title' => t('Translated string (@language)', array('@language' => $langname)), - '#title_display' => 'invisible', - '#rows' => $rows, - '#default_value' => $translation_array[0], - '#attributes' => array('lang' => $langcode), - ); - } - else { - // Dealing with plural strings. - if (isset($plural_formulas[$langcode]['plurals']) && $plural_formulas[$langcode]['plurals'] > 2) { - // Add a textarea for each plural variant. - for ($i = 0; $i < $plural_formulas[$langcode]['plurals']; $i++) { - $form['strings'][$string->lid]['translations'][$i] = array( - '#type' => 'textarea', - '#title' => ($i == 0 ? t('Singular form') : format_plural($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 ? ('' . t('Translated string (@language)', array('@language' => $langname)) . '') : '', - ); - } - } - else { - // Fallback for unknown number of plurals. - $form['strings'][$string->lid]['translations'][0] = array( - '#type' => 'textarea', - '#title' => t('Singular form'), - '#rows' => $rows, - '#default_value' => $translation_array[0], - '#attributes' => array('lang' => $langcode), - '#prefix' => '' . t('Translated string (@language)', array('@language' => $langname)) . '', - ); - $form['strings'][$string->lid]['translations'][1] = array( - '#type' => 'textarea', - '#title' => t('Plural form'), - '#rows' => $rows, - '#default_value' => isset($translation_array[1]) ? $translation_array[1] : '', - '#attributes' => array('lang' => $langcode), - ); - } - } - } - if (count(element_children($form['strings']))) { - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save translations')); - } - } - return $form; -} - -/** - * Form validation handler for locale_translate_edit_form(). - * - * @see locale_translate_edit_form_submit() - */ -function locale_translate_edit_form_validate($form, &$form_state) { - $langcode = $form_state['values']['langcode']; - foreach ($form_state['values']['strings'] as $lid => $translations) { - foreach ($translations['translations'] as $key => $value) { - if (!locale_string_is_safe($value)) { - form_set_error("strings][$lid][translations][$key", t('The submitted string contains disallowed HTML: %string', array('%string' => $value))); - form_set_error("translations][$langcode][$key", t('The submitted string contains disallowed HTML: %string', array('%string' => $value))); - watchdog('locale', 'Attempted submission of a translation string with disallowed HTML: %string', array('%string' => $value), WATCHDOG_WARNING); - } - } - } -} - -/** - * Form submission handler for locale_translate_edit_form(). - * - * @see locale_translate_edit_form_validate() - */ -function locale_translate_edit_form_submit($form, &$form_state) { - $langcode = $form_state['values']['langcode']; - $updated = array(); - - // Preload all translations for strings in the form. - $lids = array_keys($form_state['values']['strings']); - $existing_translation_objects = array(); - foreach (Drupal::service('locale.storage')->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['values']['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] : Drupal::service('locale.storage')->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(t('The strings have been saved.')); +function locale_translation_manual_status() { + module_load_include('compare.inc', 'locale'); - // Keep the user on the current pager page. - if (isset($_GET['page'])) { - $form_state['redirect'] = array('admin/config/regional/translate', array('query' => array('page' => $_GET['page']))); - } + // Check the translation status of all translatable projects in all languages. + // First we clear the cached list of projects. Although not strictly + // necessary, this is helpful in case the project list is out of sync. + locale_translation_flush_projects(); + locale_translation_check_projects(); - if ($updated) { - // Clear cache and refresh configuration and JavaScript translations. - _locale_refresh_translations(array($langcode), $updated); - _locale_refresh_configuration(array($langcode), $updated); + // Execute a batch if required. A batch is only used when remote files + // are checked. + if (batch_get()) { + return batch_process('admin/reports/translations'); } - + return new RedirectResponse(url('admin/reports/translations', array('absolute' => TRUE))); } /** diff --git a/core/modules/locale/locale.routing.yml b/core/modules/locale/locale.routing.yml index 2047229..4b7d50e 100644 --- a/core/modules/locale/locale.routing.yml +++ b/core/modules/locale/locale.routing.yml @@ -11,3 +11,10 @@ locale_check_translation: _controller: 'Drupal\locale\Controller\LocaleController::checkTranslation' requirements: _permission: 'translate interface' + +locale_translate_page: + pattern: '/admin/config/regional/translate' + defaults: + _content: 'Drupal\locale\Controller\LocaleController::translatePage' + requirements: + _permission: 'translate interface' diff --git a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarMenuTranslationTest.php b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarMenuTranslationTest.php index 02c01d4..949d565 100644 --- a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarMenuTranslationTest.php +++ b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarMenuTranslationTest.php @@ -59,7 +59,7 @@ function testToolbarClasses() { 'langcode' => $langcode, 'translation' => 'untranslated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); // Make sure will be able to translate the menu item. $this->assertNoText('No strings available.', 'Search found the menu item as untranslated.'); @@ -74,7 +74,7 @@ function testToolbarClasses() { $edit = array( $lid => $menu_item_translated, ); - $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations')); // Search for the translated menu item. $search = array( @@ -82,7 +82,7 @@ function testToolbarClasses() { 'langcode' => $langcode, 'translation' => 'translated', ); - $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->drupalPost('admin/config/regional/translate', $search, t('Filter')); // Make sure the menu item string was translated. $this->assertText($menu_item_translated, 'Search found the menu item as translated: ' . $menu_item_translated . '.');