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 .''. $original .'
';
+ if ($flag) {
+ $flag = ' '. t('(stable)') .' ';
+ }
+ else {
+ $flag = '';
+ }
+
+ return ''. $string .''. $flag .''. $original .'
';
}
/**
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;