? modules/locale/translations
Index: includes/locale.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/locale.inc,v
retrieving revision 1.201
diff -u -p -r1.201 locale.inc
--- includes/locale.inc	3 Feb 2009 18:55:29 -0000	1.201
+++ includes/locale.inc	3 Feb 2009 22:07:08 -0000
@@ -535,58 +535,135 @@ function locale_translate_overview_scree
  * String search screen.
  */
 function locale_translate_seek_screen() {
-  $output = _locale_translate_seek();
-  $output .= drupal_get_form('locale_translate_seek_form');
+  // Add CSS
+  drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css', array('preprocess' => FALSE));
+
+  $output = drupal_get_form('locale_translation_filter_form');
+  $output .= _locale_translate_seek();
   return $output;
 }
+/**
+ * @} End of "locale-translate-seek"
+ */
 
 /**
- * User interface for the string search screen.
+ * List locale translation filters that can be applied.
  */
-function locale_translate_seek_form() {
+function locale_translation_filters() {
+  $filters = array();
+
   // Get all languages, except English
   $languages = locale_language_list('name', TRUE);
   unset($languages['en']);
-
-  // Present edit form preserving previous user settings
-  $query = _locale_translate_seek_query();
-  $form = array();
-  $form['search'] = array('#type' => 'fieldset',
-    '#title' => t('Search'),
-  );
-  $form['search']['string'] = array('#type' => 'textfield',
-    '#title' => t('String contains'),
-    '#default_value' => @$query['string'],
-    '#description' => t('Leave blank to show all strings. The search is case sensitive.'),
+  
+  $filters['string'] = array(
+    'title' => t('String contains'),
+    'description' => t('Leave blank to show all strings. The search is case sensitive.'),
   );
-  $form['search']['language'] = array(
-    // Change type of form widget if more the 5 options will
-    // be present (2 of the options are added below).
-    '#type' => (count($languages) <= 3 ? 'radios' : 'select'),
-    '#title' => t('Language'),
-    '#default_value' => (!empty($query['language']) ? $query['language'] : 'all'),
-    '#options' => array_merge(array('all' => t('All languages'), 'en' => t('English (provided by Drupal)')), $languages),
+  
+  $filters['language'] = array(
+    'title' => t('Language'),
+    //'where' => "??",
+    'options' => array_merge(array('all' => t('All languages'), 'en' => t('English (provided by Drupal)')), $languages),
   );
-  $form['search']['translation'] = array('#type' => 'radios',
-    '#title' => t('Search in'),
-    '#default_value' => (!empty($query['translation']) ? $query['translation'] : 'all'),
-    '#options' => array('all' => t('Both translated and untranslated strings'), 'translated' => t('Only translated strings'), 'untranslated' => t('Only untranslated strings')),
+  
+  $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');
-  $form['search']['group'] = array('#type' => 'radios',
-    '#title' => t('Limit search to'),
-    '#default_value' => (!empty($query['group']) ? $query['group'] : 'all'),
-    '#options' => array_merge(array('all' => t('All text groups')), $groups),
+  $filters['group'] = array(
+    'title' => t('Limit search to'),
+    'options' => array_merge(array('all' => t('All text groups')), $groups),
   );
 
-  $form['search']['submit'] = array('#type' => 'submit', '#value' => t('Search'));
-  $form['#redirect'] = FALSE;
+  return $filters;
+}
+
+/**
+ * Return form for locale translation filters.
+ *
+ * @ingroup forms
+ */
+function locale_translation_filter_form() {
+  $session = &$_SESSION['locale_translation_filter'];
+  $session = is_array($session) ? $session : array();
+  $filters = locale_translation_filters();
+
+  $form['filters'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Filter translatable strings'),
+    '#theme' => 'dblog_filters',
+    '#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',
+        '#multiple' => FALSE,
+        '#size' => 0,
+        '#options' => $filter['options'],
+      );
+    }
+    if (!empty($session[$key])) {
+      $form['filters']['status'][$key]['#default_value'] = $session[$key];
+    }
+  }
+
+  $form['filters']['buttons']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Filter'),
+  );
+  if (!empty($session)) {
+    $form['filters']['buttons']['reset'] = array(
+      '#type' => 'submit',
+      '#value' => t('Reset')
+    );
+  }
 
   return $form;
 }
+
 /**
- * @} End of "locale-translate-seek"
+ * 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;
+  }
+  return 'admin/build/translate/translate';
+}
 
 /**
  * @defgroup locale-translate-import Translation import screen.
@@ -1988,90 +2065,97 @@ function _locale_translate_seek() {
   $output = '';
 
   // We have at least one criterion to match
-  if ($query = _locale_translate_seek_query()) {
-    $join = "SELECT s.source, s.location, s.lid, s.textgroup, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid ";
+  if (!($query = _locale_translate_seek_query())) {
+    $query = array(
+      'translation' => 'all',
+      'group' => 'all',
+      'language' => 'all',
+      'string' => '',
+    );
+  }
+  
+  $join = "SELECT s.source, s.location, s.lid, s.textgroup, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid ";
+  $arguments = array();
+
+  $limit_language = FALSE;
+  // Compute LIKE section
+  switch ($query['translation']) {
+    case 'translated':
+      $where = "WHERE (t.translation LIKE ?)";
+      $orderby = "ORDER BY t.translation";
+      $arguments[] = '%'. $query['string'] .'%';
+      break;
+    case 'untranslated':
+      $where = "WHERE (s.source LIKE ? AND t.translation IS NULL)";
+      $orderby = "ORDER BY s.source";
+      $arguments[] = '%'. $query['string'] .'%';
+      break;
+    case 'all' :
+    default:
+      $where = "WHERE (s.source LIKE ? OR t.translation LIKE ?)";
+      $orderby = '';
+      $arguments[] = '%'. $query['string'] .'%';
+      $arguments[] = '%'. $query['string'] .'%';
+      break;
+  }
+  $grouplimit = '';
+  if (!empty($query['group']) && $query['group'] != 'all') {
+    $grouplimit = " AND s.textgroup = ?";
+    $arguments[] = $query['group'];
+  }
 
-    $arguments = array();
-    $limit_language = FALSE;
-    // Compute LIKE section
-    switch ($query['translation']) {
-      case 'translated':
-        $where = "WHERE (t.translation LIKE ?)";
-        $orderby = "ORDER BY t.translation";
-        $arguments[] = '%'. $query['string'] .'%';
-        break;
-      case 'untranslated':
-        $where = "WHERE (s.source LIKE ? AND t.translation IS NULL)";
-        $orderby = "ORDER BY s.source";
-        $arguments[] = '%'. $query['string'] .'%';
-        break;
-      case 'all' :
-      default:
-        $where = "WHERE (s.source LIKE ? OR t.translation LIKE ?)";
-        $orderby = '';
-        $arguments[] = '%'. $query['string'] .'%';
-        $arguments[] = '%'. $query['string'] .'%';
-        break;
-    }
-    $grouplimit = '';
-    if (!empty($query['group']) && $query['group'] != 'all') {
-      $grouplimit = " AND s.textgroup = ?";
-      $arguments[] = $query['group'];
-    }
+  switch ($query['language']) {
+    // Force search in source strings
+    case "en":
+      $sql = $join . " WHERE s.source LIKE ? $grouplimit ORDER BY s.source";
+      $arguments = array('%' . $query['string'] . '%'); // $where is not used, discard its arguments
+      if (!empty($grouplimit)) {
+        $arguments[] = $query['group'];
+      }
+      break;
+    // Search in all languages
+    case "all":
+      $sql = "$join $where $grouplimit $orderby";
+      break;
+    // Some different language
+    default:
+      $sql = "$join AND t.language = ? $where $grouplimit $orderby";
+      array_unshift($arguments, $query['language']);
+      // Don't show translation flags for other languages, we can't see them with this search.
+      $limit_language = $query['language'];
+  }
 
-    switch ($query['language']) {
-      // Force search in source strings
-      case "en":
-        $sql = $join . " WHERE s.source LIKE ? $grouplimit ORDER BY s.source";
-        $arguments = array('%' . $query['string'] . '%'); // $where is not used, discard its arguments
-        if (!empty($grouplimit)) {
-          $arguments[] = $query['group'];
-        }
-        break;
-      // Search in all languages
-      case "all":
-        $sql = "$join $where $grouplimit $orderby";
-        break;
-      // Some different language
-      default:
-        $sql = "$join AND t.language = ? $where $grouplimit $orderby";
-        array_unshift($arguments, $query['language']);
-        // Don't show translation flags for other languages, we can't see them with this search.
-        $limit_language = $query['language'];
-    }
-
-    $result = pager_query($sql, 50, 0, NULL, $arguments);
-
-    $groups = module_invoke_all('locale', 'groups');
-    $header = array(t('Text group'), t('String'), ($limit_language) ? t('Language') : t('Languages'), array('data' => t('Operations'), 'colspan' => '2'));
-    $arr = array();
-    while ($locale = db_fetch_object($result)) {
-      $arr[$locale->lid]['group'] = $groups[$locale->textgroup];
-      $arr[$locale->lid]['languages'][$locale->language] = $locale->translation;
-      $arr[$locale->lid]['location'] = $locale->location;
-      $arr[$locale->lid]['source'] = $locale->source;
-    }
-    $rows = array();
-    foreach ($arr as $lid => $value) {
-      $rows[] = array(
-        $value['group'],
-        array('data' => check_plain(truncate_utf8($value['source'], 150, FALSE, TRUE)) . '<br /><small>' . $value['location'] . '</small>'),
-        array('data' => _locale_translate_language_list($value['languages'], $limit_language), 'align' => 'center'),
-        array('data' => l(t('edit'), "admin/build/translate/edit/$lid"), 'class' => 'nowrap'),
-        array('data' => l(t('delete'), "admin/build/translate/delete/$lid"), 'class' => 'nowrap'),
-      );
-    }
+  $result = pager_query($sql, 50, 0, NULL, $arguments);
 
-    if (count($rows)) {
-      $output .= theme('table', $header, $rows);
-      if ($pager = theme('pager', NULL, 50)) {
-        $output .= $pager;
-      }
-    }
-    else {
-      $output .= t('No strings found for your search.');
+  $groups = module_invoke_all('locale', 'groups');
+  $header = array(t('Text group'), t('String'), ($limit_language) ? t('Language') : t('Languages'), array('data' => t('Operations'), 'colspan' => '2'));
+  $arr = array();
+  while ($locale = db_fetch_object($result)) {
+    $arr[$locale->lid]['group'] = $groups[$locale->textgroup];
+    $arr[$locale->lid]['languages'][$locale->language] = $locale->translation;
+    $arr[$locale->lid]['location'] = $locale->location;
+    $arr[$locale->lid]['source'] = $locale->source;
+  }
+  $rows = array();
+  foreach ($arr as $lid => $value) {
+    $rows[] = array(
+      $value['group'],
+      array('data' => check_plain(truncate_utf8($value['source'], 150, FALSE, TRUE)) . '<br /><small>' . $value['location'] . '</small>'),
+      array('data' => _locale_translate_language_list($value['languages'], $limit_language), 'align' => 'center'),
+      array('data' => l(t('edit'), "admin/build/translate/edit/$lid", array('query' => drupal_get_destination())), 'class' => 'nowrap'),
+      array('data' => l(t('delete'), "admin/build/translate/delete/$lid", array('query' => drupal_get_destination())), 'class' => 'nowrap'),
+    );
+  }
+
+  if (count($rows)) {
+    $output .= theme('table', $header, $rows);
+    if ($pager = theme('pager', NULL, 50)) {
+      $output .= $pager;
     }
   }
+  else {
+    $output .= t('No strings found for your search.');
+  }
 
   return $output;
 }
@@ -2085,8 +2169,8 @@ function _locale_translate_seek_query() 
     $query = array();
     $fields = array('string', 'language', 'translation', 'group');
     foreach ($fields as $field) {
-      if (isset($_REQUEST[$field])) {
-        $query[$field] = $_REQUEST[$field];
+      if (isset($_SESSION['locale_translation_filter'][$field])) {
+        $query[$field] = $_SESSION['locale_translation_filter'][$field];
       }
     }
   }
Index: modules/locale/locale.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.css,v
retrieving revision 1.1
diff -u -p -r1.1 locale.css
--- modules/locale/locale.css	14 Aug 2006 07:14:49 -0000	1.1
+++ modules/locale/locale.css	3 Feb 2009 22:07:08 -0000
@@ -4,3 +4,18 @@
   font-style: normal;
   text-decoration: line-through;
 }
+
+#edit-language-wrapper, #edit-translation-wrapper, #edit-group-wrapper {
+  float: left; /* LTR */
+  padding-right: .8em; /* LTR */
+  margin: 0.1em;
+  /**
+   * In Opera 9, DOM elements with the property of "overflow: auto"
+   * will partially hide its contents with unnecessary scrollbars when
+   * its immediate child is floated without an explicit width set.
+   */
+  width: 15em;
+}
+#locale-translation-filter-form .form-item select.form-select {
+  width: 100%;
+}
Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.236
diff -u -p -r1.236 locale.module
--- modules/locale/locale.module	22 Jan 2009 03:11:53 -0000	1.236
+++ modules/locale/locale.module	3 Feb 2009 22:07:09 -0000
@@ -124,8 +124,8 @@ function locale_menu() {
     'weight' => 0,
     'type' => MENU_DEFAULT_LOCAL_TASK,
   );
