Index: /trunk/admin/include/functions.php
===================================================================
--- /trunk/admin/include/functions.php	(revision 12031)
+++ /trunk/admin/include/functions.php	(revision 12032)
@@ -1395,4 +1395,34 @@
 }
 
+/**
+ *
+ */
+function delete_tags($tag_ids)
+{
+  if (is_numeric($tag_ids))
+  {
+    $tag_ids = array($tag_ids);
+  }
+
+  if (!is_array($tag_ids))
+  {
+    return false;
+  }
+  
+  $query = '
+DELETE
+  FROM '.IMAGE_TAG_TABLE.'
+  WHERE tag_id IN ('.implode(',', $tag_ids).')
+;';
+  pwg_query($query);
+  
+  $query = '
+DELETE
+  FROM '.TAGS_TABLE.'
+  WHERE id IN ('.implode(',', $tag_ids).')
+;';
+  pwg_query($query);
+}
+
 function tag_id_from_tag_name($tag_name)
 {
Index: /trunk/admin/tags.php
===================================================================
--- /trunk/admin/tags.php	(revision 12031)
+++ /trunk/admin/tags.php	(revision 12032)
@@ -102,4 +102,106 @@
 
 // +-----------------------------------------------------------------------+
+// |                               merge tags                              |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['confirm_merge']))
+{
+  if (!isset($_POST['destination_tag']))
+  {
+    array_push(
+      $page['errors'],
+      l10n('No destination tag selected')
+      );
+  }
+  else
+  {
+    $destination_tag_id = $_POST['destination_tag'];
+    $tag_ids = explode(',', $_POST['merge_list']);
+    
+    if (is_array($tag_ids) and count($tag_ids) > 1)
+    {
+      $name_of_tag = array();
+      $query = '
+SELECT
+    id,
+    name
+  FROM '.TAGS_TABLE.'
+  WHERE id IN ('.implode(',', $tag_ids).')
+;';
+      $result = pwg_query($query);
+      while ($row = pwg_db_fetch_assoc($result))
+      {
+        $name_of_tag[ $row['id'] ] = trigger_event('render_tag_name', $row['name']);
+      }
+      
+      $tag_ids_to_delete = array_diff(
+        $tag_ids,
+        array($destination_tag_id)
+        );
+
+      $query = '
+SELECT
+    DISTINCT(image_id)
+  FROM '.IMAGE_TAG_TABLE.'
+  WHERE tag_id IN ('.implode(',', $tag_ids_to_delete).')
+;';
+      $image_ids = array_from_query($query, 'image_id');
+
+      delete_tags($tag_ids_to_delete);
+
+      $query = '
+SELECT
+    image_id
+  FROM '.IMAGE_TAG_TABLE.'
+  WHERE tag_id = '.$destination_tag_id.'
+;';
+      $destination_tag_image_ids = array_from_query($query, 'image_id');
+
+      $image_ids_to_link = array_diff(
+        $image_ids,
+        $destination_tag_image_ids
+        );
+
+      $inserts = array();
+      foreach ($image_ids_to_link as $image_id)
+      {
+        array_push(
+          $inserts,
+          array(
+            'tag_id' => $destination_tag_id,
+            'image_id' => $image_id
+            )
+          );
+      }
+
+      if (count($inserts) > 0)
+      {
+        mass_inserts(
+          IMAGE_TAG_TABLE,
+          array_keys($inserts[0]),
+          $inserts
+          );
+      }
+
+      $tags_deleted = array();
+      foreach ($tag_ids_to_delete as $tag_id)
+      {
+        $tags_deleted[] = $name_of_tag[$tag_id];
+      }
+      
+      array_push(
+        $page['infos'],
+        sprintf(
+          l10n('Tags <em>%s</em> merged into tag <em>%s</em>'),
+          implode(', ', $tags_deleted),
+          $name_of_tag[$destination_tag_id]
+          )
+        );
+    }
+  }
+}
+
+
+// +-----------------------------------------------------------------------+
 // |                               delete tags                             |
 // +-----------------------------------------------------------------------+
@@ -113,18 +215,6 @@
 ;';
   $tag_names = array_from_query($query, 'name');
-  
-  $query = '
-DELETE
-  FROM '.IMAGE_TAG_TABLE.'
-  WHERE tag_id IN ('.implode(',', $_POST['tags']).')
-;';
-  pwg_query($query);
-  
-  $query = '
-DELETE
-  FROM '.TAGS_TABLE.'
-  WHERE id IN ('.implode(',', $_POST['tags']).')
-;';
-  pwg_query($query);
+
+  delete_tags($_POST['tags']);
   
   array_push(
@@ -251,9 +341,15 @@
   );
 
-if (isset($_POST['edit']) and isset($_POST['tags']))
-{
+if ((isset($_POST['edit']) or isset($_POST['merge'])) and isset($_POST['tags']))
+{
+  $list_name = 'EDIT_TAGS_LIST';
+  if (isset($_POST['merge']))
+  {
+    $list_name = 'MERGE_TAGS_LIST';
+  }
+  
   $template->assign(
     array(
-      'EDIT_TAGS_LIST' => implode(',', $_POST['tags']),
+      $list_name => implode(',', $_POST['tags']),
       )
     );
Index: /trunk/admin/themes/default/template/tags.tpl
===================================================================
--- /trunk/admin/themes/default/template/tags.tpl	(revision 12031)
+++ /trunk/admin/themes/default/template/tags.tpl	(revision 12032)
@@ -1,3 +1,26 @@
 {include file='include/tag_selection.inc.tpl'}
+
+{footer_script}{literal}
+jQuery(document).ready(function(){
+  function displayDeletionWarnings() {
+    jQuery(".warningDeletion").show();
+    jQuery("input[name=destination_tag]:checked").parent("label").children(".warningDeletion").hide();
+  }
+
+  displayDeletionWarnings();
+
+  jQuery("#mergeTags label").click(function() {
+    displayDeletionWarnings();
+  });
+
+  jQuery("input[name=merge]").click(function() {
+    if (jQuery("ul.tagSelection input[type=checkbox]:checked").length < 2) {
+      alert("{/literal}{'Select at least two tags for merging'|@translate}{literal}");
+      return false;
+    }
+  });
+});
+{/literal}{/footer_script}
+
 
 <div class="titrePage">
@@ -31,4 +54,17 @@
   {/if}
 
+  {if isset($MERGE_TAGS_LIST)}
+  <input type="hidden" name="merge_list" value="{$MERGE_TAGS_LIST}">
+
+  <fieldset id="mergeTags">
+    <legend>{'Merge tags'|@translate}</legend>
+    {'Select the destination tag'|@translate}<br><br>
+    {foreach from=$tags item=tag name=tagloop}
+    <label><input type="radio" name="destination_tag" value="{$tag.ID}"{if $smarty.foreach.tagloop.index == 0} checked="checked"{/if}> {$tag.NAME}<span class="warningDeletion"> {'(this tag will be deleted)'|@translate}</span></label><br>
+    {/foreach}
+    <br><input type="submit" name="confirm_merge" value="{'Confirm merge'|@translate}">
+  </fieldset>
+  {/if}
+
   <fieldset>
     <legend>{'Add a tag'|@translate}</legend>
@@ -50,4 +86,5 @@
       <input type="hidden" name="pwg_token" value="{$PWG_TOKEN}">
       <input class="submit" type="submit" name="edit" value="{'Edit selected tags'|@translate}">
+      <input class="submit" type="submit" name="merge" value="{'Merge selected tags'|@translate}">
       <input class="submit" type="submit" name="delete" value="{'Delete selected tags'|@translate}" onclick="return confirm('{'Are you sure?'|@translate}');">
     </p>
Index: /trunk/admin/themes/default/theme.css
===================================================================
--- /trunk/admin/themes/default/theme.css	(revision 12031)
+++ /trunk/admin/themes/default/theme.css	(revision 12032)
@@ -1079,2 +1079,4 @@
 .ui-progressbar-value { background-image: url(images/pbar-ani.gif); height:10px;margin:-1px;border:1px solid #E78F08;}
 
+/* Tag Manager */
+.warningDeletion {display:none;font-style:italic;}
Index: /trunk/language/en_UK/admin.lang.php
===================================================================
--- /trunk/language/en_UK/admin.lang.php	(revision 12031)
+++ /trunk/language/en_UK/admin.lang.php	(revision 12032)
@@ -850,3 +850,11 @@
 $lang['show details'] = 'show details';
 $lang['hide details'] = 'hide details';
+$lang['Merge tags'] = 'Merge tags';
+$lang['Select the destination tag'] = 'Select the destination tag';
+$lang['(this tag will be deleted)'] = '(this tag will be deleted)';
+$lang['Confirm merge'] = 'Confirm merge';
+$lang['Merge selected tags'] = 'Merge selected tags';
+$lang['No destination tag selected'] = 'No destination tag selected';
+$lang['Tags <em>%s</em> merged into tag <em>%s</em>'] = 'Tags <em>%s</em> merged into tag <em>%s</em>';
+$lang['Select at least two tags for merging'] = 'Select at least two tags for merging';
 ?>
Index: /trunk/language/fr_FR/admin.lang.php
===================================================================
--- /trunk/language/fr_FR/admin.lang.php	(revision 12031)
+++ /trunk/language/fr_FR/admin.lang.php	(revision 12032)
@@ -859,3 +859,11 @@
 $lang['show details'] = 'montrer les détails';
 $lang['hide details'] = 'cacher les détails';
+$lang['Merge tags'] = 'Fusionner les tags';
+$lang['Select the destination tag'] = 'Sélectionnez le tag de destination';
+$lang['(this tag will be deleted)'] = '(ce tag sera supprimé)';
+$lang['Confirm merge'] = 'Confirmez la fusion';
+$lang['Merge selected tags'] = 'Fusionner les tags sélectionnés';
+$lang['No destination tag selected'] = 'Vous n\'avez pas sélectionné de tag de destination';
+$lang['Tags <em>%s</em> merged into tag <em>%s</em>'] = 'Les tags <em>%s</em> ont été fusionnés dans le tag <em>%s</em>';
+$lang['Select at least two tags for merging'] = 'Sélectionnez au moins deux tags pour la fusion';
 ?>
