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. <a href="@flag" class="flag-link" onclick="return l10nCommunity.flagTranslation('. $sid .', this);">Withdraw flag</a>', array('@flag' => $url));
+      }
+      else {
+        $output .= t('Not flagged. <a href="@flag" class="flag-link" onclick="return l10nCommunity.flagTranslation('. $sid .', this);">Flag as stable</a>', 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 '<div'. $class .'><span class="string">'. $string .'</span><span class="original hidden">'. $original .'</span></div>';
+  if ($flag) {
+    $flag = ' <span class="stable">'. t('(stable)') .'</span> ';
+  }
+  else {
+    $flag = '';
+  }
+
+  return '<div'. $class .'><span class="string">'. $string .'</span>'. $flag .'<span class="original hidden">'. $original .'</span></div>';
 }
 
 /**
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('<Any>'),
+    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 = "<div class='toolbox'>$toolbox</div>";
     $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']) .'</div>';
-      $translation_pane .= "<div class='pane suggestions'></div><div class='pane lookup'></div>";
+      $translation_pane .= "<div class='pane suggestions'></div><div class='pane lookup'></div><div class='pane flag'></div>";
       $translation_pane .= "</div>";
       $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;
 
