Index: modules/taxonomy/taxonomy.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.admin.inc,v
retrieving revision 1.20
diff -u -r1.20 taxonomy.admin.inc
--- taxonomy.admin.inc	22 Dec 2007 23:24:25 -0000	1.20
+++ taxonomy.admin.inc	7 Jan 2008 01:23:56 -0000
@@ -111,6 +111,7 @@
     'tags' => 0,
     'multiple' => 0,
     'required' => 0,
+    'synonym_collapsing' => 0,
     'weight' => 0,
   );
   $form['identification'] = array(
@@ -167,6 +168,11 @@
     '#default_value' => $edit['required'],
     '#description' => t('At least one term in this vocabulary must be selected when submitting a post.'),
   );
+  $form['settings']['synonym_collapsing'] = array('#type' => 'checkbox',
+    '#title' => t('Synonym collapsing'),
+    '#default_value' => $edit['synonym_collapsing'],
+    '#description' => t('Enable collapsing of synonyms for this vocabulary.'),
+  );
   $form['settings']['weight'] = array('#type' => 'weight',
     '#title' => t('Weight'),
     '#default_value' => $edit['weight'],
Index: modules/taxonomy/taxonomy.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.install,v
retrieving revision 1.6
diff -u -r1.6 taxonomy.install
--- taxonomy.install	18 Dec 2007 12:59:22 -0000	1.6
+++ taxonomy.install	7 Jan 2008 01:09:38 -0000
@@ -238,6 +238,14 @@
         'size' => 'tiny',
         'description' => t('Whether or not free tagging is enabled for the vocabulary. (0 = disabled, 1 = enabled)'),
       ),
+      'synonym_collapsing' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => t('Whether or not synonym collapsing is enabled for terms in this vocabulary. (0 = disabled, 1 = enabled)'),
+      ),
       'module' => array(
         'type' => 'varchar',
         'length' => 255,
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.412
diff -u -r1.412 taxonomy.module
--- taxonomy.module	31 Dec 2007 16:58:34 -0000	1.412
+++ taxonomy.module	13 Jan 2008 22:40:53 -0000
@@ -576,7 +576,11 @@
           if ($key == 'tags') {
             // Free tagging; the values will be saved for later as strings
             // instead of objects to fill the form again.
-            $taxonomy['tags'] = $term;
+            foreach ($term as $vid => $single_term) {
+              $tags = drupal_explode_tags($term[$vid]);
+              $tags = taxonomy_collapse_synonyms($tags, $vid, TRUE);
+              $taxonomy['tags'][$vid] = drupal_implode_tags($tags);
+            }
           }
           else {
             $taxonomy[$tid] = taxonomy_get_term($tid);
@@ -655,6 +659,8 @@
     foreach ($typed_input as $vid => $vid_value) {
       $typed_terms = drupal_explode_tags($vid_value);
 
+      $typed_terms = taxonomy_collapse_synonyms($typed_terms, $vid, TRUE);
+
       $inserted = array();
       foreach ($typed_terms as $typed_term) {
         // See if the term exists in the chosen vocabulary
@@ -880,6 +886,52 @@
 }
 
 /**
+ * Collapses the synonyms to their base terms.
+ */
+function taxonomy_collapse_synonyms($terms, $vid, $message = FALSE) {
+  $result = db_query('SELECT synonym_collapsing FROM {vocabulary} WHERE vid = %d', $vid);
+  $vocab = db_fetch_array($result);
+  $synonym_collapsing = $vocab['synonym_collapsing'];
+
+  $synonyms = array();
+  $added_terms = array();
+  if ($synonym_collapsing) {
+    foreach ($terms as $key => &$term) {
+      // Fetch any applicable synonym roots.
+      $base = taxonomy_get_synonym_root($term);
+      if (is_object($base)) {
+        if (!in_array($base->name, $added_terms)) {
+          // A base term was found, so set the typed term to the base term.
+          if ($message) {
+            drupal_set_message(t('The term %term has been reverted to its synonym, %synonym.', array('%term' => $term, '%synonym' => $base->name)), 'status', FALSE);
+          }
+          $term = $base->name;
+          $added_terms[strtolower($term)] = strtolower($term);
+        }
+        else {
+          if ($message) {
+            drupal_set_message(t('The tag %term\'s synonym, %synonym, was already added, so the %term tag has been removed.', array('%term' => $term, '%synonym' => $base->name)), 'status', FALSE);
+          }
+          unset($terms[$key]);
+        }
+      }
+      else {
+        if (!in_array($term, $added_terms)) {
+          $added_terms[strtolower($term)] = strtolower($term);
+        }
+        else {
+          unset($terms[$key]);
+          if ($message) {
+            drupal_set_message(t('The tag %term was already added, so it has been removed.', array('%term' => $term)), 'status', FALSE);
+          }
+        }
+      }
+    }
+  }
+  return $terms;
+}
+
+/**
  * Count the number of published nodes classified by a term.
  *
  * @param $tid
Index: modules/taxonomy/taxonomy.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.pages.inc,v
retrieving revision 1.6
diff -u -r1.6 taxonomy.pages.inc
--- taxonomy.pages.inc	6 Dec 2007 09:58:34 -0000	1.6
+++ taxonomy.pages.inc	13 Jan 2008 19:20:10 -0000
@@ -108,21 +108,38 @@
   // The user enters a comma-separated list of tags. We only autocomplete the last tag.
   $array = drupal_explode_tags($string);
 
+  $result = db_query('SELECT synonym_collapsing FROM {vocabulary} WHERE vid = %d', $vid);
+  $vocab = db_fetch_array($result);
+  $synonym_collapsing = $vocab['synonym_collapsing'];
+
   // Fetch last tag
   $last_string = trim(array_pop($array));
   $matches = array();
   if ($last_string != '') {
     $result = db_query_range(db_rewrite_sql("SELECT t.tid, t.name FROM {term_data} t WHERE t.vid = %d AND LOWER(t.name) LIKE LOWER('%%%s%%')", 't', 'tid'), $vid, $last_string, 0, 10);
-
     $prefix = count($array) ? implode(', ', $array) .', ' : '';
+    $tags = array();
+    
+    if ($synonym_collapsing) {
+      $base = db_fetch_object(db_query(db_rewrite_sql("SELECT * FROM {term_synonym} s, {term_data} t WHERE t.tid = s.tid AND LOWER(s.name) LIKE LOWER('%%%s%%')"), $last_string));    
+      if (is_object($base)) {
+        //drupal_set_message($last_string);
+        $tags[$base->tid] = $base;
+      }
+    }
 
     while ($tag = db_fetch_object($result)) {
+      $tags[] = $tag;
+    }
+    foreach ($tags as $tag) {
       $n = $tag->name;
       // Commas and quotes in terms are special cases, so encode 'em.
       if (strpos($tag->name, ',') !== FALSE || strpos($tag->name, '"') !== FALSE) {
         $n = '"'. str_replace('"', '""', $tag->name) .'"';
       }
-      $matches[$prefix . $n] = check_plain($tag->name);
+      else {
+        $matches[$prefix . $n] = check_plain($tag->name);
+      }
     }
   }