diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php index 57b68ffc191c03a2e25f241f260ea71d26a76b0b..e3b677709a297509c047e02d349de5a7fbadd822 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php @@ -8,6 +8,7 @@ namespace Drupal\locale\Tests; use Drupal\simpletest\WebTestBase; +use Drupal\Core\Language\Language; /** * Functional test for string translation and validation. @@ -471,4 +472,78 @@ function testStringSearch() { $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); $this->assertText(t('No strings available.'), t("Search didn't find the invalid string.")); } + + /** + * Tests that only changed strings are saved customized when edited. + */ + function testUICustomizedStrings(){ + $user = $this->drupalCreateUser(array('translate interface', 'administer languages', 'access administration pages')); + $this->drupalLogin($user); + $language = new Language(array('langcode' => 'de')); + language_save($language); + + // Create test source string + $string = locale_storage()->createString(array( + 'source' => $this->randomName(100), + 'context' => $this->randomName(20), + ))->save(); + + // Create translation for new string and save it as non-customized. + $translation = locale_storage()->createTranslation(array( + 'lid' => $string->lid, + 'language' => 'de', + 'translation' => $this->randomName(100), + 'customized' => 0, + ))->save(); + + // Reset locale cache. + locale_reset(); + + // Ensure non-customized translation string does appear if searching Non-customized translation. + $search = array( + 'string' => $string->getString(), + 'langcode' => 'de', + 'translation' => 'translated', + 'customized' => '0', + ); + $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + + $source = $this->assertText($translation->getString(), 'Translation is found in search result.'); + + // Submit the translations without changing the translation. + $textarea = current($this->xpath('//textarea')); + $lid = (string) $textarea[0]['name']; + $edit = array( + $lid => $translation->getString(), + ); + $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + + // Ensure unchanged translation string does appear if searching non-customized translation. + $search = array( + 'string' => $string->getString(), + 'langcode' => 'de', + 'translation' => 'translated', + 'customized' => '0', + ); + $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $source = $this->assertText($string->getString(), 'Translation is not marked as customized.'); + + // Submit the translations with a new translation. + $textarea = current($this->xpath('//textarea')); + $lid = (string) $textarea[0]['name']; + $edit = array( + $lid => $this->randomName(100), + ); + $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations')); + + // Ensure changed translation string does appear if searching customized translation. + $search = array( + 'string' => $string->getString(), + 'langcode' => 'de', + 'translation' => 'translated', + 'customized' => '1', + ); + $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter')); + $this->assertText($string->getString(), "Translation is marked as customized."); + } } diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc index dcf12b96b63620b3fdea63d0793677abce34a685..42e5ad3c84026dc9fca382bd0cdc1a9e17fab665 100644 --- a/core/modules/locale/locale.pages.inc +++ b/core/modules/locale/locale.pages.inc @@ -402,31 +402,45 @@ function locale_translate_edit_form_submit($form, &$form_state) { // Preload all translations for strings in the form. $lids = array_keys($form_state['values']['strings']); - $strings = array(); - foreach (locale_storage()->getTranslations(array('lid' => $lids, 'language' => $langcode, 'translated' => TRUE)) as $string) { - $strings[$string->lid] = $string; + $existing_translation_objects = array(); + foreach (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 => $translations) { - // No translation when all strings are empty. - $has_translation = FALSE; - foreach ($translations['translations'] as $string) { - if (!empty($string)) { - $has_translation = TRUE; - break; - } + 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; } - if ($has_translation) { + 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($strings[$lid]) ? $strings[$lid] : locale_storage()->createTranslation(array('lid' => $lid, 'language' => $langcode)); - $target->setPlurals($translations['translations']) + $target = isset($existing_translation_objects[$lid]) ? $existing_translation_objects[$lid] : locale_storage()->createTranslation(array('lid' => $lid, 'language' => $langcode)); + $target->setPlurals($new_translation['translations']) ->setCustomized() ->save(); $updated[] = $target->getId(); } - elseif (isset($strings[$lid])) { - // Empty translation entered: remove existing entry from database. - $strings[$lid]->delete(); + 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; } }