diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
index 555c198..403761b 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 7d95e3a..a3d2b32 100644
--- a/core/modules/locale/lib/Drupal/locale/Controller/LocaleController.php
+++ b/core/modules/locale/lib/Drupal/locale/Controller/LocaleController.php
@@ -7,10 +7,15 @@
namespace Drupal\locale\Controller;
use Drupal\Core\Controller\ControllerInterface;
-use Drupal\Core\Routing\PathBasedGeneratorInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
+use Drupal\Core\Routing\PathBasedGeneratorInterface;
+use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
+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 +29,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, PathBasedGeneratorInterface $url_generator) {
+ public function __construct(ModuleHandlerInterface $module_handler, PathBasedGeneratorInterface $url_generator, ContainerInterface $container) {
$this->moduleHandler = $module_handler;
$this->urlGenerator = $url_generator;
+ $this->container = $container;
}
/**
@@ -40,7 +57,8 @@ public function __construct(ModuleHandlerInterface $module_handler, PathBasedGen
public static function create(ContainerInterface $container) {
return new static(
$container->get('module_handler'),
- $container->get('url_generator')
+ $container->get('url_generator'),
+ $container
);
}
@@ -69,4 +87,17 @@ 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() {
+ $state = $this->container->get('keyvalue')->get('state');
+ return array(
+ 'filter' => drupal_get_form(new TranslateFilterForm($state)),
+ 'form' => drupal_get_form(new TranslateEditForm($state, $this->container->get('string_translation'), $this->container->get('locale.storage'))),
+ );
+ }
}
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..8bd86bb
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Form/TranslateEditForm.php
@@ -0,0 +1,280 @@
+state = $state;
+ $this->translator = $translator;
+ $this->localStorage = $local_storage;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormID() {
+ return 'locale_translate_edit_form';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(array $form, array &$form_state, NodeInterface $node = NULL) {
+ $filter_values = $this->translateFilterValues();
+ $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();
+
+ $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->translator->translate('Source string'),
+ '#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->translator->translate('Singular form'),
+ '#markup' => String::checkPlain($source_array[0]),
+ );
+ $form['strings'][$string->lid]['original_plural'] = array(
+ '#type' => 'item',
+ '#title' => $this->translator->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->translator->translate('Translated string'),
+ '#title_display' => 'invisible',
+ '#rows' => $rows,
+ '#default_value' => $translation_array[0],
+ );
+ }
+ 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->translator->translate('Singular form') : format_plural($i, 'First plural form', '@count. plural form')),
+ '#rows' => $rows,
+ '#default_value' => isset($translation_array[$i]) ? $translation_array[$i] : '',
+ );
+ }
+ }
+ else {
+ // Fallback for unknown number of plurals.
+ $form['strings'][$string->lid]['translations'][0] = array(
+ '#type' => 'textarea',
+ '#title' => $this->translator->translate('Singular form'),
+ '#rows' => $rows,
+ '#default_value' => $translation_array[0],
+ );
+ $form['strings'][$string->lid]['translations'][1] = array(
+ '#type' => 'textarea',
+ '#title' => $this->translator->translate('Plural form'),
+ '#rows' => $rows,
+ '#default_value' => isset($translation_array[1]) ? $translation_array[1] : '',
+ );
+ }
+ }
+ }
+ if (count(element_children($form['strings']))) {
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => $this->translator->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->translator->translate('The submitted string contains disallowed HTML: %string', array('%string' => $value)));
+ form_set_error("translations][$langcode][$key", $this->translator->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->localStorage->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->localStorage->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->translator->translate('The strings have been saved.'));
+
+ // Keep the user on the current pager page.
+ $page = $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..e02819c
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Form/TranslateFilterForm.php
@@ -0,0 +1,114 @@
+translateFilters();
+ $filter_values = $this->translateFilterValues();
+
+ $form['#attached']['css'] = array(
+ drupal_get_path('module', 'locale') . '/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 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';
+ }
+
+}
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..5b2abbd
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Form/TranslateFormBase.php
@@ -0,0 +1,195 @@
+localeStorage = $locale_storage;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('locale.storage')
+ );
+ }
+
+ /**
+ * 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) {
+ // @todo vlikin: Need be decoupled.
+ $request = \Drupal::request();
+
+ $filter_values = &drupal_static(__FUNCTION__);
+ if (!isset($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 $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' => 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;
+ }
+
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php
index 414cde0..f0ffe79 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/LocalePluralFormatTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
index a03f1df..fcff653 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
@@ -204,7 +204,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');
@@ -227,7 +227,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(
@@ -241,7 +241,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/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
index e2d1109..922b764 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/locale.module b/core/modules/locale/locale.module
index 932b2a1..3a997f7 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(
@@ -744,7 +742,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 83777b6..f5523cb 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 . '.');