Commit a03df8d1 authored by webchick's avatar webchick

Issue #1452188 by Schnitzel, droplet, Sutharsan, Bojhan, Kristen Pol, Gábor...

Issue #1452188 by Schnitzel, droplet, Sutharsan, Bojhan, Kristen Pol, Gábor Hojtsy, ershov.andrey, perusio, nod_, rvilar, andypost: Added New UI for string translation.
parent c32682a7
......@@ -103,15 +103,29 @@ function testUILanguageNegotiation() {
$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);
......
......@@ -91,7 +91,7 @@ function testStandalonePoFile() {
// 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 @@ function testStandalonePoFile() {
// 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 @@ function testStandalonePoFile() {
// 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 @@ function testStandalonePoFile() {
// 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 @@ function testAutomaticModuleTranslationImportLanguageEnable() {
// 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 @@ function testEmptyMsgstr() {
'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.'));
}
/**
......
......@@ -160,32 +160,41 @@ function testPluralEditExport() {
// 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 @@ function testPluralEditExport() {
// 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 @@ function testPluralEditExport() {
$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.
*
......
......@@ -61,11 +61,13 @@ function testUninstallProcess() {
$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';
......
#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;
}
#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;
}
(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);
.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 */
}
......@@ -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 {
......
This diff is collapsed.
(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);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment