diff --git l10n_community/ajax.inc l10n_community/ajax.inc index 890e4ac..45a4251 100644 --- l10n_community/ajax.inc +++ l10n_community/ajax.inc @@ -55,6 +55,43 @@ function l10n_community_string_details($langcode = NULL, $sid = 0) { exit; } +/** + * Flags or unflags a translation. + * + * @param $langcode + * Language code. + * @param $sid + * Source string id. + */ +function l10n_community_string_flag($langcode = NULL, $sid = 0) { + // Fetch information on the active translation. + $result = db_query("SELECT t.tid, t.is_stable FROM {l10n_community_translation} t WHERE t.language = '%s' AND t.sid = %d AND t.is_active = 1 AND t.is_suggestion = 0", $langcode, $sid); + $translation = db_fetch_object($result); + + if ($translation) { + $output = ''; + $token_name = 'l10n_server_'. $translation->tid .'_'. $sid; + + if ($_REQUEST['form_token'] && drupal_valid_token($_REQUEST['form_token'], $token_name)) { + db_query("UPDATE {l10n_community_translation} t SET t.is_stable = %d WHERE t.language = '%s' AND t.sid = %d", 1 - $translation->is_stable, $langcode, $sid); + $output = 'done'; + } + else { + $url = url('translate/flag/' . $langcode . '/' . $sid, array('query' => array('form_token' => drupal_get_token($token_name)))); + if ($translation->is_stable) { + $output .= t('Flagged as stable. Withdraw flag', array('@flag' => $url)); + } + else { + $output .= t('Not flagged. Flag as stable', array('@flag' => $url)); + } + } + + print $output; + } + + exit; +} + function l10n_community_string_suggestions($langcode = NULL, $sid = 0) { // Existing, "unresolved" suggestions. $suggestions = array(); diff --git l10n_community/images/icon_toolbox.gif l10n_community/images/icon_toolbox.gif index 3c3f40e..e3a8c1b 100644 Binary files l10n_community/images/icon_toolbox.gif and l10n_community/images/icon_toolbox.gif differ diff --git l10n_community/l10n_community.css l10n_community/l10n_community.css index fadadbe..ab641af 100644 --- l10n_community/l10n_community.css +++ l10n_community/l10n_community.css @@ -108,7 +108,8 @@ table.l10n-server-translate td { } table.l10n-server-translate td .suggestions, - table.l10n-server-translate td .lookup { + table.l10n-server-translate td .lookup, + table.l10n-server-translate td .flag { display:none; } @@ -191,6 +192,14 @@ table.l10n-server-translate label.option { background: url(images/icon_toolbox.gif) right -20px no-repeat; } + .l10n-flag { + background: url(images/icon_toolbox.gif) 0px -60px no-repeat; + } + + .l10n-flag.active { + background: url(images/icon_toolbox.gif) right -60px no-repeat; + } + ul.l10n-community-strings { margin: 0; } @@ -204,6 +213,11 @@ ul.l10n-community-strings li .buttons { float:left; } +.l10n-community-strings .stable { + font-style: italic; + color: #AAA; +} + .l10n-community-string .original { display:none; } diff --git l10n_community/l10n_community.install l10n_community/l10n_community.install index e119e0b..e99d856 100644 --- l10n_community/l10n_community.install +++ l10n_community/l10n_community.install @@ -323,12 +323,20 @@ function l10n_community_schema() { 'not null' => TRUE, 'default' => 0, 'disp-width' => '11' + ), + 'is_stable' => array( + 'description' => 'Flag of whether this translation is marked as stable (1) or not (0).', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'disp-width' => '11' ) ), 'primary key' => array('tid'), 'indexes' => array( 'is_active' => array('is_active'), 'is_suggestion' => array('is_suggestion'), + 'is_stable' => array('is_stable'), 'language' => array('language'), 'suggestion_active' => array('is_suggestion', 'is_active'), 'uid_entered' => array('uid_entered'), @@ -536,3 +544,13 @@ function l10n_community_update_6005() { db_add_field($ret, 'l10n_community_string', 'context', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '')); return $ret; } + +/** + * Add the stable column to allow marking translations as finished. + */ +function l10n_community_update_6006() { + $ret = array(); + db_add_field($ret, 'l10n_community_translation', 'is_stable', array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'disp-width' => '11', 'description' => 'Flag of whether this translation is marked as stable (1) or not (0).')); + db_add_index($ret, 'l10n_community_translation', 'is_stable', array('is_stable')); + return $ret; +} diff --git l10n_community/l10n_community.js l10n_community/l10n_community.js index fbab1f9..7718088 100644 --- l10n_community/l10n_community.js +++ l10n_community/l10n_community.js @@ -49,6 +49,16 @@ l10nCommunity.init = function() { // switch display panes l10nCommunity.switchPanes(this, 'translate'); }); + + $('#l10n-community-translate-form .l10n-flag').click(function() { + // switch display panes + var elem = this; + var sid = $(this).parents('.translation').attr('id').substring(6); + $.get(Drupal.settings.l10n_flag_callback + sid, null, function(data) { + $('#tpane-' + sid + ' .flag').empty().append(data); + l10nCommunity.switchPanes(elem, 'flag'); + }); + }); $('#l10n-community-translate-form .l10n-lookup').click(function() { // switch display panes @@ -193,6 +203,26 @@ l10nCommunity.declineSuggestion = function(tid, sid, elem, token) { } /** + * Translation flagging callback. + */ +l10nCommunity.flagTranslation = function(sid, elem) { + // Invoke server side callback to save the decline action. + $.ajax({ + type: "POST", + url: elem.href, + success: function () { + $('#tpane-' + sid + ' .l10n-flag').click(); + }, + error: function (xmlhttp) { + // Being an internal/system error, this is not translatable. + alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ uri); + } + }); + // Return false for onclick handling. + return false; +}; + +/** * Suggestion editing copy callback. */ l10nCommunity.copySuggestion = function(sid, translation) { diff --git l10n_community/l10n_community.module l10n_community/l10n_community.module index 3b20979..90be4e2 100644 --- l10n_community/l10n_community.module +++ l10n_community/l10n_community.module @@ -50,6 +50,16 @@ define('L10N_STATUS_NO_SUGGESTION', 4); */ define('L10N_STATUS_HAS_SUGGESTION', 8); +/** + * Isn't marked as stable. + */ +define('L10N_STATUS_UNSTABLE', 16); + +/** + * Is marked as stable. + */ +define('L10N_STATUS_STABLE', 32); + // = Core hooks ================================================================ /** @@ -178,6 +188,13 @@ function l10n_community_menu() { 'access arguments' => array('access localization community'), 'type' => MENU_CALLBACK, ); + $items['translate/flag'] = array( + 'title' => 'String flags', + 'page callback' => 'l10n_community_string_flag', + 'file' => 'ajax.inc', + 'access arguments' => array('flag translations'), + 'type' => MENU_CALLBACK, + ); $items['translate/suggestions'] = array( 'title' => 'String suggestions', 'page callback' => 'l10n_community_string_suggestions', @@ -1331,7 +1348,7 @@ function theme_l10n_community_copy_button() { * @param $string * Source string to translate. */ -function l10n_community_format_text($string, $sid = NULL, $delta = NULL) { +function l10n_community_format_text($string, $sid = NULL, $delta = NULL, $flag = FALSE) { static $path = NULL, $title = NULL; if (!isset($path)) { @@ -1362,7 +1379,14 @@ function l10n_community_format_text($string, $sid = NULL, $delta = NULL) { $class = ' class="string-'. $sid .'"'; } - return ''. $string .''; + if ($flag) { + $flag = ' '. t('(stable)') .' '; + } + else { + $flag = ''; + } + + return ''. $string .''. $flag .''; } /** diff --git l10n_community/translate.inc l10n_community/translate.inc index 1b51aec..cea0fc3 100644 --- l10n_community/translate.inc +++ l10n_community/translate.inc @@ -81,6 +81,11 @@ function l10n_community_filter_form(&$form_state, $project = NULL, $status = L10 L10N_STATUS_NO_SUGGESTION => t('Has no suggestion'), L10N_STATUS_HAS_SUGGESTION => t('Has suggestion'), ); + $flag_options = array( + L10N_STATUS_ALL => t(''), + L10N_STATUS_UNSTABLE => t('Unstable'), + L10N_STATUS_STABLE => t('Stable'), + ); $form['project'] = array( '#title' => t('Project'), @@ -140,6 +145,11 @@ function l10n_community_filter_form(&$form_state, $project = NULL, $status = L10 '#options' => $suggestion_options, '#default_value' => $status & (L10N_STATUS_HAS_SUGGESTION | L10N_STATUS_NO_SUGGESTION), ); + $form['status']['flag'] = array( + '#type' => 'select', + '#options' => $flag_options, + '#default_value' => $status & (L10N_STATUS_UNSTABLE | L10N_STATUS_STABLE), + ); $form['search'] = array( '#title' => t('Contains'), @@ -188,7 +198,7 @@ function l10n_community_filter_form_submit($form, &$form_state) { unset($form_state['values']['release']); } } - $form_state['values']['status'] = ((int) $form_state['values']['status']['translation']) | ((int) $form_state['values']['status']['suggestion']); + $form_state['values']['status'] = ((int) $form_state['values']['status']['translation']) | ((int) $form_state['values']['status']['suggestion'] | ((int) $form_state['values']['status']['flag'])); // Redirect keeping the relevant filters intact in the URL. $form_state['redirect'] = array( @@ -214,6 +224,7 @@ function l10n_community_translate_view($strings = array(), $language = NULL, $pr $output = ''; $rows = array(); foreach ($strings as $string) { + $row = array(); // Source display // Multiple source strings if we deal with plurals. @@ -300,10 +311,10 @@ function l10n_community_translate_form(&$form_state, $strings = array(), $langua $form[$string->sid] = array( '#tree' => TRUE, ); - // A toolbox which displays action icons on each string editor fieldset. $toolbox = theme('l10n_community_button', 'translate', 'l10n-translate active'); $toolbox .= theme('l10n_community_button', 'lookup', 'l10n-lookup'); + $toolbox .= $string->is_active && !$string->is_suggestion ? theme('l10n_community_button', 'flag', 'l10n-flag') : ''; $toolbox .= $string->has_suggestion ? theme('l10n_community_button', 'has-suggestion', 'l10n-suggestions') : ""; $toolbox = "
$toolbox
"; $form[$string->sid]['toolbox'] = array( @@ -386,7 +397,7 @@ function l10n_community_translate_form(&$form_state, $strings = array(), $langua if ($translated) { $form[$string->sid]['translation_existing'] = array( '#type' => 'item', - '#value' => theme('l10n_community_strings', array(l10n_community_format_text($string->translation, $string->sid))), + '#value' => theme('l10n_community_strings', array(l10n_community_format_text($string->translation, $string->sid, NULL, $string->is_stable))), ); } $form[$string->sid]['translation']['value'] = array( @@ -432,6 +443,7 @@ function l10n_community_translate_form(&$form_state, $strings = array(), $langua '#type' => 'checkbox', ); } + } // Add all strings for copy-pasting and some helpers. @@ -445,6 +457,7 @@ function l10n_community_translate_form(&$form_state, $strings = array(), $langua 'l10n_decline_confirm' => t('Suggestion declined.'), 'l10n_details_callback' => url('translate/details/'. $language->language .'/'), + 'l10n_flag_callback' => url('translate/flag/'. $language->language .'/'), 'l10n_suggestions_callback' => url('translate/suggestions/'. $language->language .'/'), 'l10n_approve_callback' => url('translate/approve/'), 'l10n_decline_callback' => url('translate/decline/'), @@ -558,7 +571,7 @@ function theme_l10n_community_translate_form($form) { $translation_pane .= !empty($element['translation_existing']) ? drupal_render($element['translation_existing']) : ''; $translation_pane .= drupal_render($element['messagebox']); $translation_pane .= drupal_render($element['translation']) .''; - $translation_pane .= "
"; + $translation_pane .= "
"; $translation_pane .= ""; $row = array( array( @@ -606,8 +619,8 @@ function theme_l10n_community_in_context($string) { * Project object to look up strings for. * @param $status * Filter strings by status. See L10N_STATUS_ALL, - * L10N_STATUS_UNTRANSLATED, L10N_STATUS_HAS_SUGGESTION and - * L10N_STATUS_TRANSLATED. + * L10N_STATUS_UNTRANSLATED, L10N_STATUS_HAS_SUGGESTION, + * L10N_STATUS_TRANSLATED, L10N_STATUS_UNSTABLE, L10N_STATUS_STABLE. * @param $release * Release id of the particular project release to filter with. * Use NULL to not filter on releases. @@ -629,13 +642,13 @@ function l10n_community_get_strings($langcode, $project = NULL, $status = L10N_S if (!isset($project)) { // No project based filtering. - $sql = "SELECT DISTINCT s.sid, s.value, s.context, t.tid, t.language, t.translation, t.uid_entered, t.uid_approved, t.time_entered, t.time_approved, t.has_suggestion, t.is_suggestion, t.is_active FROM {l10n_community_string} s LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE"; + $sql = "SELECT DISTINCT s.sid, s.value, s.context, t.tid, t.language, t.translation, t.uid_entered, t.uid_approved, t.time_entered, t.time_approved, t.has_suggestion, t.is_suggestion, t.is_active, t.is_stable FROM {l10n_community_string} s LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE"; $sql_count = "SELECT COUNT(DISTINCT(s.sid)) FROM {l10n_community_string} s LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE"; $sql_args = array($langcode); } else { // Project based filtering and language based filtering built in. - $sql = "SELECT DISTINCT s.sid, s.value, s.context, t.tid, t.language, t.translation, t.uid_entered, t.uid_approved, t.time_entered, t.time_approved, t.has_suggestion, t.is_suggestion, t.is_active FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE r.pid = %d"; + $sql = "SELECT DISTINCT s.sid, s.value, s.context, t.tid, t.language, t.translation, t.uid_entered, t.uid_approved, t.time_entered, t.time_approved, t.has_suggestion, t.is_suggestion, t.is_active, t.is_stable FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE r.pid = %d"; $sql_count = "SELECT COUNT(DISTINCT(s.sid)) FROM {l10n_community_release} r INNER JOIN {l10n_community_file} f ON r.rid = f.rid INNER JOIN {l10n_community_line} l ON f.fid = l.fid INNER JOIN {l10n_community_string} s ON l.sid = s.sid LEFT JOIN {l10n_community_translation} t ON s.sid = t.sid AND t.language = '%s' AND t.is_active = 1 AND t.is_suggestion = 0 WHERE r.pid = %d"; $sql_args = array($langcode, $project->pid); } @@ -681,6 +694,12 @@ function l10n_community_get_strings($langcode, $project = NULL, $status = L10N_S elseif ($status & L10N_STATUS_NO_SUGGESTION) { $status_sql .= " AND t.has_suggestion = 0"; } + if ($status & L10N_STATUS_UNSTABLE) { + $status_sql .= " AND (t.is_stable IS NULL OR t.is_stable <> 1)"; + } + elseif ($status & L10N_STATUS_STABLE) { + $status_sql .= " AND t.is_stable = 1"; + } $sql .= $status_sql; $sql_count .= $status_sql;