diff --git a/core/includes/gettext.inc b/core/includes/gettext.inc
index 95e84cf..dac9d73 100644
--- a/core/includes/gettext.inc
+++ b/core/includes/gettext.inc
@@ -26,8 +26,11 @@
  * @param $mode
  *   Should existing translations be replaced LOCALE_IMPORT_KEEP or
  *   LOCALE_IMPORT_OVERWRITE.
+ * @param $customized
+ *   Whether the strings being imported should be saved as customized.
+ *   Use LOCALE_CUSTOMIZED or LOCALE_NOT_CUSTOMIZED.
  */
-function _locale_import_po($file, $langcode, $mode) {
+function _locale_import_po($file, $langcode, $mode, $customized = LOCALE_NOT_CUSTOMIZED) {
   // Try to allocate enough time to parse and import the data.
   drupal_set_time_limit(240);
 
@@ -38,7 +41,7 @@ function _locale_import_po($file, $langcode, $mode) {
   }
 
   // Get strings from file (returns on failure after a partial import, or on success)
-  $status = _locale_import_read_po('db-store', $file, $mode, $langcode);
+  $status = _locale_import_read_po('db-store', $file, $mode, $langcode, $customized);
   if ($status === FALSE) {
     // Error messages are set in _locale_import_read_po().
     return FALSE;
@@ -85,8 +88,11 @@ function _locale_import_po($file, $langcode, $mode) {
  *   LOCALE_IMPORT_OVERWRITE.
  * @param $lang
  *   Language code.
+ * @param $customized
+ *   Whether the strings being imported should be saved as customized.
+ *   Use LOCALE_CUSTOMIZED or LOCALE_NOT_CUSTOMIZED.
  */
-function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL) {
+function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $customized = LOCALE_NOT_CUSTOMIZED) {
 
   // The file will get closed by PHP on returning from this function.
   $fd = fopen($file->uri, 'rb');
@@ -138,7 +144,7 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL) {
       }
       elseif (($context == 'MSGSTR') || ($context == 'MSGSTR_ARR')) {
         // We are currently in string token, close it out.
-        _locale_import_one_string($op, $current, $mode, $lang, $file);
+        _locale_import_one_string($op, $current, $mode, $lang, $file, $customized);
 
         // Start a new entry for the comment.
         $current         = array();
@@ -182,7 +188,7 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL) {
 
       if (($context == 'MSGSTR') || ($context == 'MSGSTR_ARR')) {
         // We are currently in a message string, close it out.
-        _locale_import_one_string($op, $current, $mode, $lang, $file);
+        _locale_import_one_string($op, $current, $mode, $lang, $file, $customized);
 
         // Start a new context for the id.
         $current = array();
@@ -212,7 +218,7 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL) {
 
       if (($context == 'MSGSTR') || ($context == 'MSGSTR_ARR')) {
         // We are currently in a message, start a new one.
-        _locale_import_one_string($op, $current, $mode, $lang, $file);
+        _locale_import_one_string($op, $current, $mode, $lang, $file, $customized);
         $current = array();
       }
       elseif (!empty($current['msgctxt'])) {
@@ -326,7 +332,7 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL) {
 
   // End of PO file, closed out the last entry.
   if (($context == 'MSGSTR') || ($context == 'MSGSTR_ARR')) {
-    _locale_import_one_string($op, $current, $mode, $lang, $file);
+    _locale_import_one_string($op, $current, $mode, $lang, $file, $customized);
   }
   elseif ($context != 'COMMENT') {
     _locale_import_message('The translation file %filename ended unexpectedly at line %line.', $file, $lineno);
@@ -368,8 +374,11 @@ function _locale_import_message($message, $file, $lineno = NULL) {
  * @param $file
  *   Object representation of file being imported, only required when op is
  *   'db-store'.
+ * @param $customized
+ *   Whether the strings being imported should be saved as customized.
+ *   Use LOCALE_CUSTOMIZED or LOCALE_NOT_CUSTOMIZED.
  */
-function _locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NULL, $file = NULL) {
+function _locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NULL, $file = NULL, $customized = LOCALE_NOT_CUSTOMIZED) {
   $report = &drupal_static(__FUNCTION__, array('additions' => 0, 'updates' => 0, 'deletes' => 0, 'skips' => 0));
   $header_done = &drupal_static(__FUNCTION__ . ':header_done', FALSE);
   $strings = &drupal_static(__FUNCTION__ . ':strings', array());
@@ -429,7 +438,7 @@ function _locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NUL
             if ($key == 0) {
               $plid = 0;
             }
-            $plid = _locale_import_one_string_db($report, $lang, isset($value['msgctxt']) ? $value['msgctxt'] : '', $english[$key], $trans, $comments, $mode, $plid, $key);
+            $plid = _locale_import_one_string_db($report, $lang, isset($value['msgctxt']) ? $value['msgctxt'] : '', $english[$key], $trans, $comments, $mode, $customized, $plid, $key);
           }
         }
 
@@ -437,7 +446,7 @@ function _locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NUL
           // A simple string to import.
           $english = $value['msgid'];
           $translation = $value['msgstr'];
-          _locale_import_one_string_db($report, $lang, isset($value['msgctxt']) ? $value['msgctxt'] : '', $english, $translation, $comments, $mode);
+          _locale_import_one_string_db($report, $lang, isset($value['msgctxt']) ? $value['msgctxt'] : '', $english, $translation, $comments, $mode, $customized);
         }
       }
   } // end of db-store operation
@@ -461,6 +470,9 @@ function _locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NUL
  *   Location value to save with source string.
  * @param $mode
  *   Import mode to use, LOCALE_IMPORT_KEEP or LOCALE_IMPORT_OVERWRITE.
+ * @param $customized
+ *   Whether the strings being imported should be saved as customized.
+ *   Use LOCALE_CUSTOMIZED or LOCALE_NOT_CUSTOMIZED.
  * @param $plid
  *   Optional plural ID to use.
  * @param $plural
@@ -469,7 +481,7 @@ function _locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NUL
  * @return
  *   The string ID of the existing string modified or the new string added.
  */
-function _locale_import_one_string_db(&$report, $langcode, $context, $source, $translation, $location, $mode, $plid = 0, $plural = 0) {
+function _locale_import_one_string_db(&$report, $langcode, $context, $source, $translation, $location, $mode, $customized = LOCALE_NOT_CUSTOMIZED, $plid = 0, $plural = 0) {
   $lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = :context", array(':source' => $source, ':context' => $context))->fetchField();
 
   if (!empty($translation)) {
@@ -499,6 +511,7 @@ function _locale_import_one_string_db(&$report, $langcode, $context, $source, $t
             'translation' => $translation,
             'plid' => $plid,
             'plural' => $plural,
+            'customized' => $customized,
           ))
           ->execute();
 
@@ -511,6 +524,7 @@ function _locale_import_one_string_db(&$report, $langcode, $context, $source, $t
             'translation' => $translation,
             'plid' => $plid,
             'plural' => $plural,
+            'customized' => $customized,
           ))
           ->condition('language', $langcode)
           ->condition('lid', $lid)
@@ -535,7 +549,8 @@ function _locale_import_one_string_db(&$report, $langcode, $context, $source, $t
            'language' => $langcode,
            'translation' => $translation,
            'plid' => $plid,
-           'plural' => $plural
+           'plural' => $plural,
+           'customized' => $customized,
         ))
         ->execute();
 
@@ -866,17 +881,32 @@ function _locale_import_parse_quoted($string) {
  * @param $language
  *   Language object to generate the output for, or NULL if generating
  *   translation template.
+ * @param $customized
+ *   Customization status of translation strings; if not NULL, only
+ *   translations with this status (LOCALE_NOT_CUSTOMIZED / LOCALE_CUSTOMIZED)
+ *   will be exported. Ignored if $language is NULL.
  *
  * @return
  *   An array of translated strings that can be used to generate an export.
  */
-function _locale_export_get_strings($language = NULL) {
-  if (isset($language)) {
-    $result = db_query("SELECT s.lid, s.source, s.context, s.location, t.translation, t.plid, t.plural FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = :language ORDER BY t.plid, t.plural", array(':language' => $language->langcode));
+function _locale_export_get_strings($language = NULL, $customized = NULL) {
+
+  $query = db_select('locales_source', 's');
+  if (!empty($language)) {
+    $query->leftJoin('locales_target', 't', 's.lid = t.lid AND t.language = :language', array(':language' => $language->langcode));
+    if (isset($customized)) {
+      $query->condition('t.customized', $customized);
+    }
+    $query->fields('t', array('translation'));
   }
   else {
-    $result = db_query("SELECT s.lid, s.source, s.context, s.location, t.plid, t.plural FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid ORDER BY t.plid, t.plural");
+    $query->leftJoin('locales_target', 't', 's.lid = t.lid');
   }
+  $query->fields('s', array('lid', 'source', 'context', 'location'))
+    ->fields('t', array('plid', 'plural'))
+    ->orderBy('t.plid')
+    ->orderBy('t.plural');
+
   $strings = array();
   foreach ($result as $child) {
     $string = array(
diff --git a/core/includes/locale.inc b/core/includes/locale.inc
index 8a381ed..b74e86b 100644
--- a/core/includes/locale.inc
+++ b/core/includes/locale.inc
@@ -73,6 +73,22 @@ define('LOCALE_JS_OBJECT_CONTEXT', '
 ');
 
 /**
+ * Flag for locally not customized interface translation.
+ *
+ * Such translations are imported from .po files downloaded from
+ * localize.drupal.org for example.
+ */
+const LOCALE_NOT_CUSTOMIZED = 0;
+
+/**
+ * Flag for locally customized interface translation.
+ *
+ * Such translations are edited from their imported originals on the user
+ * interface or are imported as customized.
+ */
+const LOCALE_CUSTOMIZED = 1;
+
+/**
  * Translation import mode overwriting all existing translations
  * if new translated version available.
  */
diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc
index a4982e1..666f2e7 100644
--- a/core/modules/locale/locale.bulk.inc
+++ b/core/modules/locale/locale.bulk.inc
@@ -39,21 +39,30 @@ function locale_translate_import_form($form, &$form_state) {
     );
   }
 
-  $form['import'] = array('#type' => 'fieldset',
+  $form['import'] = array(
+    '#type' => 'fieldset',
     '#title' => t('Import translation'),
   );
-  $form['import']['file'] = array('#type' => 'file',
+  $form['import']['file'] = array(
+    '#type' => 'file',
     '#title' => t('Language file'),
     '#size' => 50,
     '#description' => t('A Gettext Portable Object (<em>.po</em>) file.'),
   );
-  $form['import']['langcode'] = array('#type' => 'select',
+  $form['import']['langcode'] = array(
+    '#type' => 'select',
     '#title' => t('Import into'),
     '#options' => $language_options,
     '#default_value' => $default,
     '#description' => t('Choose the language you want to add strings into. If you choose a language which is not yet set up, it will be added.'),
   );
-  $form['import']['mode'] = array('#type' => 'radios',
+  $form['import']['customized'] = array(
+    '#title' => t('Import as customized translations'),
+    '#type' => 'checkbox',
+    '#description' => t('Check if the file you import contains custom translations and was not obtained from a base translation resource such as localize.drupal.org.'),
+  );
+  $form['import']['mode'] = array(
+    '#type' => 'radios',
     '#title' => t('Mode'),
     '#default_value' => LOCALE_IMPORT_KEEP,
     '#options' => array(
@@ -87,9 +96,10 @@ function locale_translate_import_form_submit($form, &$form_state) {
       language_save($language);
       drupal_set_message(t('The language %language has been created.', array('%language' => t($predefined[$langcode][0]))));
     }
+    $customized = $form_state['values']['customized'] ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED;
 
     // Now import strings into the language
-    if ($return = _locale_import_po($file, $langcode, $form_state['values']['mode']) == FALSE) {
+    if ($return = _locale_import_po($file, $langcode, $form_state['values']['mode'], $customized) == FALSE) {
       $variables = array('%filename' => $file->filename);
       drupal_set_message(t('The translation import of %filename failed.', $variables), 'error');
       watchdog('locale', 'The translation import of %filename failed.', $variables, WATCHDOG_ERROR);
@@ -137,14 +147,27 @@ function locale_translate_export_screen() {
  *   An associate array with localized language names
  */
 function locale_translate_export_po_form($form, &$form_state, $names) {
-  $form['export_title'] = array('#type' => 'item',
+  $form['export_title'] = array(
+    '#type' => 'item',
     '#title' => t('Export translation'),
   );
-  $form['langcode'] = array('#type' => 'select',
+  $form['langcode'] = array(
+    '#type' => 'select',
     '#title' => t('Language name'),
     '#options' => $names,
     '#description' => t('Select the language to export in Gettext Portable Object (<em>.po</em>) format.'),
   );
+  $form['customized'] = array(
+    '#type' => 'radios',
+    '#title' => t('Customization status'),
+    '#options' => array(
+      -1 => t('All translations'),
+      LOCALE_NOT_CUSTOMIZED => t('Non-customized translations only'),
+      LOCALE_CUSTOMIZED => t('Customized translations only'),
+    ),
+    '#default_value' => -1,
+  );
+
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Export'));
   return $form;
@@ -172,11 +195,13 @@ function locale_translate_export_pot_form() {
 function locale_translate_export_po_form_submit($form, &$form_state) {
   // If template is required, language code is not given.
   $language = NULL;
+  $customized = NULL;
   if (isset($form_state['values']['langcode'])) {
     $languages = language_list();
     $language = $languages[$form_state['values']['langcode']];
+    $customized = ($form_state['values']['customized'] == -1) ? NULL : $form_state['values']['customized'];
   }
-  _locale_export_po($language, _locale_export_po_generate($language, _locale_export_get_strings($language)));
+  _locale_export_po($language, _locale_export_po_generate($language, _locale_export_get_strings($language, $customized)));
 }
 
 /**
diff --git a/core/modules/locale/locale.css b/core/modules/locale/locale.css
index 38112b5..c5495fc 100644
--- a/core/modules/locale/locale.css
+++ b/core/modules/locale/locale.css
@@ -6,7 +6,7 @@
 
 #locale-translation-filter-form .form-item-language,
 #locale-translation-filter-form .form-item-translation,
-#locale-translation-filter-form .form-item-group {
+#locale-translation-filter-form .form-item-customized {
   float: left; /* LTR */
   padding-right: .8em; /* LTR */
   margin: 0.1em;
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index a8bcb2d..9ffc774 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -188,6 +188,11 @@ function locale_schema() {
         'default' => 0,
         'description' => 'Plural index number in case of plural strings.',
       ),
+      'customized' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0, // LOCALE_NOT_CUSTOMIZED
+      ),
     ),
     'primary key' => array('language', 'lid', 'plural'),
     'foreign keys' => array(
@@ -319,6 +324,27 @@ function locale_update_8002() {
 }
 
 /**
+ * Adds customized column to locales_target.
+ */
+function locale_update_8003() {
+  $spec = array(
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0, // LOCALE_NOT_CUSTOMIZED
+  );
+  db_add_field('locales_target', 'customized', $spec);
+
+  // If l10n_update module was installed retain its status data,
+  // but drop the old field from the table.
+  if (db_field_exists('locales_target', 'l10n_status')) {
+    db_update('locales_target')
+      ->expression('customized', 'l10n_status')
+      ->execute();
+    db_drop_field('locales_target', 'l10n_status');
+  }
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x"
  * The next series of updates should start at 9000.
  */
diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc
index e41bae5..6f4299f 100644
--- a/core/modules/locale/locale.pages.inc
+++ b/core/modules/locale/locale.pages.inc
@@ -29,6 +29,7 @@ function _locale_translate_seek() {
     $query = array(
       'translation' => 'all',
       'language' => 'all',
+      'customized' => 'all',
       'string' => '',
     );
   }
@@ -36,13 +37,16 @@ function _locale_translate_seek() {
   $sql_query = db_select('locales_source', 's');
   $sql_query->leftJoin('locales_target', 't', 't.lid = s.lid');
   $sql_query->fields('s', array('source', 'location', 'context', 'lid'));
-  $sql_query->fields('t', array('translation', 'language'));
+  $sql_query->fields('t', array('translation', 'language', 'customized'));
 
   // Compute LIKE section.
   switch ($query['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'], '=');
+      }
       break;
     case 'untranslated':
       $sql_query->condition(db_and()
@@ -134,7 +138,7 @@ function _locale_translate_seek_query() {
   $query = &drupal_static(__FUNCTION__);
   if (!isset($query)) {
     $query = array();
-    $fields = array('string', 'language', 'translation');
+    $fields = array('string', 'language', 'translation', 'customized');
     foreach ($fields as $field) {
       if (isset($_SESSION['locale_translation_filter'][$field])) {
         $query[$field] = $_SESSION['locale_translation_filter'][$field];
@@ -172,7 +176,25 @@ function locale_translation_filters() {
 
   $filters['translation'] = array(
     'title' => t('Search in'),
-    'options' => array('all' => t('Both translated and untranslated strings'), 'translated' => t('Only translated strings'), 'untranslated' => t('Only untranslated strings')),
+    'options' => array(
+      'all' => t('Both translated and untranslated strings'),
+      'translated' => t('Only translated strings'),
+      'untranslated' => t('Untranslated strings')
+    ),
+  );
+
+  $filters['customized'] = array(
+    'title' => t('Customized'),
+    'options' => array(
+      'all' => t('All'),
+      LOCALE_NOT_CUSTOMIZED => t('Non-customized only'),
+      LOCALE_CUSTOMIZED => t('Customized only'),
+    ),
+    'states' => array(
+      'visible' => array(
+        ':input[name=translation]' => array('value' => 'translated'),
+      )
+    ),
   );
 
   return $filters;
@@ -210,6 +232,9 @@ function locale_translation_filter_form() {
         '#size' => 0,
         '#options' => $filter['options'],
       );
+      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];
@@ -353,21 +378,23 @@ function locale_translate_edit_form_submit($form, &$form_state) {
     $translation = db_query("SELECT translation FROM {locales_target} WHERE lid = :lid AND language = :language", array(':lid' => $lid, ':language' => $key))->fetchField();
     if (!empty($value)) {
       // Only update or insert if we have a value to use.
-      if (!empty($translation)) {
+      if (!empty($translation) && ($translation != $value)) {
         db_update('locales_target')
           ->fields(array(
             'translation' => $value,
+            'customized' => LOCALE_CUSTOMIZED,
           ))
           ->condition('lid', $lid)
           ->condition('language', $key)
           ->execute();
       }
-      else {
+      if (empty($translation)) {
         db_insert('locales_target')
           ->fields(array(
             'lid' => $lid,
             'translation' => $value,
             'language' => $key,
+            'customized' => LOCALE_CUSTOMIZED,
           ))
           ->execute();
       }
