diff --git a/includes/locale.inc b/includes/locale.inc
index 6154cf3c355ce9e9c2e53b2761089ed86c846746..d0b11f83bf7d1dbc866aa517a39a8fa71f385afc 100644
--- a/includes/locale.inc
+++ b/includes/locale.inc
@@ -1688,129 +1688,6 @@ function _locale_export_remove_plural($entry) {
  * @} End of "locale-api-import-export"
  */
 
-/**
- * @defgroup locale-api-seek Translation search API
- * @{
- * Functions to search in translation files.
- *
- * These functions provide the functionality to search for specific
- * translations.
- */
-
-/**
- * Perform a string search and display results in a table
- */
-function _locale_translate_seek() {
-  $output = '';
-
-  // We have at least one criterion to match
-  if (!($query = _locale_translate_seek_query())) {
-    $query = array(
-      'translation' => 'all',
-      'group' => 'all',
-      'language' => 'all',
-      'string' => '',
-    );
-  }
-
-  $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', 'textgroup'));
-  $sql_query->fields('t', array('translation', 'language'));
-
-  // Compute LIKE section.
-  switch ($query['translation']) {
-    case 'translated':
-      $sql_query->condition('t.translation', '%' . db_like($query['string']) . '%', 'LIKE');
-      $sql_query->orderBy('t.translation', 'DESC');
-      break;
-    case 'untranslated':
-      $sql_query->condition(db_and()
-        ->condition('s.source', '%' . db_like($query['string']) . '%', 'LIKE')
-        ->isNull('t.translation')
-      );
-      $sql_query->orderBy('s.source');
-      break;
-    case 'all' :
-    default:
-      $condition = db_or()
-        ->condition('s.source', '%' . db_like($query['string']) . '%', 'LIKE');
-      if ($query['language'] != 'en') {
-        // Only search in translations if the language is not forced to English.
-        $condition->condition('t.translation', '%' . db_like($query['string']) . '%', 'LIKE');
-      }
-      $sql_query->condition($condition);
-      break;
-  }
-
-  $limit_language = NULL;
-  if ($query['language'] != 'en' && $query['language'] != 'all') {
-    $sql_query->condition('language', $query['language']);
-    $limit_language = $query['language'];
-  }
-
-  // Add a condition on the text group.
-  if (!empty($query['group']) && $query['group'] != 'all') {
-    $sql_query->condition('s.textgroup', $query['group']);
-  }
-
-  $sql_query = $sql_query->extend('PagerDefault')->limit(50);
-  $locales = $sql_query->execute();
-
-  $groups = module_invoke_all('locale', 'groups');
-  $header = array(t('Text group'), t('String'), t('Context'), ($limit_language) ? t('Language') : t('Languages'), array('data' => t('Operations'), 'colspan' => '2'));
-
-  $strings = array();
-  foreach ($locales as $locale) {
-    if (!isset($strings[$locale->lid])) {
-      $strings[$locale->lid] = array(
-        'group' => $locale->textgroup,
-        'languages' => array(),
-        'location' => $locale->location,
-        'source' => $locale->source,
-        'context' => $locale->context,
-      );
-    }
-    if (isset($locale->language)) {
-      $strings[$locale->lid]['languages'][$locale->language] = $locale->translation;
-    }
-  }
-
-  $rows = array();
-  foreach ($strings as $lid => $string) {
-    $rows[] = array(
-      $groups[$string['group']],
-      array('data' => check_plain(truncate_utf8($string['source'], 150, FALSE, TRUE)) . '<br /><small>' . $string['location'] . '</small>'),
-      $string['context'],
-      array('data' => _locale_translate_language_list($string['languages'], $limit_language), 'align' => 'center'),
-      array('data' => l(t('edit'), "admin/config/regional/translate/edit/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
-      array('data' => l(t('delete'), "admin/config/regional/translate/delete/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
-    );
-  }
-
-  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'empty' => t('No strings available.')));
-  $output .= theme('pager');
-
-  return $output;
-}
-
-/**
- * Build array out of search criteria specified in request variables
- */
-function _locale_translate_seek_query() {
-  $query = &drupal_static(__FUNCTION__);
-  if (!isset($query)) {
-    $query = array();
-    $fields = array('string', 'language', 'translation', 'group');
-    foreach ($fields as $field) {
-      if (isset($_SESSION['locale_translation_filter'][$field])) {
-        $query[$field] = $_SESSION['locale_translation_filter'][$field];
-      }
-    }
-  }
-  return $query;
-}
-
 /**
  * Force the JavaScript translation file(s) to be refreshed.
  *
@@ -1974,28 +1851,6 @@ function _locale_rebuild_js($langcode = NULL) {
   }
 }
 
-/**
- * List languages in search result table
- */
-function _locale_translate_language_list($translation, $limit_language) {
-  // Add CSS.
-  drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
-
-  $languages = language_list();
-  unset($languages['en']);
-  $output = '';
-  foreach ($languages as $langcode => $language) {
-    if (!$limit_language || $limit_language == $langcode) {
-      $output .= (!empty($translation[$langcode])) ? $langcode . ' ' : "<em class=\"locale-untranslated\">$langcode</em> ";
-    }
-  }
-
-  return $output;
-}
-/**
- * @} End of "locale-api-seek"
- */
-
 /**
  * @defgroup locale-api-predefined List of predefined languages
  * @{
diff --git a/modules/locale/locale.admin.inc b/modules/locale/locale.admin.inc
index b0a77c5b6ed1d619e239288e1c66831e993565d1..ad7a583a74a7d2a5102a9a21cda40a2569c71b9d 100644
--- a/modules/locale/locale.admin.inc
+++ b/modules/locale/locale.admin.inc
@@ -743,186 +743,6 @@ function locale_language_providers_session_form($form, &$form_state) {
  * @} End of "locale-language-administration"
  */
 
-/**
- * @defgroup locale-translate-administration-screens Translation administration screens
- * @{
- * Screens for translation administration.
- *
- * These functions provide various screens as administration interface
- * to import, export and view translations.
- */
-
-/**
- * Overview screen for translations.
- */
-function locale_translate_overview_screen() {
-  drupal_static_reset('language_list');
-  $languages = language_list('language');
-  $groups = module_invoke_all('locale', 'groups');
-
-  // Build headers with all groups in order.
-  $headers = array_merge(array(t('Language')), array_values($groups));
-
-  // Collect summaries of all source strings in all groups.
-  $sums = db_query("SELECT COUNT(*) AS strings, textgroup FROM {locales_source} GROUP BY textgroup");
-  $groupsums = array();
-  foreach ($sums as $group) {
-    $groupsums[$group->textgroup] = $group->strings;
-  }
-
-  // Set up overview table with default values, ensuring common order for values.
-  $rows = array();
-  foreach ($languages as $langcode => $language) {
-    $rows[$langcode] = array('name' => ($langcode == 'en' ? t('English (built-in)') : t($language->name)));
-    foreach ($groups as $group => $name) {
-      $rows[$langcode][$group] = ($langcode == 'en' ? t('n/a') : '0/' . (isset($groupsums[$group]) ? $groupsums[$group] : 0) . ' (0%)');
-    }
-  }
-
-  // Languages with at least one record in the locale table.
-  $translations = db_query("SELECT COUNT(*) AS translation, t.language, s.textgroup FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid GROUP BY textgroup, language");
-  foreach ($translations as $data) {
-    $ratio = (!empty($groupsums[$data->textgroup]) && $data->translation > 0) ? round(($data->translation/$groupsums[$data->textgroup]) * 100.0, 2) : 0;
-    $rows[$data->language][$data->textgroup] = $data->translation . '/' . $groupsums[$data->textgroup] . " ($ratio%)";
-  }
-
-  return theme('table', array('header' => $headers, 'rows' => $rows));
-}
-
-/**
- * String search screen.
- */
-function locale_translate_seek_screen() {
-  // Add CSS.
-  drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
-
-  $elements = drupal_get_form('locale_translation_filter_form');
-  $output = drupal_render($elements);
-  $output .= _locale_translate_seek();
-  return $output;
-}
-
-/**
- * List locale translation filters that can be applied.
- */
-function locale_translation_filters() {
-  $filters = array();
-
-  // Get all languages, except English
-  drupal_static_reset('language_list');
-  $languages = locale_language_list('name');
-  unset($languages['en']);
-
-  $filters['string'] = array(
-    'title' => t('String contains'),
-    'description' => t('Leave blank to show all strings. The search is case sensitive.'),
-  );
-
-  $filters['language'] = array(
-    'title' => t('Language'),
-    'options' => array_merge(array('all' => t('All languages'), 'en' => t('English (provided by Drupal)')), $languages),
-  );
-
-  $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')),
-  );
-
-  $groups = module_invoke_all('locale', 'groups');
-  $filters['group'] = array(
-    'title' => t('Limit search to'),
-    'options' => array_merge(array('all' => t('All text groups')), $groups),
-  );
-
-  return $filters;
-}
-
-/**
- * Return form for locale translation filters.
- *
- * @ingroup forms
- */
-function locale_translation_filter_form() {
-  $filters = locale_translation_filters();
-
-  $form['filters'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Filter translatable strings'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-  );
-  foreach ($filters as $key => $filter) {
-    // Special case for 'string' filter.
-    if ($key == 'string') {
-      $form['filters']['status']['string'] = array(
-        '#type' => 'textfield',
-        '#title' => $filter['title'],
-        '#description' => $filter['description'],
-      );
-    }
-    else {
-      $form['filters']['status'][$key] = array(
-        '#title' => $filter['title'],
-        '#type' => 'select',
-        '#empty_value' => 'all',
-        '#empty_option' => $filter['options']['all'],
-        '#size' => 0,
-        '#options' => $filter['options'],
-      );
-    }
-    if (!empty($_SESSION['locale_translation_filter'][$key])) {
-      $form['filters']['status'][$key]['#default_value'] = $_SESSION['locale_translation_filter'][$key];
-    }
-  }
-
-  $form['filters']['actions'] = array(
-    '#type' => 'actions',
-    '#attributes' => array('class' => array('container-inline')),
-  );
-  $form['filters']['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Filter'),
-  );
-  if (!empty($_SESSION['locale_translation_filter'])) {
-    $form['filters']['actions']['reset'] = array(
-      '#type' => 'submit',
-      '#value' => t('Reset')
-    );
-  }
-
-  return $form;
-}
-
-/**
- * Validate result from locale translation filter form.
- */
-function locale_translation_filter_form_validate($form, &$form_state) {
-  if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['language']) && empty($form_state['values']['group'])) {
-    form_set_error('type', t('You must select something to filter by.'));
-  }
-}
-
-/**
- * Process result from locale translation filter form.
- */
-function locale_translation_filter_form_submit($form, &$form_state) {
-  $op = $form_state['values']['op'];
-  $filters = locale_translation_filters();
-  switch ($op) {
-    case t('Filter'):
-      foreach ($filters as $name => $filter) {
-        if (isset($form_state['values'][$name])) {
-          $_SESSION['locale_translation_filter'][$name] = $form_state['values'][$name];
-        }
-      }
-      break;
-    case t('Reset'):
-      $_SESSION['locale_translation_filter'] = array();
-      break;
-  }
-
-  $form_state['redirect'] = 'admin/config/regional/translate/translate';
-}
 
 /**
  * User interface for the translation import screen.
@@ -1091,191 +911,6 @@ function locale_translate_export_po_form_submit($form, &$form_state) {
   }
   _locale_export_po($language, _locale_export_po_generate($language, _locale_export_get_strings($language, $form_state['values']['group'])));
 }
-/**
- * @} End of "locale-translate-administration-screens"
- */
-
-/**
- * @defgroup locale-translate-edit-delete Translation editing/deletion interface
- * @{
- * Edit and delete translation strings.
- *
- * These functions provide the user interface to edit and delete
- * translation strings.
- */
-
-/**
- * User interface for string editing.
- */
-function locale_translate_edit_form($form, &$form_state, $lid) {
-  // Fetch source string, if possible.
-  $source = db_query('SELECT source, context, textgroup, location FROM {locales_source} WHERE lid = :lid', array(':lid' => $lid))->fetchObject();
-  if (!$source) {
-    drupal_set_message(t('String not found.'), 'error');
-    drupal_goto('admin/config/regional/translate/translate');
-  }
-
-  // Add original text to the top and some values for form altering.
-  $form['original'] = array(
-    '#type'  => 'item',
-    '#title' => t('Original text'),
-    '#markup' => check_plain(wordwrap($source->source, 0)),
-  );
-  if (!empty($source->context)) {
-    $form['context'] = array(
-      '#type' => 'item',
-      '#title' => t('Context'),
-      '#markup' => check_plain($source->context),
-    );
-  }
-  $form['lid'] = array(
-    '#type'  => 'value',
-    '#value' => $lid
-  );
-  $form['textgroup'] = array(
-    '#type'  => 'value',
-    '#value' => $source->textgroup,
-  );
-  $form['location'] = array(
-    '#type'  => 'value',
-    '#value' => $source->location
-  );
-
-  // Include default form controls with empty values for all languages.
-  // This ensures that the languages are always in the same order in forms.
-  $languages = language_list();
-  $default = language_default();
-  // We don't need the default language value, that value is in $source.
-  $omit = $source->textgroup == 'default' ? 'en' : $default->language;
-  unset($languages[($omit)]);
-  $form['translations'] = array('#tree' => TRUE);
-  // Approximate the number of rows to use in the default textarea.
-  $rows = min(ceil(str_word_count($source->source) / 12), 10);
-  foreach ($languages as $langcode => $language) {
-    $form['translations'][$langcode] = array(
-      '#type' => 'textarea',
-      '#title' => t($language->name),
-      '#rows' => $rows,
-      '#default_value' => '',
-    );
-  }
-
-  // Fetch translations and fill in default values in the form.
-  $result = db_query("SELECT DISTINCT translation, language FROM {locales_target} WHERE lid = :lid AND language <> :omit", array(':lid' => $lid, ':omit' => $omit));
-  foreach ($result as $translation) {
-    $form['translations'][$translation->language]['#default_value'] = $translation->translation;
-  }
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save translations'));
-  return $form;
-}
-
-/**
- * Validate string editing form submissions.
- */
-function locale_translate_edit_form_validate($form, &$form_state) {
-  // Locale string check is needed for default textgroup only.
-  $safe_check_needed = $form_state['values']['textgroup'] == 'default';
-  foreach ($form_state['values']['translations'] as $key => $value) {
-    if ($safe_check_needed && !locale_string_is_safe($value)) {
-      form_set_error('translations', t('The submitted string contains disallowed HTML: %string', array('%string' => $value)));
-      watchdog('locale', 'Attempted submission of a translation string with disallowed HTML: %string', array('%string' => $value), WATCHDOG_WARNING);
-    }
-  }
-}
-
-/**
- * Process string editing form submissions.
- *
- * Saves all translations of one string submitted from a form.
- */
-function locale_translate_edit_form_submit($form, &$form_state) {
-  $lid = $form_state['values']['lid'];
-  foreach ($form_state['values']['translations'] as $key => $value) {
-    $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)) {
-        db_update('locales_target')
-          ->fields(array(
-            'translation' => $value,
-          ))
-          ->condition('lid', $lid)
-          ->condition('language', $key)
-          ->execute();
-      }
-      else {
-        db_insert('locales_target')
-          ->fields(array(
-            'lid' => $lid,
-            'translation' => $value,
-            'language' => $key,
-          ))
-          ->execute();
-      }
-    }
-    elseif (!empty($translation)) {
-      // Empty translation entered: remove existing entry from database.
-      db_delete('locales_target')
-        ->condition('lid', $lid)
-        ->condition('language', $key)
-        ->execute();
-    }
-
-    // Force JavaScript translation file recreation for this language.
-    _locale_invalidate_js($key);
-  }
-
-  drupal_set_message(t('The string has been saved.'));
-
-  // Clear locale cache.
-  _locale_invalidate_js();
-  cache_clear_all('locale:', 'cache', TRUE);
-
-  $form_state['redirect'] = 'admin/config/regional/translate/translate';
-  return;
-}
-
-/**
- * String deletion confirmation page.
- */
-function locale_translate_delete_page($lid) {
-  if ($source = db_query('SELECT lid, source FROM {locales_source} WHERE lid = :lid', array(':lid' => $lid))->fetchObject()) {
-    return drupal_get_form('locale_translate_delete_form', $source);
-  }
-  else {
-    return drupal_not_found();
-  }
-}
-
-/**
- * User interface for the string deletion confirmation screen.
- */
-function locale_translate_delete_form($form, &$form_state, $source) {
-  $form['lid'] = array('#type' => 'value', '#value' => $source->lid);
-  return confirm_form($form, t('Are you sure you want to delete the string "%source"?', array('%source' => $source->source)), 'admin/config/regional/translate/translate', t('Deleting the string will remove all translations of this string in all languages. This action cannot be undone.'), t('Delete'), t('Cancel'));
-}
-
-/**
- * Process string deletion submissions.
- */
-function locale_translate_delete_form_submit($form, &$form_state) {
-  db_delete('locales_source')
-    ->condition('lid', $form_state['values']['lid'])
-    ->execute();
-  db_delete('locales_target')
-    ->condition('lid', $form_state['values']['lid'])
-    ->execute();
-  // Force JavaScript translation file recreation for all languages.
-  _locale_invalidate_js();
-  cache_clear_all('locale:', 'cache', TRUE);
-  drupal_set_message(t('The string has been removed.'));
-  $form_state['redirect'] = 'admin/config/regional/translate/translate';
-}
-/**
- * @} End of "locale-translate-edit-delete"
- */
 
 /**
  * Returns HTML for a locale date format form.
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 07884614a51e6b2d84ae1c91b842bbb83df46200..871048be0d6d70338893ce1a5fed775b2dc7f25f 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -140,7 +140,7 @@ function locale_menu() {
     'description' => 'Translate the built in interface and optionally other text.',
     'page callback' => 'locale_translate_overview_screen',
     'access arguments' => array('translate interface'),
-    'file' => 'locale.admin.inc',
+    'file' => 'locale.pages.inc',
     'weight' => -5,
   );
   $items['admin/config/regional/translate/overview'] = array(
@@ -154,7 +154,7 @@ function locale_menu() {
     'type' => MENU_LOCAL_TASK,
     'page callback' => 'locale_translate_seek_screen', // search results and form concatenated
     'access arguments' => array('translate interface'),
-    'file' => 'locale.admin.inc',
+    'file' => 'locale.pages.inc',
   );
   $items['admin/config/regional/translate/import'] = array(
     'title' => 'Import',
@@ -178,14 +178,14 @@ function locale_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('locale_translate_edit_form', 5),
     'access arguments' => array('translate interface'),
-    'file' => 'locale.admin.inc',
+    '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.admin.inc',
+    'file' => 'locale.pages.inc',
   );
 
   // Localize date formats.
diff --git a/modules/locale/locale.pages.inc b/modules/locale/locale.pages.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b4ccb6b8116ea44d50d0bbd69a90570eccbec64a
--- /dev/null
+++ b/modules/locale/locale.pages.inc
@@ -0,0 +1,500 @@
+<?php
+
+/**
+ * @defgroup locale-translate-administration-screens Translation administration screens
+ * @{
+ * Screens for translation administration.
+ *
+ * These functions provide various screens to view, edit and delete translations.
+ */
+
+/**
+ * Overview screen for translations.
+ */
+function locale_translate_overview_screen() {
+  drupal_static_reset('language_list');
+  $languages = language_list('language');
+  $groups = module_invoke_all('locale', 'groups');
+
+  // Build headers with all groups in order.
+  $headers = array_merge(array(t('Language')), array_values($groups));
+
+  // Collect summaries of all source strings in all groups.
+  $sums = db_query("SELECT COUNT(*) AS strings, textgroup FROM {locales_source} GROUP BY textgroup");
+  $groupsums = array();
+  foreach ($sums as $group) {
+    $groupsums[$group->textgroup] = $group->strings;
+  }
+
+  // Set up overview table with default values, ensuring common order for values.
+  $rows = array();
+  foreach ($languages as $langcode => $language) {
+    $rows[$langcode] = array('name' => ($langcode == 'en' ? t('English (built-in)') : t($language->name)));
+    foreach ($groups as $group => $name) {
+      $rows[$langcode][$group] = ($langcode == 'en' ? t('n/a') : '0/' . (isset($groupsums[$group]) ? $groupsums[$group] : 0) . ' (0%)');
+    }
+  }
+
+  // Languages with at least one record in the locale table.
+  $translations = db_query("SELECT COUNT(*) AS translation, t.language, s.textgroup FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid GROUP BY textgroup, language");
+  foreach ($translations as $data) {
+    $ratio = (!empty($groupsums[$data->textgroup]) && $data->translation > 0) ? round(($data->translation/$groupsums[$data->textgroup]) * 100.0, 2) : 0;
+    $rows[$data->language][$data->textgroup] = $data->translation . '/' . $groupsums[$data->textgroup] . " ($ratio%)";
+  }
+
+  return theme('table', array('header' => $headers, 'rows' => $rows));
+}
+
+/**
+ * String search screen.
+ */
+function locale_translate_seek_screen() {
+  // Add CSS.
+  drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
+
+  $elements = drupal_get_form('locale_translation_filter_form');
+  $output = drupal_render($elements);
+  $output .= _locale_translate_seek();
+  return $output;
+}
+
+/**
+ * Perform a string search and display results in a table
+ */
+function _locale_translate_seek() {
+  $output = '';
+
+  // We have at least one criterion to match
+  if (!($query = _locale_translate_seek_query())) {
+    $query = array(
+      'translation' => 'all',
+      'group' => 'all',
+      'language' => 'all',
+      'string' => '',
+    );
+  }
+
+  $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', 'textgroup'));
+  $sql_query->fields('t', array('translation', 'language'));
+
+  // Compute LIKE section.
+  switch ($query['translation']) {
+    case 'translated':
+      $sql_query->condition('t.translation', '%' . db_like($query['string']) . '%', 'LIKE');
+      $sql_query->orderBy('t.translation', 'DESC');
+      break;
+    case 'untranslated':
+      $sql_query->condition(db_and()
+        ->condition('s.source', '%' . db_like($query['string']) . '%', 'LIKE')
+        ->isNull('t.translation')
+      );
+      $sql_query->orderBy('s.source');
+      break;
+    case 'all' :
+    default:
+      $condition = db_or()
+        ->condition('s.source', '%' . db_like($query['string']) . '%', 'LIKE');
+      if ($query['language'] != 'en') {
+        // Only search in translations if the language is not forced to English.
+        $condition->condition('t.translation', '%' . db_like($query['string']) . '%', 'LIKE');
+      }
+      $sql_query->condition($condition);
+      break;
+  }
+
+  $limit_language = NULL;
+  if ($query['language'] != 'en' && $query['language'] != 'all') {
+    $sql_query->condition('language', $query['language']);
+    $limit_language = $query['language'];
+  }
+
+  // Add a condition on the text group.
+  if (!empty($query['group']) && $query['group'] != 'all') {
+    $sql_query->condition('s.textgroup', $query['group']);
+  }
+
+  $sql_query = $sql_query->extend('PagerDefault')->limit(50);
+  $locales = $sql_query->execute();
+
+  $groups = module_invoke_all('locale', 'groups');
+  $header = array(t('Text group'), t('String'), t('Context'), ($limit_language) ? t('Language') : t('Languages'), array('data' => t('Operations'), 'colspan' => '2'));
+
+  $strings = array();
+  foreach ($locales as $locale) {
+    if (!isset($strings[$locale->lid])) {
+      $strings[$locale->lid] = array(
+        'group' => $locale->textgroup,
+        'languages' => array(),
+        'location' => $locale->location,
+        'source' => $locale->source,
+        'context' => $locale->context,
+      );
+    }
+    if (isset($locale->language)) {
+      $strings[$locale->lid]['languages'][$locale->language] = $locale->translation;
+    }
+  }
+
+  $rows = array();
+  foreach ($strings as $lid => $string) {
+    $rows[] = array(
+      $groups[$string['group']],
+      array('data' => check_plain(truncate_utf8($string['source'], 150, FALSE, TRUE)) . '<br /><small>' . $string['location'] . '</small>'),
+      $string['context'],
+      array('data' => _locale_translate_language_list($string['languages'], $limit_language), 'align' => 'center'),
+      array('data' => l(t('edit'), "admin/config/regional/translate/edit/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
+      array('data' => l(t('delete'), "admin/config/regional/translate/delete/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
+    );
+  }
+
+  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'empty' => t('No strings available.')));
+  $output .= theme('pager');
+
+  return $output;
+}
+
+/**
+ * List languages in search result table
+ */
+function _locale_translate_language_list($translation, $limit_language) {
+  // Add CSS.
+  drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
+
+  $languages = language_list();
+  unset($languages['en']);
+  $output = '';
+  foreach ($languages as $langcode => $language) {
+    if (!$limit_language || $limit_language == $langcode) {
+      $output .= (!empty($translation[$langcode])) ? $langcode . ' ' : "<em class=\"locale-untranslated\">$langcode</em> ";
+    }
+  }
+
+  return $output;
+}
+
+/**
+ * Build array out of search criteria specified in request variables
+ */
+function _locale_translate_seek_query() {
+  $query = &drupal_static(__FUNCTION__);
+  if (!isset($query)) {
+    $query = array();
+    $fields = array('string', 'language', 'translation', 'group');
+    foreach ($fields as $field) {
+      if (isset($_SESSION['locale_translation_filter'][$field])) {
+        $query[$field] = $_SESSION['locale_translation_filter'][$field];
+      }
+    }
+  }
+  return $query;
+}
+
+/**
+ * List locale translation filters that can be applied.
+ */
+function locale_translation_filters() {
+  $filters = array();
+
+  // Get all languages, except English
+  drupal_static_reset('language_list');
+  $languages = locale_language_list('name');
+  unset($languages['en']);
+
+  $filters['string'] = array(
+    'title' => t('String contains'),
+    'description' => t('Leave blank to show all strings. The search is case sensitive.'),
+  );
+
+  $filters['language'] = array(
+    'title' => t('Language'),
+    'options' => array_merge(array('all' => t('All languages'), 'en' => t('English (provided by Drupal)')), $languages),
+  );
+
+  $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')),
+  );
+
+  $groups = module_invoke_all('locale', 'groups');
+  $filters['group'] = array(
+    'title' => t('Limit search to'),
+    'options' => array_merge(array('all' => t('All text groups')), $groups),
+  );
+
+  return $filters;
+}
+
+/**
+ * Return form for locale translation filters.
+ *
+ * @ingroup forms
+ */
+function locale_translation_filter_form() {
+  $filters = locale_translation_filters();
+
+  $form['filters'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Filter translatable strings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+  foreach ($filters as $key => $filter) {
+    // Special case for 'string' filter.
+    if ($key == 'string') {
+      $form['filters']['status']['string'] = array(
+        '#type' => 'textfield',
+        '#title' => $filter['title'],
+        '#description' => $filter['description'],
+      );
+    }
+    else {
+      $form['filters']['status'][$key] = array(
+        '#title' => $filter['title'],
+        '#type' => 'select',
+        '#empty_value' => 'all',
+        '#empty_option' => $filter['options']['all'],
+        '#size' => 0,
+        '#options' => $filter['options'],
+      );
+    }
+    if (!empty($_SESSION['locale_translation_filter'][$key])) {
+      $form['filters']['status'][$key]['#default_value'] = $_SESSION['locale_translation_filter'][$key];
+    }
+  }
+
+  $form['filters']['actions'] = array(
+    '#type' => 'actions',
+    '#attributes' => array('class' => array('container-inline')),
+  );
+  $form['filters']['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Filter'),
+  );
+  if (!empty($_SESSION['locale_translation_filter'])) {
+    $form['filters']['actions']['reset'] = array(
+      '#type' => 'submit',
+      '#value' => t('Reset')
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Validate result from locale translation filter form.
+ */
+function locale_translation_filter_form_validate($form, &$form_state) {
+  if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['language']) && empty($form_state['values']['group'])) {
+    form_set_error('type', t('You must select something to filter by.'));
+  }
+}
+
+/**
+ * Process result from locale translation filter form.
+ */
+function locale_translation_filter_form_submit($form, &$form_state) {
+  $op = $form_state['values']['op'];
+  $filters = locale_translation_filters();
+  switch ($op) {
+    case t('Filter'):
+      foreach ($filters as $name => $filter) {
+        if (isset($form_state['values'][$name])) {
+          $_SESSION['locale_translation_filter'][$name] = $form_state['values'][$name];
+        }
+      }
+      break;
+    case t('Reset'):
+      $_SESSION['locale_translation_filter'] = array();
+      break;
+  }
+
+  $form_state['redirect'] = 'admin/config/regional/translate/translate';
+}
+
+/**
+ * @} End of "locale-translate-administration-screens"
+ */
+
+/**
+ * @defgroup locale-translate-edit-delete Translation editing/deletion interface
+ * @{
+ * Edit and delete translation strings.
+ *
+ * These functions provide the user interface to edit and delete
+ * translation strings.
+ */
+
+/**
+ * User interface for string editing.
+ */
+function locale_translate_edit_form($form, &$form_state, $lid) {
+  // Fetch source string, if possible.
+  $source = db_query('SELECT source, context, textgroup, location FROM {locales_source} WHERE lid = :lid', array(':lid' => $lid))->fetchObject();
+  if (!$source) {
+    drupal_set_message(t('String not found.'), 'error');
+    drupal_goto('admin/config/regional/translate/translate');
+  }
+
+  // Add original text to the top and some values for form altering.
+  $form['original'] = array(
+    '#type'  => 'item',
+    '#title' => t('Original text'),
+    '#markup' => check_plain(wordwrap($source->source, 0)),
+  );
+  if (!empty($source->context)) {
+    $form['context'] = array(
+      '#type' => 'item',
+      '#title' => t('Context'),
+      '#markup' => check_plain($source->context),
+    );
+  }
+  $form['lid'] = array(
+    '#type'  => 'value',
+    '#value' => $lid
+  );
+  $form['textgroup'] = array(
+    '#type'  => 'value',
+    '#value' => $source->textgroup,
+  );
+  $form['location'] = array(
+    '#type'  => 'value',
+    '#value' => $source->location
+  );
+
+  // Include default form controls with empty values for all languages.
+  // This ensures that the languages are always in the same order in forms.
+  $languages = language_list();
+  $default = language_default();
+  // We don't need the default language value, that value is in $source.
+  $omit = $source->textgroup == 'default' ? 'en' : $default->language;
+  unset($languages[($omit)]);
+  $form['translations'] = array('#tree' => TRUE);
+  // Approximate the number of rows to use in the default textarea.
+  $rows = min(ceil(str_word_count($source->source) / 12), 10);
+  foreach ($languages as $langcode => $language) {
+    $form['translations'][$langcode] = array(
+      '#type' => 'textarea',
+      '#title' => t($language->name),
+      '#rows' => $rows,
+      '#default_value' => '',
+    );
+  }
+
+  // Fetch translations and fill in default values in the form.
+  $result = db_query("SELECT DISTINCT translation, language FROM {locales_target} WHERE lid = :lid AND language <> :omit", array(':lid' => $lid, ':omit' => $omit));
+  foreach ($result as $translation) {
+    $form['translations'][$translation->language]['#default_value'] = $translation->translation;
+  }
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save translations'));
+  return $form;
+}
+
+/**
+ * Validate string editing form submissions.
+ */
+function locale_translate_edit_form_validate($form, &$form_state) {
+  // Locale string check is needed for default textgroup only.
+  $safe_check_needed = $form_state['values']['textgroup'] == 'default';
+  foreach ($form_state['values']['translations'] as $key => $value) {
+    if ($safe_check_needed && !locale_string_is_safe($value)) {
+      form_set_error('translations', t('The submitted string contains disallowed HTML: %string', array('%string' => $value)));
+      watchdog('locale', 'Attempted submission of a translation string with disallowed HTML: %string', array('%string' => $value), WATCHDOG_WARNING);
+    }
+  }
+}
+
+/**
+ * Process string editing form submissions.
+ *
+ * Saves all translations of one string submitted from a form.
+ */
+function locale_translate_edit_form_submit($form, &$form_state) {
+  $lid = $form_state['values']['lid'];
+  foreach ($form_state['values']['translations'] as $key => $value) {
+    $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)) {
+        db_update('locales_target')
+          ->fields(array(
+            'translation' => $value,
+          ))
+          ->condition('lid', $lid)
+          ->condition('language', $key)
+          ->execute();
+      }
+      else {
+        db_insert('locales_target')
+          ->fields(array(
+            'lid' => $lid,
+            'translation' => $value,
+            'language' => $key,
+          ))
+          ->execute();
+      }
+    }
+    elseif (!empty($translation)) {
+      // Empty translation entered: remove existing entry from database.
+      db_delete('locales_target')
+        ->condition('lid', $lid)
+        ->condition('language', $key)
+        ->execute();
+    }
+
+    // Force JavaScript translation file recreation for this language.
+    _locale_invalidate_js($key);
+  }
+
+  drupal_set_message(t('The string has been saved.'));
+
+  // Clear locale cache.
+  _locale_invalidate_js();
+  cache_clear_all('locale:', 'cache', TRUE);
+
+  $form_state['redirect'] = 'admin/config/regional/translate/translate';
+  return;
+}
+
+/**
+ * String deletion confirmation page.
+ */
+function locale_translate_delete_page($lid) {
+  if ($source = db_query('SELECT lid, source FROM {locales_source} WHERE lid = :lid', array(':lid' => $lid))->fetchObject()) {
+    return drupal_get_form('locale_translate_delete_form', $source);
+  }
+  else {
+    return drupal_not_found();
+  }
+}
+
+/**
+ * User interface for the string deletion confirmation screen.
+ */
+function locale_translate_delete_form($form, &$form_state, $source) {
+  $form['lid'] = array('#type' => 'value', '#value' => $source->lid);
+  return confirm_form($form, t('Are you sure you want to delete the string "%source"?', array('%source' => $source->source)), 'admin/config/regional/translate/translate', t('Deleting the string will remove all translations of this string in all languages. This action cannot be undone.'), t('Delete'), t('Cancel'));
+}
+
+/**
+ * Process string deletion submissions.
+ */
+function locale_translate_delete_form_submit($form, &$form_state) {
+  db_delete('locales_source')
+    ->condition('lid', $form_state['values']['lid'])
+    ->execute();
+  db_delete('locales_target')
+    ->condition('lid', $form_state['values']['lid'])
+    ->execute();
+  // Force JavaScript translation file recreation for all languages.
+  _locale_invalidate_js();
+  cache_clear_all('locale:', 'cache', TRUE);
+  drupal_set_message(t('The string has been removed.'));
+  $form_state['redirect'] = 'admin/config/regional/translate/translate';
+}
+/**
+ * @} End of "locale-translate-edit-delete"
+ */