-  $items['admin/build/translate/search'] = array(
-    'title' => 'Search',
+  $items['admin/build/translate/translate'] = array(
+    'title' => 'Translate',
     'weight' => 10,
     'type' => MENU_LOCAL_TASK,
     'page callback' => 'locale_translate_seek_screen', // search results and form concatenated
Index: modules/locale/locale.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.test,v
retrieving revision 1.15
diff -u -p -r1.15 locale.test
--- modules/locale/locale.test	22 Jan 2009 03:29:01 -0000	1.15
+++ modules/locale/locale.test	3 Feb 2009 22:07:09 -0000
@@ -65,7 +65,7 @@ class LocaleTestCase extends DrupalWebTe
       'translation' => 'all',
       'group' => 'all',
     );
-    $this->drupalPost('admin/build/translate/search', $search, t('Search'));
+    $this->drupalPost('admin/build/translate/translate', $search, t('Filter'));
     // assertText seems to remove the input field where $name always could be
     // found, so this is not a false assert. See how assertNoText succeeds
     // later.
@@ -75,7 +75,9 @@ class LocaleTestCase extends DrupalWebTe
     // reasonable.
     $this->clickLink(t('edit'));
     // We save the lid from the path.
-    $lid = preg_replace('/\D/', '', substr($this->getUrl(), strlen($base_url)));
+    $matches = array();
+    preg_match('!admin/build/translate/edit/(\d)+!', $this->getUrl(), $matches);
+    $lid = $matches[1];
     // No t() here, it's surely not translated yet.
     $this->assertText($name, 'name found on edit screen');
     $edit = array (
@@ -84,7 +86,7 @@ class LocaleTestCase extends DrupalWebTe
     $this->drupalPost(NULL, $edit, t('Save translations'));
     $this->assertText(t('The string has been saved.'), 'The string has been saved.');
     $this->assertTrue($name != $translation && t($name, array(), $langcode) == $translation, 't() works');
-    $this->drupalPost('admin/build/translate/search', $search, t('Search'));
+    $this->drupalPost('admin/build/translate/translate', $search, t('Filter'));
     // The indicator should not be here.
     $this->assertNoRaw($language_indicator, 'String is translated');
     $this->drupalLogout();
@@ -105,9 +107,10 @@ class LocaleTestCase extends DrupalWebTe
 
     // Delete the name string.
     $this->drupalLogin($translate_user);
+    $source = db_fetch_object(db_query('SELECT * FROM {locales_source} WHERE lid = %d', $lid));
     $this->drupalPost('admin/build/translate/delete/' . $lid, array(), t('Delete'));
     $this->assertText(t('The string has been removed.'), 'The string has been removed message.');
-    $this->drupalPost('admin/build/translate/search', $search, t('Search'));
+    $this->drupalPost('admin/build/translate/translate', $search, t('Filter'));
     $this->assertNoText($name, 'Search now can not find the name');
   }
 
@@ -155,7 +158,7 @@ class LocaleTestCase extends DrupalWebTe
       'translation' => 'all',
       'group' => 'all',
     );
-    $this->drupalPost('admin/build/translate/search', $search, t('Search'));
+    $this->drupalPost('admin/build/translate/translate', $search, t('Filter'));
     // Find the edit path
     $content = $this->drupalGetContent();
     $this->assertTrue(preg_match('@(admin/build/translate/edit/[0-9]+)@', $content, $matches), t('Found the edit path'));
