summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwebchick2012-06-15 10:01:31 (GMT)
committerwebchick2012-06-15 10:01:31 (GMT)
commita03df8d124a3ba4c1c5acf886a617ea633d52eb3 (patch)
tree329c2079bb470845cfee388cfce77b82f97cf3c2
parentc32682a70fd58393cf0ec5f5cc31f7dc1d21ca4f (diff)
Issue #1452188 by Schnitzel, droplet, Sutharsan, Bojhan, Kristen Pol, Gábor Hojtsy, ershov.andrey, perusio, nod_, rvilar, andypost: Added New UI for string translation.
-rw-r--r--core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php28
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php23
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php85
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php199
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php8
-rw-r--r--core/modules/locale/locale-rtl.css5
-rw-r--r--core/modules/locale/locale.admin.css50
-rw-r--r--core/modules/locale/locale.admin.js51
-rw-r--r--core/modules/locale/locale.css25
-rw-r--r--core/modules/locale/locale.module38
-rw-r--r--core/modules/locale/locale.pages.inc560
-rw-r--r--core/modules/translation/translation.js21
12 files changed, 595 insertions, 498 deletions
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
index bc50f02..02d5139 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
@@ -103,15 +103,29 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
$language_browser_fallback_string = "In $langcode_browser_fallback In $langcode_browser_fallback In $langcode_browser_fallback";
$language_string = "In $langcode In $langcode In $langcode";
// Do a translate search of our target string.
- $edit = array( 'string' => $default_string);
- $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Filter'));
- // Should find the string and now click edit to post translated string.
- $this->clickLink('edit');
+ $search = array(
+ 'string' => $default_string,
+ 'langcode' => $langcode_browser_fallback,
+ );
+ $this->drupalPost('admin/config/regional/translate/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'));
+
+ $search = array(
+ 'string' => $default_string,
+ 'langcode' => $langcode,
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+ $textarea = current($this->xpath('//textarea'));
+ $lid = (string) $textarea[0]['name'];
$edit = array(
- "translations[$langcode_browser_fallback][0]" => $language_browser_fallback_string,
- "translations[$langcode][0]" => $language_string,
+ $lid => $language_string,
);
- $this->drupalPost(NULL, $edit, t('Save translations'));
+ $this->drupalPost('admin/config/regional/translate/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/Tests/LocaleImportFunctionalTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php
index 3beee64..6fe77c2 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php
@@ -91,7 +91,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
// Ensure string wasn't overwritten.
$search = array(
'string' => 'Montag',
- 'language' => 'fr',
+ 'langcode' => 'fr',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -113,7 +113,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
// Ensure string was overwritten.
$search = array(
'string' => 'Montag',
- 'language' => 'fr',
+ 'langcode' => 'fr',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -149,7 +149,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
// Ensure string wasn't overwritten.
$search = array(
'string' => 'januari',
- 'language' => 'fr',
+ 'langcode' => 'fr',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -168,7 +168,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
// Ensure string was overwritten.
$search = array(
'string' => 'januari',
- 'language' => 'fr',
+ 'langcode' => 'fr',
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -201,7 +201,7 @@ class LocaleImportFunctionalTest extends WebTestBase {
// Ensure strings were successfully imported.
$search = array(
'string' => 'lundi',
- 'language' => $langcode,
+ 'langcode' => $langcode,
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -241,20 +241,15 @@ class LocaleImportFunctionalTest extends WebTestBase {
'overwrite_options[not_customized]' => TRUE,
));
$this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 0, '%update' => 0, '%delete' => 1)), t('The translation file was successfully imported.'));
- // This is the language indicator on the translation search screen for
- // untranslated strings.
- $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
+
$str = "Operations";
$search = array(
'string' => $str,
- 'language' => 'all',
- 'translation' => 'all',
+ 'langcode' => $langcode,
+ 'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
- // assertText() seems to remove the input field where $str always could be
- // found, so this is not a false assert.
- $this->assertText($str, t('Search found the string.'));
- $this->assertRaw($language_indicator, t('String is untranslated again.'));
+ $this->assertText($str, t('Search found the string as untranslated.'));
}
/**
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
index c0cf178..32e0ab4 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
@@ -160,32 +160,41 @@ class LocalePluralFormatTest extends WebTestBase {
// Check if the source appears on the translation page.
$this->drupalGet('admin/config/regional/translate');
- $this->assertText("1 hour, @count hours");
+ $this->assertText("1 hour");
+ $this->assertText("@count hours");
// Look up editing page for this plural string and check fields.
- $lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", array(':source' => "1 hour" . LOCALE_PLURAL_DELIMITER . "@count hours"))->fetchField();
- $path = 'admin/config/regional/translate/edit/' . $lid;
+ $path = 'admin/config/regional/translate/';
$this->drupalGet($path);
// Labels for plural editing elements.
- $this->assertFieldByXPath('//label[@for="edit-translations-hr-0"]', 'Singular form ');
- $this->assertFieldByXPath('//label[@for="edit-translations-hr-1"]', 'First plural form ');
- $this->assertFieldByXPath('//label[@for="edit-translations-hr-2"]', '2. plural form ');
- $this->assertFieldByXPath('//label[@for="edit-translations-fr-0"]', 'Singular form ');
- $this->assertFieldByXPath('//label[@for="edit-translations-fr-1"]', 'Plural form ');
-
- // Plural values for both languages.
- $this->assertFieldById('edit-translations-hr-0', '@count sat');
- $this->assertFieldById('edit-translations-hr-1', '@count sata');
- $this->assertFieldById('edit-translations-hr-2', '@count sati');
- $this->assertNoFieldById('edit-translations-hr-3');
- $this->assertFieldById('edit-translations-fr-0', '1 heure');
- $this->assertFieldById('edit-translations-fr-1', '@count heures');
- $this->assertNoFieldById('edit-translations-fr-2');
-
- // Edit some translations and see if that took effect.
+ $this->assertText('Singular form');
+ $this->assertText('First plural form');
+ $this->assertText('2. plural form');
+ $this->assertNoText('3. plural form');
+
+ // Plural values for langcode hr.
+ $this->assertText('@count sat');
+ $this->assertText('@count sata');
+ $this->assertText('@count sati');
+
+ // Edit langcode hr translations and see if that took effect.
$edit = array(
- 'translations[fr][0]' => '1 heure edited',
- 'translations[hr][1]' => '@count sata edited',
+ 'strings[10][translations][1]' => '@count sata edited',
+ );
+ $this->drupalPost($path, $edit, t('Save translations'));
+
+ $search = array(
+ 'langcode' => 'fr',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+ // Plural values for the langcode fr.
+ $this->assertText('1 heure');
+ $this->assertText('@count heures');
+ $this->assertNoText('2. plural form');
+
+ // Edit langcode fr translations and see if that took effect.
+ $edit = array(
+ 'strings[10][translations][0]' => '1 heure edited',
);
$this->drupalPost($path, $edit, t('Save translations'));
@@ -194,21 +203,36 @@ class LocalePluralFormatTest extends WebTestBase {
// not save our source string for performance optimization if we do not ask
// specifically for a language.
format_plural(1, '1 day', '@count days', array(), array('langcode' => 'fr'));
- // Look up editing page for this plural string and check fields.
$lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", array(':source' => "1 day" . LOCALE_PLURAL_DELIMITER . "@count days"))->fetchField();
- $path = 'admin/config/regional/translate/edit/' . $lid;
+ // Look up editing page for this plural string and check fields.
+ $search = array(
+ 'string' => '1 day',
+ 'langcode' => 'fr',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
- // Save complete translations for the string in both languages.
+ // Save complete translations for the string in langcode fr.
$edit = array(
- 'translations[fr][0]' => '1 jour',
- 'translations[fr][1]' => '@count jours',
- 'translations[hr][0]' => '@count dan',
- 'translations[hr][1]' => '@count dana',
- 'translations[hr][2]' => '@count dana',
+ "strings[$lid][translations][0]" => '1 jour',
+ "strings[$lid][translations][1]" => '@count jours',
);
$this->drupalPost($path, $edit, t('Save translations'));
- // Get the French translations.
+ // Save complete translations for the string in langcode hr.
+ $search = array(
+ 'string' => '1 day',
+ 'langcode' => 'hr',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+
+ $edit = array(
+ "strings[$lid][translations][0]" => '@count dan',
+ "strings[$lid][translations][1]" => '@count dana',
+ "strings[$lid][translations][2]" => '@count dana',
+ );
+ $this->drupalPost($path, $edit, t('Save translations'));
+
+ // Get the French translations.
$this->drupalPost('admin/config/regional/translate/export', array(
'langcode' => 'fr',
), t('Export'));
@@ -225,7 +249,6 @@ class LocalePluralFormatTest extends WebTestBase {
$this->assertRaw("msgid \"1 day\"\nmsgid_plural \"@count days\"\nmsgstr[0] \"@count dan\"\nmsgstr[1] \"@count dana\"\nmsgstr[2] \"@count dana\"", t('Added Croatian plural translations exported properly.'));
}
-
/**
* Imports a standalone .po file in a given language.
*
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
index 7db6aef..212f32e 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
@@ -67,21 +67,19 @@ class LocaleTranslationTest extends WebTestBase {
$this->drupalLogin($translate_user);
$search = array(
'string' => $name,
- 'language' => 'all',
- 'translation' => 'all',
+ 'langcode' => $langcode,
+ 'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/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.
- $this->assertText($name, t('Search found the name.'));
- $this->assertRaw($language_indicator, t('Name is untranslated.'));
+ $this->assertText($name, t('Search found the string as untranslated.'));
+
// Assume this is the only result, given the random name.
- $this->clickLink(t('edit'));
// We save the lid from the path.
- $matches = array();
- preg_match('!admin/config/regional/translate/edit/(\d+)!', $this->getUrl(), $matches);
- $lid = $matches[1];
+ $textarea = current($this->xpath('//textarea'));
+ $lid = (string) $textarea[0]['name'];
+ $edit = array(
+ $lid => $this->randomName(),
+ );
// No t() here, it's surely not translated yet.
$this->assertText($name, t('name found on edit screen.'));
$this->assertNoText('English', t('No way to translate the string to English.'));
@@ -91,24 +89,46 @@ class LocaleTranslationTest extends WebTestBase {
$this->drupalLogout();
$this->drupalLogin($translate_user);
$this->drupalPost('admin/config/regional/translate/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.
- $this->assertText($name, t('Search found the name.'));
- $this->assertRaw($language_indicator, t('Name is untranslated.'));
+ $this->assertText($name, t('Search found the string as untranslated.'));
+
// Assume this is the only result, given the random name.
- $this->clickLink(t('edit'));
- $string_edit_url = $this->getUrl();
+ $textarea = current($this->xpath('//textarea'));
+ $lid = (string) $textarea[0]['name'];
$edit = array(
- "translations[$langcode][0]" => $translation,
- 'translations[en][0]' => $translation_to_en,
+ $lid => $translation,
);
- $this->drupalPost(NULL, $edit, t('Save translations'));
- $this->assertText(t('The string has been saved.'), t('The string has been saved.'));
+ $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
+ $this->assertText(t('The strings have been saved.'), t('The strings have been saved.'));
$this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
- $this->drupalGet($string_edit_url);
+ $search = array(
+ 'string' => $name,
+ 'langcode' => $langcode,
+ 'translation' => 'translated',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->assertRaw($translation, t('Non-English translation properly saved.'));
+
+
+ $search = array(
+ 'string' => $name,
+ 'langcode' => 'en',
+ 'translation' => 'untranslated',
+ );
+ $this->drupalPost('admin/config/regional/translate/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'));
+ $search = array(
+ 'string' => $name,
+ 'langcode' => 'en',
+ 'translation' => 'translated',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
$this->assertRaw($translation_to_en, t('English translation properly saved.'));
+
$this->assertTrue($name != $translation && t($name, array(), array('langcode' => $langcode)) == $translation, t('t() works for non-English.'));
// Refresh the locale() cache to get fresh data from t() below. We are in
// the same HTTP request and therefore t() is not refreshed by saving the
@@ -117,16 +137,15 @@ class LocaleTranslationTest extends WebTestBase {
// Now we should get the proper fresh translation from t().
$this->assertTrue($name != $translation_to_en && t($name, array(), array('langcode' => 'en')) == $translation_to_en, t('t() works for English.'));
$this->assertTrue(t($name, array(), array('langcode' => LANGUAGE_SYSTEM)) == $name, t('t() works for LANGUAGE_SYSTEM.'));
+
+ $search = array(
+ 'string' => $name,
+ 'langcode' => 'en',
+ 'translation' => 'untranslated',
+ );
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
- // The indicator should not be here.
- $this->assertNoRaw($language_indicator, t('String is translated.'));
-
- // Try to edit a non-existent string and ensure we're redirected correctly.
- // Assuming we don't have 999,999 strings already.
- $random_lid = 999999;
- $this->drupalGet('admin/config/regional/translate/edit/' . $random_lid);
- $this->assertText(t('String not found'), t('String not found.'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+ $this->assertText(t('No strings available.'), t('String is translated.'));
+
$this->drupalLogout();
// Delete the language.
@@ -147,26 +166,26 @@ class LocaleTranslationTest extends WebTestBase {
$this->drupalLogin($translate_user);
$search = array(
'string' => $name,
- 'language' => 'all',
- 'translation' => 'all',
+ 'langcode' => 'en',
+ 'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
// Assume this is the only result, given the random name.
- $this->clickLink(t('delete'));
- $this->assertText(t('Are you sure you want to delete the string'), t('"delete" link is correct.'));
- // Delete the string.
- $path = 'admin/config/regional/translate/delete/' . $lid;
- $this->drupalGet($path);
- // First test the 'cancel' link.
- $this->clickLink(t('Cancel'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
- $this->assertRaw($name, t('The string was not deleted.'));
- // Delete the name string.
- $this->drupalPost('admin/config/regional/translate/delete/' . $lid, array(), t('Delete'));
- $this->assertText(t('The string has been removed.'), t('The string has been removed message.'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+ $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->assertRaw($name, t('The strings have been saved.'));
+ $this->drupalLogin($translate_user);
+ $search = array(
+ 'string' => $name,
+ 'langcode' => 'en',
+ 'translation' => 'untranslated',
+ );
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
- $this->assertNoText($name, t('Search now can not find the name.'));
+ $this->assertNoText(t('No strings available.'), t('The translation has been removed'));
}
/*
@@ -192,16 +211,29 @@ class LocaleTranslationTest extends WebTestBase {
drupal_static_reset('language_list');
// Build the JavaScript translation file.
- $this->drupalGet('admin/config/regional/translate/translate');
- // Retrieve the id of the first string available in the {locales_source}
- // table and translate it.
- $query = db_select('locales_source', 'l');
- $query->addExpression('min(l.lid)', 'lid');
- $result = $query->condition('l.location', '%.js%', 'LIKE')->execute();
- $url = 'admin/config/regional/translate/edit/' . $result->fetchObject()->lid;
- $edit = array('translations['. $langcode .'][0]' => $this->randomName());
- $this->drupalPost($url, $edit, t('Save translations'));
+ // Retrieve the source string of the first string available in the
+ // {locales_source} table and translate it.
+ $source = db_select('locales_source', 'l')
+ ->fields('l', array('source'))
+ ->condition('l.location', '%.js%', 'LIKE')
+ ->range(0, 1)
+ ->execute()
+ ->fetchField();
+
+ $search = array(
+ 'string' => $source,
+ 'langcode' => $langcode,
+ 'translation' => 'all',
+ );
+ $this->drupalPost('admin/config/regional/translate/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'));
// Trigger JavaScript translation parsing and building.
_locale_rebuild_js($langcode);
@@ -230,9 +262,7 @@ class LocaleTranslationTest extends WebTestBase {
$langcode = 'xx';
// The English name for the language. This will be translated.
$name = $this->randomName(16);
- // This is the language indicator on the translation search screen for
- // untranslated strings.
- $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
+
// These will be the invalid translations of $name.
$key = $this->randomName(16);
$bad_translations[$key] = "<script>alert('xss');</script>" . $key;
@@ -256,19 +286,19 @@ class LocaleTranslationTest extends WebTestBase {
// Reset locale cache.
$search = array(
'string' => $name,
- 'language' => 'all',
+ 'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
// Find the edit path.
- $content = $this->drupalGetContent();
- $this->assertTrue(preg_match('@(admin/config/regional/translate/edit/[0-9]+)@', $content, $matches), t('Found the edit path.'));
- $path = $matches[0];
+
+ $textarea = current($this->xpath('//textarea'));
+ $lid = (string) $textarea[0]['name'];
foreach ($bad_translations as $key => $translation) {
$edit = array(
- "translations[$langcode][0]" => $translation,
+ $lid => $translation,
);
- $this->drupalPost($path, $edit, t('Save translations'));
+ $this->drupalPost('admin/config/regional/translate/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'), t('The string was rejected as unsafe.'));
@@ -306,6 +336,15 @@ class LocaleTranslationTest extends WebTestBase {
'direction' => '0',
);
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+
+ $edit = array(
+ 'predefined_langcode' => 'custom',
+ 'langcode' => 'yy',
+ 'name' => $this->randomName(16),
+ 'direction' => '0',
+ );
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+
// Add string.
t($name, array(), array('langcode' => $langcode));
// Reset locale cache.
@@ -316,7 +355,7 @@ class LocaleTranslationTest extends WebTestBase {
$this->drupalLogin($translate_user);
$search = array(
'string' => $name,
- 'language' => 'all',
+ 'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -329,7 +368,7 @@ class LocaleTranslationTest extends WebTestBase {
// translated strings'.
$search = array(
'string' => $name,
- 'language' => 'all',
+ 'langcode' => $langcode,
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -339,7 +378,7 @@ class LocaleTranslationTest extends WebTestBase {
// strings'.
$search = array(
'string' => $name,
- 'language' => 'all',
+ 'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -347,21 +386,19 @@ class LocaleTranslationTest extends WebTestBase {
// Add translation.
// Assume this is the only result, given the random name.
- $this->clickLink(t('edit'));
// We save the lid from the path.
- $matches = array();
- preg_match('!admin/config/regional/translate/edit/(\d)+!', $this->getUrl(), $matches);
- $lid = $matches[1];
+ $textarea = current($this->xpath('//textarea'));
+ $lid = (string) $textarea[0]['name'];
$edit = array(
- "translations[$langcode][0]" => $translation,
+ $lid => $translation,
);
- $this->drupalPost(NULL, $edit, t('Save translations'));
+ $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Save translations'));
// Ensure translated string does appear if searching on 'only
// translated strings'.
$search = array(
'string' => $translation,
- 'language' => 'all',
+ 'langcode' => $langcode,
'translation' => 'translated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -371,7 +408,7 @@ class LocaleTranslationTest extends WebTestBase {
// untranslated strings'.
$search = array(
'string' => $name,
- 'language' => 'all',
+ 'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -381,7 +418,7 @@ class LocaleTranslationTest extends WebTestBase {
// untranslated strings'.
$search = array(
'string' => $translation,
- 'language' => 'all',
+ 'langcode' => $langcode,
'translation' => 'untranslated',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -390,7 +427,7 @@ class LocaleTranslationTest extends WebTestBase {
// Ensure translated string does appear if searching on the custom language.
$search = array(
'string' => $translation,
- 'language' => $langcode,
+ 'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -399,7 +436,7 @@ class LocaleTranslationTest extends WebTestBase {
// Ensure translated string doesn't appear if searching in System (English).
$search = array(
'string' => $translation,
- 'language' => LANGUAGE_SYSTEM,
+ 'langcode' => 'yy',
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
@@ -409,7 +446,7 @@ class LocaleTranslationTest extends WebTestBase {
$unavailable_string = $this->randomName(16);
$search = array(
'string' => $unavailable_string,
- 'language' => 'all',
+ 'langcode' => $langcode,
'translation' => 'all',
);
$this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
index 72868e9..71aff68 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
@@ -61,11 +61,13 @@ class LocaleUninstallTest extends WebTestBase {
$user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
$this->drupalLogin($user);
$this->drupalGet('admin/config/regional/translate/translate');
- $string = db_query('SELECT min(lid) AS lid FROM {locales_source} WHERE location LIKE :location', array(
+ $string = db_query('SELECT min(lid) AS lid, source FROM {locales_source} WHERE location LIKE :location', array(
':location' => '%.js%',
))->fetchObject();
- $edit = array('translations[fr][0]' => 'french translation');
- $this->drupalPost('admin/config/regional/translate/edit/' . $string->lid, $edit, t('Save translations'));
+ $edit = array('string' => $string->source);
+ $this->drupalPost('admin/config/regional/translate', $edit, t('Filter'));
+ $edit = array('strings[' . $string->lid . '][translations][0]' => 'french translation');
+ $this->drupalPost('admin/config/regional/translate', $edit, t('Save translations'));
_locale_rebuild_js('fr');
$locale_javascripts = variable_get('locale_translation_javascript', array());
$js_file = 'public://' . variable_get('locale_js_directory', 'languages') . '/fr_' . $locale_javascripts['fr'] . '.js';
diff --git a/core/modules/locale/locale-rtl.css b/core/modules/locale/locale-rtl.css
index aaf1988..3ec5531 100644
--- a/core/modules/locale/locale-rtl.css
+++ b/core/modules/locale/locale-rtl.css
@@ -1,12 +1,11 @@
-
#locale-translation-filter-form .form-item-language,
#locale-translation-filter-form .form-item-translation,
#locale-translation-filter-form .form-item-group {
float: right;
- padding-left: .8em;
+ padding-left: 1em;
padding-right: 0;
}
#locale-translation-filter-form .form-actions {
float: right;
- padding: 3ex 1em 0 0;
+ padding: 3.5ex 0 0 0;
}
diff --git a/core/modules/locale/locale.admin.css b/core/modules/locale/locale.admin.css
new file mode 100644
index 0000000..4b252b6
--- /dev/null
+++ b/core/modules/locale/locale.admin.css
@@ -0,0 +1,50 @@
+#locale-translate-filter-form .form-item-langcode,
+#locale-translate-filter-form .form-item-translation,
+#locale-translate-filter-form .form-item-customized {
+ float: left; /* LTR */
+ padding-right: 1em; /* LTR */
+ margin-bottom: 0;
+ /**
+ * In Opera 9, DOM elements with the property of "overflow: auto"
+ * will partially hide its contents with unnecessary scrollbars when
+ * its immediate child is floated without an explicit width set.
+ */
+ width: 15em;
+}
+#locale-translate-filter-form .form-type-select select {
+ width: 100%;
+}
+#locale-translate-filter-form .form-actions {
+ float: left; /* LTR */
+ padding: 3.5ex 0 0 0em; /* LTR */
+}
+#locale-translate-edit-form th{
+ width: 50%;
+ table-layout: fixed;
+}
+#locale-translate-edit-form tr .form-item{
+ white-space: normal;
+}
+#locale-translate-edit-form td {
+ vertical-align: top
+}
+
+#locale-translate-edit-form tr.changed {
+ background: #ffb;
+}
+
+#locale-translate-edit-form tr .form-type-item abbr.ajax-changed {
+ position: absolute;
+}
+
+#locale-translate-filter-form fieldset.form-wrapper {
+ margin-bottom:0;
+}
+
+#locale-translate-edit-form #edit-strings table.locale-translate-edit-table {
+ margin-top: 54px;
+}
+
+#locale-translate-edit-form #edit-strings table.locale-translate-edit-table.changed {
+ margin-top: 0;
+}
diff --git a/core/modules/locale/locale.admin.js b/core/modules/locale/locale.admin.js
new file mode 100644
index 0000000..9e1917c
--- /dev/null
+++ b/core/modules/locale/locale.admin.js
@@ -0,0 +1,51 @@
+(function ($) {
+
+"use strict";
+
+/**
+ * Markes changes of translations
+ */
+Drupal.behaviors.localeTranslateDirty = {
+ attach: function () {
+ var $form = $("#locale-translate-edit-form").once('localetranslatedirty');
+ if ($form.length) {
+ // Display a notice if any row changed.
+ $form.one('change.localeTranslateDirty', 'table', function () {
+ var $marker = $(Drupal.theme('localeTranslateChangedWarning')).hide();
+ $(this).addClass('changed').before($marker);
+ $marker.fadeIn('slow');
+ });
+ // Highlight changed row.
+ $form.on('change.localeTranslateDirty', 'tr', function (e) {
+ var
+ $row = $(this),
+ $rowToMark = $row.once('localemark'),
+ marker = Drupal.theme('localeTranslateChangedMarker');
+
+ $row.addClass('changed');
+ // Add an asterisk only once if row changed.
+ if ($rowToMark.length) {
+ $rowToMark.find('td:first-child .form-item').append(marker);
+ }
+ });
+ }
+ },
+ detach: function (context, settings, trigger) {
+ if (trigger === 'unload') {
+ var $form = $("#locale-translate-edit-form").removeOnce('localetranslatedirty');
+ if ($form.length) {
+ $form.off('change.localeTranslateDirty');
+ }
+ }
+ }
+};
+
+Drupal.theme.prototype.localeTranslateChangedMarker = function () {
+ return '<abbr class="warning ajax-changed" title="' + Drupal.t('Changed') + '">*</abbr>';
+};
+
+Drupal.theme.prototype.localeTranslateChangedWarning = function () {
+ return '<div class="localetranslate-changed-warning messages warning">' + Drupal.theme('localeTranslateChangedMarker') + ' ' + Drupal.t('Changes made in this table will not be saved until the form is submitted.') + '</div>';
+};
+
+})(jQuery);
diff --git a/core/modules/locale/locale.css b/core/modules/locale/locale.css
deleted file mode 100644
index 6c03945..0000000
--- a/core/modules/locale/locale.css
+++ /dev/null
@@ -1,25 +0,0 @@
-.locale-untranslated {
- font-style: normal;
- text-decoration: line-through;
-}
-
-#locale-translation-filter-form .form-item-language,
-#locale-translation-filter-form .form-item-translation,
-#locale-translation-filter-form .form-item-customized {
- float: left; /* LTR */
- padding-right: .8em; /* LTR */
- margin: 0.1em;
- /**
- * In Opera 9, DOM elements with the property of "overflow: auto"
- * will partially hide its contents with unnecessary scrollbars when
- * its immediate child is floated without an explicit width set.
- */
- width: 15em;
-}
-#locale-translation-filter-form .form-type-select select {
- width: 100%;
-}
-#locale-translation-filter-form .form-actions {
- float: left; /* LTR */
- padding: 3ex 0 0 1em; /* LTR */
-}
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index ae4c5f0..c034ab3 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -89,7 +89,7 @@ function locale_help($path, $arg) {
return $output;
case 'admin/config/regional/language':
- return '<p>' . t('Interface text can be translated. <a href="@translations">Download contributed translations</a> from Drupal.org.', array('@translations' => 'http://localize.drupal.org')) . '</p>';
+ return '<p>' . t('Interface text can be <a href="@translate">translated</a>. <a href="@translations">Download contributed translations</a> from Drupal.org.', array('@translations' => 'http://localize.drupal.org', '@translate' => url('admin/config/regional/translate'))) . '</p>';
case 'admin/config/regional/translate':
$output = '<p>' . t('This page allows a translator to search for specific translated and untranslated strings, and is used when creating or editing translations. (Note: For translation tasks involving many strings, it may be more convenient to <a href="@export">export</a> strings for offline editing in a desktop Gettext translation editor.) Searches may be limited to strings in a specific language.', array('@export' => url('admin/config/regional/translate/export'))) . '</p>';
@@ -113,7 +113,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_seek_screen',
+ 'page callback' => 'locale_translate_page',
'access arguments' => array('translate interface'),
'file' => 'locale.pages.inc',
'weight' => -5,
@@ -141,20 +141,6 @@ function locale_menu() {
'type' => MENU_LOCAL_TASK,
'file' => 'locale.bulk.inc',
);
- $items['admin/config/regional/translate/edit/%'] = array(
- 'title' => 'Edit string',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('locale_translate_edit_form', 5),
- 'access arguments' => array('translate interface'),
- 'file' => 'locale.pages.inc',
- );
- $items['admin/config/regional/translate/delete/%'] = array(
- 'title' => 'Delete string',
- 'page callback' => 'locale_translate_delete_page',
- 'page arguments' => array(5),
- 'access arguments' => array('translate interface'),
- 'file' => 'locale.pages.inc',
- );
// Localize date formats.
$items['admin/config/regional/date-time/locale'] = array(
@@ -267,6 +253,10 @@ function locale_theme() {
'locale_date_format_form' => array(
'render element' => 'form',
),
+ 'locale_translate_edit_form_strings' => array(
+ 'render element' => 'form',
+ 'file' => 'locale.pages.inc',
+ ),
);
}
@@ -636,13 +626,15 @@ function locale_form_language_admin_overview_form_alter(&$form, &$form_state) {
);
if ($langcode != 'en' || locale_translate_english()) {
$form['languages'][$langcode]['locale_statistics'] = array(
- '#type' => 'link',
- '#title' => t('@translated/@total (@ratio%)', array(
- '@translated' => $stats[$langcode]['translated'],
- '@total' => $total_strings,
- '@ratio' => $stats[$langcode]['ratio'],
- )),
- '#href' => 'admin/config/regional/translate/translate',
+ '#markup' => l(
+ t('@translated/@total (@ratio%)', array(
+ '@translated' => $stats[$langcode]['translated'],
+ '@total' => $total_strings,
+ '@ratio' => $stats[$langcode]['ratio'],
+ )),
+ 'admin/config/regional/translate/translate',
+ array('query' => array('langcode' => $langcode))
+ ),
);
}
else {
diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc
index 726731d..b91d3a4 100644
--- a/core/modules/locale/locale.pages.inc
+++ b/core/modules/locale/locale.pages.inc
@@ -10,155 +10,89 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* String search screen.
*/
-function locale_translate_seek_screen() {
- // Add CSS.
- drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
-
- $elements = drupal_get_form('locale_translation_filter_form');
- $output = drupal_render($elements);
- $output .= _locale_translate_seek();
- return $output;
+function locale_translate_page() {
+ return array(
+ 'filter' => drupal_get_form('locale_translate_filter_form'),
+ 'form' => drupal_get_form('locale_translate_edit_form'),
+ );
}
/**
- * Perform a string search and display results in a table
+ * Build a string search query.
*/
-function _locale_translate_seek() {
- $output = '';
-
- // We have at least one criterion to match
- if (!($query = _locale_translate_seek_query())) {
- $query = array(
- 'translation' => 'all',
- 'language' => 'all',
- 'customized' => 'all',
- 'string' => '',
- );
- }
+function locale_translate_query() {
+ $filter_values = locale_translate_filter_values();
$sql_query = db_select('locales_source', 's');
- $sql_query->leftJoin('locales_target', 't', 't.lid = s.lid');
+ // Language is sanitized to be one of the possible options in
+ // locale_translate_filter_values().
+ $sql_query->leftJoin('locales_target', 't', "t.lid = s.lid AND t.language = :langcode", array(':langcode' => $filter_values['langcode']));
$sql_query->fields('s', array('source', 'location', 'context', 'lid'));
$sql_query->fields('t', array('translation', 'language', 'customized'));
- // Compute LIKE section.
- switch ($query['translation']) {
+ if (!empty($filter_values['string'])) {
+ $sql_query->condition(db_or()
+ ->condition('s.source', '%' . db_like($filter_values['string']) . '%', 'LIKE')
+ ->condition('t.translation', '%' . db_like($filter_values['string']) . '%', 'LIKE')
+ );
+ }
+
+ // Add translation status conditions.
+ switch ($filter_values['translation']) {
case 'translated':
- $sql_query->condition('t.translation', '%' . db_like($query['string']) . '%', 'LIKE');
- $sql_query->orderBy('t.translation', 'DESC');
- if ($query['customized'] != 'all') {
- $sql_query->condition('t.customized', $query['customized']);
+ $sql_query->isNotNull('t.translation');
+ if ($filter_values['customized'] != 'all') {
+ $sql_query->condition('t.customized', $filter_values['customized']);
}
break;
+
case 'untranslated':
- $sql_query->condition(db_and()
- ->condition('s.source', '%' . db_like($query['string']) . '%', 'LIKE')
- ->isNull('t.translation')
- );
- $sql_query->orderBy('s.source');
- break;
- case 'all' :
- default:
- $condition = db_or()
- ->condition('s.source', '%' . db_like($query['string']) . '%', 'LIKE');
- if ($query['language'] != LANGUAGE_SYSTEM) {
- // Only search in translations if the language is not forced to system language.
- $condition->condition('t.translation', '%' . db_like($query['string']) . '%', 'LIKE');
- }
- $sql_query->condition($condition);
+ $sql_query->isNull('t.translation');
break;
- }
-
- $limit_language = NULL;
- if ($query['language'] != LANGUAGE_SYSTEM && $query['language'] != 'all') {
- $sql_query->condition('language', $query['language']);
- $limit_language = $query['language'];
- }
-
- $sql_query = $sql_query
- ->extend('Drupal\Core\Database\Query\PagerSelectExtender')
- ->limit(50);
- $locales = $sql_query->execute();
-
- $header = array(t('String'), t('Context'), ($limit_language) ? t('Language') : t('Languages'), array('data' => t('Operations'), 'colspan' => '2'));
-
- $strings = array();
- foreach ($locales as $locale) {
- if (!isset($strings[$locale->lid])) {
- $strings[$locale->lid] = array(
- 'languages' => array(),
- 'location' => $locale->location,
- 'source' => $locale->source,
- 'context' => $locale->context,
- );
- }
- if (isset($locale->language)) {
- $strings[$locale->lid]['languages'][$locale->language] = $locale->translation;
- }
- }
-
- $rows = array();
- foreach ($strings as $lid => $string) {
- $rows[] = array(
- array('data' => check_plain(truncate_utf8(str_replace(LOCALE_PLURAL_DELIMITER, ', ', $string['source']), 150, FALSE, TRUE)) . '<br /><small>' . $string['location'] . '</small>'),
- $string['context'],
- array('data' => _locale_translate_language_list($string['languages'], $limit_language), 'align' => 'center'),
- array('data' => l(t('edit'), "admin/config/regional/translate/edit/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
- array('data' => l(t('delete'), "admin/config/regional/translate/delete/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
- );
- }
-
- $output .= theme('table', array('header' => $header, 'rows' => $rows, 'empty' => t('No strings available.')));
- $output .= theme('pager');
-
- return $output;
-}
-
-/**
- * List languages in search result table
- */
-function _locale_translate_language_list($translation, $limit_language) {
- // Add CSS.
- drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
- $languages = language_list();
- if (!locale_translate_english()) {
- unset($languages['en']);
- }
- $output = '';
- foreach ($languages as $langcode => $language) {
- if (!$limit_language || $limit_language == $langcode) {
- $output .= (!empty($translation[$langcode])) ? $langcode . ' ' : "<em class=\"locale-untranslated\">$langcode</em> ";
- }
}
- return $output;
+ $sql_query = $sql_query->extend('Drupal\Core\Database\Query\PagerSelectExtender')->limit(30);
+ return $sql_query->execute();
}
/**
- * Build array out of search criteria specified in request variables
+ * Build array out of search criteria specified in request variables.
*/
-function _locale_translate_seek_query() {
- $query = &drupal_static(__FUNCTION__);
- if (!isset($query)) {
- $query = array();
- $fields = array('string', 'language', 'translation', 'customized');
- foreach ($fields as $field) {
- if (isset($_SESSION['locale_translation_filter'][$field])) {
- $query[$field] = $_SESSION['locale_translation_filter'][$field];
+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 $query;
+ return $filter_values;
}
/**
* List locale translation filters that can be applied.
*/
-function locale_translation_filters() {
+function locale_translate_filters() {
$filters = array();
- // Get all languages, except English
+ // Get all languages, except English.
drupal_static_reset('language_list');
$languages = language_list();
$language_options = array();
@@ -168,14 +102,23 @@ function locale_translation_filters() {
}
}
+ // Pick the current interface language code for the filter.
+ $default_langcode = drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode;
+ 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['language'] = array(
- 'title' => t('Language'),
- 'options' => array_merge(array('all' => t('All languages'), LANGUAGE_SYSTEM => t('System (English)')), $language_options),
+ $filters['langcode'] = array(
+ 'title' => t('Translation language'),
+ 'options' => $language_options,
+ 'default' => $default_langcode,
);
$filters['translation'] = array(
@@ -183,8 +126,9 @@ function locale_translation_filters() {
'options' => array(
'all' => t('Both translated and untranslated strings'),
'translated' => t('Only translated strings'),
- 'untranslated' => t('Untranslated strings')
+ 'untranslated' => t('Only untranslated strings'),
),
+ 'default' => 'all',
);
$filters['customized'] = array(
@@ -197,8 +141,9 @@ function locale_translation_filters() {
'states' => array(
'visible' => array(
':input[name=translation]' => array('value' => 'translated'),
- )
+ ),
),
+ 'default' => 'all',
);
return $filters;
@@ -209,8 +154,13 @@ function locale_translation_filters() {
*
* @ingroup forms
*/
-function locale_translation_filter_form() {
- $filters = locale_translation_filters();
+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') . '/locale.admin.css',
+ );
$form['filters'] = array(
'#type' => 'fieldset',
@@ -225,24 +175,24 @@ function locale_translation_filter_form() {
'#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' => 'all',
- '#empty_option' => $filter['options']['all'],
+ '#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'];
}
}
- if (!empty($_SESSION['locale_translation_filter'][$key])) {
- $form['filters']['status'][$key]['#default_value'] = $_SESSION['locale_translation_filter'][$key];
- }
}
$form['filters']['actions'] = array(
@@ -253,10 +203,10 @@ function locale_translation_filter_form() {
'#type' => 'submit',
'#value' => t('Filter'),
);
- if (!empty($_SESSION['locale_translation_filter'])) {
+ if (!empty($_SESSION['locale_translate_filter'])) {
$form['filters']['actions']['reset'] = array(
'#type' => 'submit',
- '#value' => t('Reset')
+ '#value' => t('Reset'),
);
}
@@ -264,168 +214,159 @@ function locale_translation_filter_form() {
}
/**
- * Validate result from locale translation filter form.
- */
-function locale_translation_filter_form_validate($form, &$form_state) {
- if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['language'])) {
- form_set_error('type', t('You must select something to filter by.'));
- }
-}
-
-/**
* Process result from locale translation filter form.
*/
-function locale_translation_filter_form_submit($form, &$form_state) {
+function locale_translate_filter_form_submit($form, &$form_state) {
$op = $form_state['values']['op'];
- $filters = locale_translation_filters();
+ $filters = locale_translate_filters();
switch ($op) {
case t('Filter'):
foreach ($filters as $name => $filter) {
if (isset($form_state['values'][$name])) {
- $_SESSION['locale_translation_filter'][$name] = $form_state['values'][$name];
+ $_SESSION['locale_translate_filter'][$name] = $form_state['values'][$name];
}
}
break;
+
case t('Reset'):
- $_SESSION['locale_translation_filter'] = array();
+ $_SESSION['locale_translate_filter'] = array();
break;
+
}
$form_state['redirect'] = 'admin/config/regional/translate/translate';
}
-
/**
- * User interface for string editing.
+ * User interface for string editing as one table.
*
* @ingroup forms
*/
-function locale_translate_edit_form($form, &$form_state, $lid) {
- // Fetch source string, if possible.
- $source = db_query('SELECT source, context, location FROM {locales_source} WHERE lid = :lid', array(':lid' => $lid))->fetchObject();
- if (!$source) {
- drupal_set_message(t('String not found.'), 'error');
- drupal_goto('admin/config/regional/translate/translate');
- }
- // Split source to work with plural values.
- $source_array = explode(LOCALE_PLURAL_DELIMITER, $source->source);
- if (count($source_array) == 1) {
- // Add original text value and mark as non-plural.
- $form['plural'] = array(
- '#type' => 'value',
- '#value' => 0
- );
- $form['original'] = array(
- '#type' => 'item',
- '#title' => t('Original text'),
- '#markup' => check_plain($source_array[0]),
- );
- }
- else {
- // Add original text value and mark as plural.
- $form['plural'] = array(
- '#type' => 'value',
- '#value' => 1
- );
- $form['original_singular'] = array(
- '#type' => 'item',
- '#title' => t('Original singular form'),
- '#markup' => check_plain($source_array[0]),
- );
- $form['original_plural'] = array(
- '#type' => 'item',
- '#title' => t('Original plural form'),
- '#markup' => check_plain($source_array[1]),
- );
- }
- if (!empty($source->context)) {
- $form['context'] = array(
- '#type' => 'item',
- '#title' => t('Context'),
- '#markup' => check_plain($source->context),
- );
- }
- $form['lid'] = array(
- '#type' => 'value',
- '#value' => $lid
+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 . '/locale.admin.css',
);
- $form['location'] = array(
- '#type' => 'value',
- '#value' => $source->location
+ $form['#attached']['js'] = array(
+ $path . '/locale.admin.js',
);
- // Include default form controls with empty values for all languages.
- // This ensures that the languages are always in the same order in forms.
- $languages = language_list();
- if (!locale_translate_english()) {
- unset($languages['en']);
- }
- // Store languages to iterate for validation and submission of the form.
- $form_state['langcodes'] = array_keys($languages);
- $plural_formulas = variable_get('locale_translation_plurals', array());
+ $form['langcode'] = array(
+ '#type' => 'value',
+ '#value' => $filter_values['langcode'],
+ );
- $form['translations'] = array(
- '#type' => 'vertical_tabs',
- '#tree' => TRUE
+ $form['strings'] = array(
+ '#type' => 'item',
+ '#tree' => TRUE,
+ '#language' => $langname,
+ '#theme' => 'locale_translate_edit_form_strings',
);
- // Approximate the number of rows to use in the default textarea.
- $rows = min(ceil(str_word_count($source_array[0]) / 12), 10);
- foreach ($languages as $langcode => $language) {
- $form['translations'][$langcode] = array(
- '#type' => 'fieldset',
- '#title' => $language->name,
- );
- if (empty($form['plural']['#value'])) {
- $form['translations'][$langcode][0] = array(
- '#type' => 'textarea',
- '#title' => $language->name,
- '#rows' => $rows,
- '#default_value' => '',
- );
- }
- 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['translations'][$langcode][$i] = array(
- '#type' => 'textarea',
- '#title' => ($i == 0 ? t('Singular form') : format_plural($i, 'First plural form', '@count. plural form')),
- '#rows' => $rows,
- '#default_value' => '',
- );
- }
+ if (isset($langcode)) {
+ $strings = locale_translate_query();
+
+ $plural_formulas = variable_get('locale_translation_plurals', array());
+
+ foreach ($strings as $string) {
+ // Split source to work with plural values.
+ $source_array = explode(LOCALE_PLURAL_DELIMITER, $string->source);
+ $translation_array = explode(LOCALE_PLURAL_DELIMITER, $string->translation);
+ 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'),
+ '#title_display' => 'invisible',
+ '#markup' => check_plain($source_array[0]),
+ );
}
else {
- // Fallback for unknown number of plurals.
- $form['translations'][$langcode][0] = array(
- '#type' => 'textarea',
+ // 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'),
- '#rows' => $rows,
- '#default_value' => '',
+ '#markup' => check_plain($source_array[0]),
);
- $form['translations'][$langcode][1] = array(
- '#type' => 'textarea',
+ $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),
+ );
+ }
+ $form['strings'][$string->lid]['location'] = array(
+ '#type' => 'value',
+ '#value' => $string->location,
+ );
+
+ // 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'),
+ '#title_display' => 'invisible',
'#rows' => $rows,
- '#default_value' => '',
+ '#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 ? t('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' => t('Singular form'),
+ '#rows' => $rows,
+ '#default_value' => $translation_array[0],
+ );
+ $form['strings'][$string->lid]['translations'][1] = array(
+ '#type' => 'textarea',
+ '#title' => t('Plural form'),
+ '#rows' => $rows,
+ '#default_value' => isset($translation_array[1]) ? $translation_array[1] : '',
+ );
+ }
+ }
}
- }
-
- // Fetch translations and fill in default values in the form.
- $result = db_query("SELECT DISTINCT translation, language FROM {locales_target} WHERE lid = :lid", array(':lid' => $lid));
- foreach ($result as $translation) {
- $translation_array = explode(LOCALE_PLURAL_DELIMITER, $translation->translation);
- for ($i = 0; $i < count($translation_array); $i++) {
- $form['translations'][$translation->language][$i]['#default_value'] = $translation_array[$i];
+ if (count(element_children($form['strings']))) {
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save translations'));
}
}
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save translations'));
return $form;
}
@@ -433,9 +374,11 @@ function locale_translate_edit_form($form, &$form_state, $lid) {
* Validate string editing form submissions.
*/
function locale_translate_edit_form_validate($form, &$form_state) {
- foreach ($form_state['langcodes'] as $langcode) {
- foreach ($form_state['values']['translations'][$langcode] as $key => $value) {
+ $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);
}
@@ -445,18 +388,16 @@ function locale_translate_edit_form_validate($form, &$form_state) {
/**
* Process string editing form submissions.
- *
- * Saves all translations of one string submitted from a form.
*/
function locale_translate_edit_form_submit($form, &$form_state) {
- $lid = $form_state['values']['lid'];
- foreach ($form_state['langcodes'] as $langcode) {
+ $langcode = $form_state['values']['langcode'];
+ foreach ($form_state['values']['strings'] as $lid => $translations) {
// Serialize plural variants in one string by LOCALE_PLURAL_DELIMITER.
- $value = implode(LOCALE_PLURAL_DELIMITER, $form_state['values']['translations'][$langcode]);
- $translation = db_query("SELECT translation FROM {locales_target} WHERE lid = :lid AND language = :language", array(':lid' => $lid, ':language' => $langcode))->fetchField();
+ $translation_new = implode(LOCALE_PLURAL_DELIMITER, $translations['translations']);
+ $translation_old = db_query("SELECT translation FROM {locales_target} WHERE lid = :lid AND language = :language", array(':lid' => $lid, ':language' => $langcode))->fetchField();
// No translation when all strings are empty.
$has_translation = FALSE;
- foreach ($form_state['values']['translations'][$langcode] as $string) {
+ foreach ($translations['translations'] as $string) {
if (!empty($string)) {
$has_translation = TRUE;
break;
@@ -464,28 +405,28 @@ function locale_translate_edit_form_submit($form, &$form_state) {
}
if ($has_translation) {
// Only update or insert if we have a value to use.
- if (!empty($translation) && $translation != $value) {
+ if (!empty($translation_old) && $translation_old != $translation_new) {
db_update('locales_target')
->fields(array(
- 'translation' => $value,
+ 'translation' => $translation_new,
'customized' => LOCALE_CUSTOMIZED,
))
->condition('lid', $lid)
->condition('language', $langcode)
->execute();
}
- if (empty($translation)) {
+ if (empty($translation_old)) {
db_insert('locales_target')
->fields(array(
'lid' => $lid,
- 'translation' => $value,
+ 'translation' => $translation_new,
'language' => $langcode,
'customized' => LOCALE_CUSTOMIZED,
))
->execute();
}
}
- elseif (!empty($translation)) {
+ elseif (!empty($translation_old)) {
// Empty translation entered: remove existing entry from database.
db_delete('locales_target')
->condition('lid', $lid)
@@ -493,55 +434,52 @@ function locale_translate_edit_form_submit($form, &$form_state) {
->execute();
}
- // Force JavaScript translation file recreation for this language.
- _locale_invalidate_js($langcode);
}
- drupal_set_message(t('The string has been saved.'));
+ drupal_set_message(t('The strings have been saved.'));
+
+ // 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'])));
+ }
+ // Force JavaScript translation file recreation for this language.
+ _locale_invalidate_js($langcode);
// Clear locale cache.
- _locale_invalidate_js();
cache()->deletePrefix('locale:');
-
- $form_state['redirect'] = 'admin/config/regional/translate/translate';
- return;
}
/**
- * String deletion confirmation page.
+ * Default theme function for translatione edit form.
*/
-function locale_translate_delete_page($lid) {
- if ($source = db_query('SELECT lid, source FROM {locales_source} WHERE lid = :lid', array(':lid' => $lid))->fetchObject()) {
- return drupal_get_form('locale_translate_delete_form', $source);
- }
- else {
- throw new NotFoundHttpException();
+function theme_locale_translate_edit_form_strings($variables) {
+ $output = '';
+ $form = $variables['form'];
+ $header = array(
+ t('Source string'),
+ t('Translation for @language', array('@language' => $form['#language'])),
+ );
+ $rows = array();
+ foreach (element_children($form) as $lid) {
+ $string = $form[$lid];
+ if ($string['plural']['#value']) {
+ $source = drupal_render($string['original_singular']) . '<br />' . drupal_render($string['original_plural']);
+ }
+ else {
+ $source = drupal_render($string['original']);
+ }
+ $source .= empty($string['context']) ? '' : '<br /><small>' . t('In Context') . ':&nbsp;' . $string['context']['#value'] . '</small>';
+ $rows[] = array(
+ array('data' => $source),
+ array('data' => $string['translations']),
+ );
}
-}
-
-/**
- * User interface for the string deletion confirmation screen.
- *
- * @ingroup forms
- */
-function locale_translate_delete_form($form, &$form_state, $source) {
- $form['lid'] = array('#type' => 'value', '#value' => $source->lid);
- return confirm_form($form, t('Are you sure you want to delete the string "%source"?', array('%source' => $source->source)), 'admin/config/regional/translate/translate', t('Deleting the string will remove all translations of this string in all languages. This action cannot be undone.'), t('Delete'), t('Cancel'));
-}
-
-/**
- * Process string deletion submissions.
- */
-function locale_translate_delete_form_submit($form, &$form_state) {
- db_delete('locales_source')
- ->condition('lid', $form_state['values']['lid'])
- ->execute();
- db_delete('locales_target')
- ->condition('lid', $form_state['values']['lid'])
- ->execute();
- // Force JavaScript translation file recreation for all languages.
- _locale_invalidate_js();
- cache()->deletePrefix('locale:');
- drupal_set_message(t('The string has been removed.'));
- $form_state['redirect'] = 'admin/config/regional/translate/translate';
+ $output .= theme('table', array(
+ 'header' => $header,
+ 'rows' => $rows,
+ 'empty' => t('No strings available.'),
+ 'attributes' => array('class' => array('locale-translate-edit-table')),
+ ));
+ $output .= theme('pager');
+ return $output;
}
diff --git a/core/modules/translation/translation.js b/core/modules/translation/translation.js
new file mode 100644
index 0000000..d4b9f53
--- /dev/null
+++ b/core/modules/translation/translation.js
@@ -0,0 +1,21 @@
+(function ($) {
+
+"use strict";
+
+Drupal.behaviors.TranslationEnable = {
+ attach: function (context) {
+ $('#edit-node-type-language-default, #edit-node-type-language-locked', context).change(function(context) {
+ var default_language = $('#edit-node-type-language-default').val();
+
+ if ((default_language == 'und' || default_language == 'zxx' || default_language == 'mul') && $('#edit-node-type-language-locked').attr('checked')) {
+ $('.form-item-node-type-language-translation-enabled').hide();
+ $('#edit-node-type-language-translation-enabled').removeAttr('checked');
+ } else {
+ $('.form-item-node-type-language-translation-enabled').show();
+ }
+ });
+ $('#edit-node-type-language-default', context).trigger('change');
+ }
+};
+
+})(jQuery);