Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.309
diff -u -p -r1.309 bootstrap.inc
--- includes/bootstrap.inc	9 Oct 2009 16:33:13 -0000	1.309
+++ includes/bootstrap.inc	16 Oct 2009 01:13:34 -0000
@@ -127,15 +127,10 @@ define('DRUPAL_BOOTSTRAP_PAGE_HEADER', 5
 define('DRUPAL_BOOTSTRAP_LANGUAGE', 6);
 
 /**
- * Eighth bootstrap phase: set $_GET['q'] to Drupal path of request.
- */
-define('DRUPAL_BOOTSTRAP_PATH', 7);
-
-/**
  * Final bootstrap phase: Drupal is fully loaded; validate and fix
  * input data.
  */
-define('DRUPAL_BOOTSTRAP_FULL', 8);
+define('DRUPAL_BOOTSTRAP_FULL', 7);
 
 /**
  * Role ID for anonymous users; should match what's in the "role" table.
@@ -1382,7 +1377,7 @@ function drupal_anonymous_user($session 
  *   function called from drupal_bootstrap (recursion).
  * @return
  *   The most recently completed phase.
- *   
+ *
  */
 function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
   $final_phase = &drupal_static(__FUNCTION__ . '_final_phase');
@@ -1399,7 +1394,6 @@ function drupal_bootstrap($phase = NULL,
     DRUPAL_BOOTSTRAP_SESSION,
     DRUPAL_BOOTSTRAP_PAGE_HEADER,
     DRUPAL_BOOTSTRAP_LANGUAGE,
-    DRUPAL_BOOTSTRAP_PATH,
     DRUPAL_BOOTSTRAP_FULL,
   ));
   $completed_phase = &drupal_static(__FUNCTION__ . '_completed_phase', -1);
@@ -1535,12 +1529,6 @@ function _drupal_bootstrap($phase) {
       drupal_language_initialize();
       break;
 
-    case DRUPAL_BOOTSTRAP_PATH:
-      require_once DRUPAL_ROOT . '/includes/path.inc';
-      // Initialize $_GET['q'] prior to loading modules and invoking hook_init().
-      drupal_path_initialize();
-      break;
-
     case DRUPAL_BOOTSTRAP_FULL:
       require_once DRUPAL_ROOT . '/includes/common.inc';
       _drupal_bootstrap_full();
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1021
diff -u -p -r1.1021 common.inc
--- includes/common.inc	15 Oct 2009 21:19:30 -0000	1.1021
+++ includes/common.inc	16 Oct 2009 01:13:34 -0000
@@ -2357,6 +2357,7 @@ function url($path = NULL, array $option
     'https' => FALSE,
     'prefix' => ''
   );
+
   if (!isset($options['external'])) {
     // Return an external link if $path contains an allowed absolute URL.
     // Only call the slow filter_xss_bad_protocol if $path contains a ':' before
@@ -2365,10 +2366,12 @@ function url($path = NULL, array $option
     $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path));
   }
 
-  // May need language dependent rewriting if language.inc is present.
-  if (function_exists('language_url_rewrite')) {
-    language_url_rewrite($path, $options);
-  }
+  // Preserve the original path before altering or aliasing.
+  $original_path = $path;
+
+  // Allow other modules to alter the outbound URL and options.
+  drupal_alter('url_outbound', $path, $options);
+
   if ($options['fragment']) {
     $options['fragment'] = '#' . $options['fragment'];
   }
@@ -2417,21 +2420,16 @@ function url($path = NULL, array $option
     }
   }
 
-  // Preserve the original path before aliasing.
-  $original_path = $path;
-
   // The special path '<front>' links to the default front page.
   if ($path == '<front>') {
     $path = '';
   }
   elseif (!empty($path) && !$options['alias']) {
     $language = isset($options['language']) && isset($options['language']->language) ? $options['language']->language : '';
-    $path = drupal_get_path_alias($path, $language);
-  }
-
-  if (function_exists('custom_url_rewrite_outbound')) {
-    // Modules may alter outbound links by reference.
-    custom_url_rewrite_outbound($path, $options, $original_path);
+    $alias = drupal_get_path_alias($original_path, $language);
+    if ($alias != $original_path) {
+      $path = $alias;
+    }
   }
 
   $base = $options['absolute'] ? $options['base_url'] . '/' : base_path();
@@ -2595,7 +2593,7 @@ function l($text, $path, array $options 
  *
  * In order for page callbacks to be reusable in different delivery formats,
  * they should not issue any "print" or "echo" statements, but instead just
- * return content. 
+ * return content.
  *
  * @param $page_callback_result
  *   The result of a page callback. Can be one of:
@@ -2608,7 +2606,7 @@ function l($text, $path, array $options 
  *   to be appropriate for the page request as determined by the calling
  *   function (e.g., menu_execute_active_handler()). If not given, it is
  *   determined from the menu router information of the current page. In either
- *   case, modules have a final chance to alter which function is called. 
+ *   case, modules have a final chance to alter which function is called.
  *
  * @see menu_execute_active_handler()
  * @see hook_menu()
@@ -2655,7 +2653,7 @@ function drupal_deliver_html_page($page_
   // Menu status constants are integers; page content is a string or array.
   if (is_int($page_callback_result)) {
     // @todo: Break these up into separate functions?
-    switch ($page_callback_result) {   
+    switch ($page_callback_result) {
       case MENU_NOT_FOUND:
         // Print a 404 page.
         drupal_add_http_header('404 Not Found');
@@ -2719,7 +2717,7 @@ function drupal_deliver_html_page($page_
         drupal_add_http_header('503 Service unavailable');
         drupal_set_title(t('Site under maintenance'));
         print theme('maintenance_page', array('content' => filter_xss_admin(variable_get('maintenance_mode_message',
-          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))))));    
+          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))))));
         break;
     }
   }
@@ -4154,6 +4152,7 @@ function _drupal_bootstrap_full() {
     return;
   }
   $called = 1;
+  require_once DRUPAL_ROOT . '/includes/path.inc';
   require_once DRUPAL_ROOT . '/includes/theme.inc';
   require_once DRUPAL_ROOT . '/includes/pager.inc';
   require_once DRUPAL_ROOT . '/includes/menu.inc';
@@ -4187,6 +4186,8 @@ function _drupal_bootstrap_full() {
     ini_set('log_errors', 1);
     ini_set('error_log', file_directory_path() . '/error.log');
   }
+  // Initialize $_GET['q'] prior to invoking hook_init().
+  drupal_path_initialize();
   // Set a custom theme for the current page, if there is one. We need to run
   // this before invoking hook_init(), since any modules which initialize the
   // theme system will prevent a custom theme from being correctly set later.
@@ -6018,4 +6019,3 @@ function drupal_get_updaters() {
   }
   return $updaters;
 }
-
Index: includes/language.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/language.inc,v
retrieving revision 1.20
diff -u -p -r1.20 language.inc
--- includes/language.inc	9 Oct 2009 16:33:13 -0000	1.20
+++ includes/language.inc	16 Oct 2009 01:13:35 -0000
@@ -325,47 +325,6 @@ function language_from_default() {
 }
 
 /**
- * Rewrite URLs allowing modules to hook in.
- *
- * @param $path
- *   The path to rewrite.
- * @param $options
- *   An associative array of additional options as in url().
- */
-function language_url_rewrite(&$path, &$options) {
-  // Only modify relative (insite) URLs.
-  if (!$options['external']) {
-    static $callbacks;
-
-    if (!isset($callbacks)) {
-      $callbacks = array();
-
-      foreach (language_types_configurable() as $type) {
-        // Get url rewriter callbacks only from enabled language providers.
-        $negotiation = variable_get("language_negotiation_$type", array());
-
-        foreach ($negotiation as $id => $provider) {
-          if (isset($provider['file'])) {
-            require_once DRUPAL_ROOT . '/' . $provider['file'];
-          }
-
-          // Avoid duplicate callback entries.
-          if (isset($provider['callbacks']['url_rewrite'])) {
-            $callbacks[$provider['callbacks']['url_rewrite']] = NULL;
-          }
-        }
-      }
-
-      $callbacks = array_keys($callbacks);
-    }
-
-    foreach ($callbacks as $callback) {
-      $callback($path, $options);
-    }
-  }
-}
-
-/**
  * Split the given path into prefix and actual path.
  *
  * Parse the given path and return the language object identified by the
Index: includes/path.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/path.inc,v
retrieving revision 1.45
diff -u -p -r1.45 path.inc
--- includes/path.inc	15 Oct 2009 17:53:34 -0000	1.45
+++ includes/path.inc	16 Oct 2009 01:13:35 -0000
@@ -7,7 +7,7 @@
  *
  * These functions are not loaded for cached pages, but modules that need
  * to use them in hook_init() or hook exit() can make them available, by
- * executing "drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH);".
+ * executing "drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);".
  */
 
 /**
@@ -205,13 +205,25 @@ function drupal_get_path_alias($path = N
  */
 function drupal_get_normal_path($path, $path_language = '') {
   $result = $path;
+
+  // Lookup the path alias first.
   if ($source = drupal_lookup_path('source', $path, $path_language)) {
     $result = $source;
   }
-  if (function_exists('custom_url_rewrite_inbound')) {
-    // Modules may alter the inbound request path by reference.
-    custom_url_rewrite_inbound($result, $path, $path_language);
+
+  // Allow other modules to alter the outbound URL and options.
+  // We can't use drupal_alter() here because we want to run the hooks in
+  // reverse order from hook_url_outbound_alter() and since we also can't
+  // run module_implements(). BLEH!
+  $result_copy = $result;
+  foreach (array_reverse(module_list(FALSE, TRUE)) as $module) {
+    drupal_load('module', $module);
+    $function = $module . '_url_inbound_alter';
+    if (function_exists($function)) {
+      $function($result, $result_copy, $path_language);
+    }
   }
+
   return $result;
 }
 
@@ -347,7 +359,7 @@ function drupal_match_path($path, $patte
  * This function is not available in hook_boot() so use $_GET['q'] instead.
  * However, be careful when doing that because in the case of Example #3
  * $_GET['q'] will contain "path/alias". If "node/306" is needed, calling
- * drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH) makes this function available.
+ * drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL) makes this function available.
  *
  * @return
  *   The current Drupal URL path.
Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.524
diff -u -p -r1.524 forum.module
--- modules/forum/forum.module	15 Oct 2009 12:44:36 -0000	1.524
+++ modules/forum/forum.module	16 Oct 2009 01:13:35 -0000
@@ -610,7 +610,7 @@ function forum_block_view_pre_render($el
  */
 function forum_form($node, $form_state) {
   $type = node_type_get_type($node);
-  
+
   if (!empty($node->nid)) {
     $forum_terms = $node->taxonomy_forums;
     // If editing, give option to leave shadows
@@ -626,10 +626,29 @@ function forum_form($node, $form_state) 
 }
 
 /**
- * Implement hook_term_path().
+ * Implement hook_url_outbound_alter().
  */
-function forum_term_path($term) {
-  return 'forum/' . $term->tid;
+function forum_url_outbound_alter(&$path, &$options) {
+  if (preg_match('!taxonomy/term/(\d+)!', $path, $matches)) {
+    $vocabulary = taxonomy_vocabulary_load($matches[1]);
+    if ($vocabulary && $vocabulary->module == 'forum') {
+      $path = 'forum/' . $matches[1];
+    }
+  }
+}
+
+/**
+ * Implement hook_url_inbound_alter().
+ */
+function forum_url_inbound_alter(&$path, $original_path, $language) {
+  if (preg_match('!forum/(\d+)!', $path, $matches)) {
+    // Because we are not fully bootstrapped, load taxonomy.module manually.
+    drupal_load('module', 'taxonomy');
+    $vocabulary = taxonomy_vocabulary_load($matches[1]);
+    if ($vocabulary && $vocabulary->module == 'forum') {
+      $path = 'taxonomy/term/' . $matches[1];
+    }
+  }
 }
 
 /**
Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.263
diff -u -p -r1.263 locale.module
--- modules/locale/locale.module	13 Oct 2009 21:34:14 -0000	1.263
+++ modules/locale/locale.module	16 Oct 2009 01:13:35 -0000
@@ -1015,3 +1015,40 @@ function locale_date_format_reset_form_s
   $form_state['redirect'] = 'admin/config/regional/date-time/locale';
 }
 
+/**
+ * Implement hook_url_outbound_alter().
+ *
+ * Rewrite outbound URLs with language based prefixes.
+ */
+function locale_url_outbound_alter(&$path, &$options) {
+  // Only modify relative (insite) URLs.
+  if (!$options['external']) {
+    static $callbacks;
+
+    if (!isset($callbacks)) {
+      $callbacks = array();
+
+      foreach (language_types_configurable() as $type) {
+        // Get url rewriter callbacks only from enabled language providers.
+        $negotiation = variable_get("language_negotiation_$type", array());
+
+        foreach ($negotiation as $id => $provider) {
+          if (isset($provider['file'])) {
+            require_once DRUPAL_ROOT . '/' . $provider['file'];
+          }
+
+          // Avoid duplicate callback entries.
+          if (isset($provider['callbacks']['url_rewrite'])) {
+            $callbacks[$provider['callbacks']['url_rewrite']] = NULL;
+          }
+        }
+      }
+
+      $callbacks = array_keys($callbacks);
+    }
+
+    foreach ($callbacks as $callback) {
+      $callback($path, $options);
+    }
+  }
+}
Index: modules/simpletest/tests/path.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/path.test,v
retrieving revision 1.1
diff -u -p -r1.1 path.test
--- modules/simpletest/tests/path.test	11 Sep 2009 02:19:02 -0000	1.1
+++ modules/simpletest/tests/path.test	16 Oct 2009 01:13:35 -0000
@@ -126,3 +126,84 @@ class DrupalMatchPathTestCase extends Dr
     );
   }
 }
+
+
+/**
+ * Tests hook_url_alter functions.
+ */
+class UrlAlterFunctionalTest extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('URL altering'),
+      'description' => t('Tests hook_url_inbound_alter() and hook_url_outbound_alter().'),
+      'group' => t('Path API'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('path', 'forum', 'url_alter_test');
+  }
+
+  /**
+   * Test that URL altering works and that it occurs in the correct order.
+   */
+  function testUrlAlter() {
+    $account = $this->drupalCreateUser(array('administer url aliases'));
+    $this->drupalLogin($account);
+
+    $uid = $account->uid;
+    $name = $account->name;
+
+    //path_save(array('source' => "user/$uid/test2", 'alias' => 'user/test2'));
+    //path_save(array('source' => "user/$uid/test3", 'alias' => "user/$uid/alias/test3"));
+    //path_save(array('source' => "user/$uid/test4", 'alias' => 'alias/test4'));
+
+    // Test single alter paths first.
+    $this->assertUrlAlter("user/$uid", "user/$name");
+
+    // Make sure a path with an alias always uses the alias.
+    path_save(array('source' => "user/$uid/test1", 'alias' => 'alias/test1'));
+    $this->assertUrlAlter("user/$uid/test1", 'alias/test1');
+
+    // Make sure aliases are saved with the normal path.
+    $edit = array('source' => "user/$name/test2", 'alias' => 'alias/test2');
+    $this->drupalPost('admin/config/search/path/add', $edit, t('Create new alias'));
+    $this->assertUrlAlter("user/$uid/test2", 'alias/test2');
+
+    // Test a non-existant user is not altered.
+    $this->assertUrlAlter('user/' . ($uid + 1), 'user/' . ($uid + 1));
+
+    // Test double alter paths next.
+
+    // Test that 'forum' is altered to 'community' correctly.
+    $this->assertUrlAlter('forum', 'community');
+
+    // Test that a non-existant forum URL is not altered.
+    $this->assertUrlAlter('taxonomy/term/3', 'taxonomy/term/3');
+  }
+
+  /**
+   * Assert that a path is altered to an expected value and back again.
+   *
+   * @param $original
+   *   A string with the original path that is run through url(). This should
+   *   also be the expected result after drupal_get_normal_path().
+   * @param $final
+   *   A string with the path that is run through drupal_get_normal_path().
+   *   This should also be the expected result after url().
+   * @return
+   *   TRUE if $original was correctly altered to $final and then back, FALSE
+   *   otherwise.
+   */
+  protected function assertUrlAlter($original, $final) {
+    // Test outbound altering.
+    $final_result = url($original);
+    $base_path = base_path() . (variable_get('clean_url', '0') ? '' : '?q=');
+    $final_result = substr($final_result, strlen($base_path));
+    $this->assertIdentical($final, $final_result, t('Altered outbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $final_result)));
+
+    // Test inbound altering.
+    $original_result = drupal_get_normal_path($final);
+    $this->assertIdentical($original, $original_result, t('Altered inbound URL %final, expected %original, and got %result.', array('%final' => $final, '%original' => $original, '%result' => $original_result)));
+  }
+}
Index: modules/simpletest/tests/url_alter_test.info
===================================================================
RCS file: modules/simpletest/tests/url_alter_test.info
diff -N modules/simpletest/tests/url_alter_test.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/url_alter_test.info	16 Oct 2009 01:13:35 -0000
@@ -0,0 +1,8 @@
+; $Id$
+name = Url_alter tests
+description = A support modules for url_alter hook testing.
+core = 7.x
+package = Testing
+version = VERSION
+files[] = url_alter_test.module
+hidden = TRUE
Index: modules/simpletest/tests/url_alter_test.module
===================================================================
RCS file: modules/simpletest/tests/url_alter_test.module
diff -N modules/simpletest/tests/url_alter_test.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/url_alter_test.module	16 Oct 2009 01:13:35 -0000
@@ -0,0 +1,45 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Module to help test hook_url_inbound_alter() and hook_url_outbound_alter().
+ */
+
+/**
+ * Implement hook_url_inbound_alter().
+ */
+function url_alter_test_url_inbound_alter(&$path, $original_path, $path_language) {
+  // Rewrite user/username to user/uid.
+  if (preg_match('!^user/([^/]+)(/.*)?!', $path, $matches)) {
+    // Because we are not fully bootstrapped, load taxonomy.module manually.
+    drupal_load('module', 'user');
+    if ($account = user_load_by_name($matches[1])) {
+      $matches += array(2 => '');
+      $path = 'user/' . $account->uid;
+    }
+  }
+
+  // Rewrite community/ to forum/.
+  if ($path == 'community' || strpos($path, 'community/') === 0) {
+    $path = substr_replace('community', 'forum', 0, 9);
+  }
+}
+
+/**
+ * Implement hook_url_outbound_alter().
+ */
+function url_alter_test_url_outbound_alter(&$path, &$options) {
+  // Rewrite user/uid to user/username.
+  if (preg_match('!^user/([0-9]+)(/.*)?!', $path, $matches)) {
+    if ($account = user_load($matches[1])) {
+      $matches += array(2 => '');
+      $path = 'user/' . $account->name . $matches[2];
+    }
+  }
+
+  // Rewrite forum/ to community/.
+  if ($path == 'forum' || strpos($path, 'forum/') === 0) {
+    $path = substr_replace('forum', 'community', 0, 5);
+  }
+}
Index: modules/statistics/statistics.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/statistics/statistics.module,v
retrieving revision 1.320
diff -u -p -r1.320 statistics.module
--- modules/statistics/statistics.module	5 Sep 2009 13:49:28 -0000	1.320
+++ modules/statistics/statistics.module	16 Oct 2009 01:13:35 -0000
@@ -45,7 +45,7 @@ function statistics_help($path, $arg) {
 function statistics_exit() {
   global $user;
 
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH);
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 
   if (variable_get('statistics_count_content_views', 0)) {
     // We are counting content views.
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.90
diff -u -p -r1.90 system.api.php
--- modules/system/system.api.php	15 Oct 2009 17:55:55 -0000	1.90
+++ modules/system/system.api.php	16 Oct 2009 01:13:36 -0000
@@ -2284,7 +2284,7 @@ function hook_drupal_goto_alter(&$path, 
  *   the Drupal installation process that occurs after the installation profile
  *   is selected.
  * @param $install_state
- *   An array of information about the current installation state. 
+ *   An array of information about the current installation state.
  */
 function hook_install_tasks_alter(&$tasks, $install_state) {
   // Replace the "Choose language" installation task provided by Drupal core
@@ -2459,7 +2459,7 @@ function hook_date_format_types() {
  * module can define additional types that can be used when displaying dates. A
  * date type is a key which can be passed to format_date() to return a date in
  * the configured displayed format. A date format is a string defining the date
- * and time elements to use. For example, a date type could be 
+ * and time elements to use. For example, a date type could be
  * 'mymodule_extra_long', while a date format is like 'Y-m-d'.
  *
  * New date types must first be declared using hook_date_format_types(). It is
@@ -2487,7 +2487,7 @@ function hook_date_format_types() {
  *     'short', 'mymodule_extra_long'. It must first be declared in
  *     hook_date_format_types() unless extending a type provided by another
  *     module.
- *   - 'format': a string defining the date and time elements to use. It 
+ *   - 'format': a string defining the date and time elements to use. It
  *     can contain any of the formatting options described at
  *     http://php.net/manual/en/function.date.php
  *   - 'locales': (optional) an array of 2 and 5 character language codes, for
@@ -2605,5 +2605,77 @@ function hook_page_delivery_callback_alt
 }
 
 /**
+ * Alters inbound URL requests.
+ *
+ * @param $path
+ *   The path being constructed, which, if a path alias, has been resolved to a
+ *   Drupal path by the database, and which also may have been altered by other
+ *   modules before this one.
+ * @param $original_path
+ *   The original path, before being checked for path aliases or altered by the
+ *   modules.
+ * @param $path_language
+ *   The language of the path.
+ *
+ * @see drupal_get_normal_path()
+ */
+function hook_url_inbound_alter(&$path, $original_path, $path_language) {
+  // Change all node/[title]/edit paths to node/[nid]/edit.
+  if (preg_match('|^node(/.*)/edit|', $path, $matches)) {
+    $nodes = node_load_multiple(array(), array('title' => $matches[1]));
+    if (count($nodes) === 1) {
+      $node = array_shift($nodes);
+      $path = "node/$node->nid/edit";
+    }
+  }
+
+  // Create the path user/me/edit, which allows a user to edit their account.
+  if (preg_match('|^user/me/edit(/.*)?|', $path, $matches)) {
+    global $user;
+    $path = 'user/' . $user->uid . '/edit' . $matches[1];
+  }
+}
+
+/**
+ * Alters outbound URLs.
+ *
+ * @param $path
+ *   The outbound path to alter, not adjusted for path aliases yet. It won't be
+ *   adjusted for path aliases until all modules are finished altering it, thus
+ *   being consistent with hook_url_alter_inbound(), which adjusts for all path
+ *   aliases before allowing modules to alter it. This may have been altered by
+ *   other modules before this one.
+ * @param $options
+ *   A set of URL options for the URL so elements such as a fragment or a query
+ *   string can be added to the URL.
+ *
+ * @see url()
+ */
+function hook_url_outbound_alter(&$path, &$options) {
+  // Use an external RSS feed rather than the Drupal one.
+  if ($path == 'rss.xml') {
+    $path = 'http://example.com/rss.xml';
+    $options['external'] = TRUE;
+  }
+
+  // Instead of pointing to user/[uid]/edit, point to user/me/edit.
+  if (preg_match('|^user/([0-9]*)/edit(/.*)?|', $path, $matches)) {
+    global $user;
+    if ($user->uid == $matches[1]) {
+      $path = 'user/me/edit' . $matches[2];
+    }
+  }
+
+  // Change node/[nid]/edit paths to node/[title]/edit.
+  if (preg_match('|^node([0-9]*)/edit|', $path, $matches)) {
+    $node = node_load($matches[1]);
+    $nodes = node_load_multiple(array(), array('title' => $node->title));
+    if (count($nodes) === 1) {
+      $path = "node/$node->title/edit";
+    }
+  }
+}
+
+/**
  * @} End of "addtogroup hooks".
  */
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.522
diff -u -p -r1.522 taxonomy.module
--- modules/taxonomy/taxonomy.module	15 Oct 2009 14:34:07 -0000	1.522
+++ modules/taxonomy/taxonomy.module	16 Oct 2009 01:13:36 -0000
@@ -158,23 +158,6 @@ function taxonomy_theme() {
 }
 
 /**
- * For vocabularies not maintained by taxonomy.module, give the maintaining
- * module a chance to provide a path for terms in that vocabulary.
- *
- * @param $term
- *   A term object.
- * @return
- *   An internal Drupal path.
- */
-function taxonomy_term_path($term) {
-  $vocabulary = taxonomy_vocabulary_load($term->vid);
-  if ($vocabulary->module != 'taxonomy' && $path = module_invoke($vocabulary->module, 'term_path', $term)) {
-    return $path;
-  }
-  return 'taxonomy/term/' . $term->tid;
-}
-
-/**
  * Implement hook_menu().
  */
 function taxonomy_menu() {
@@ -1093,7 +1076,7 @@ function taxonomy_field_formatter_info()
  */
 function theme_field_formatter_taxonomy_term_link($variables) {
   $term = $variables['element']['#item']['taxonomy_term'];
-  return l($term->name, taxonomy_term_path($term));
+  return l($term->name, 'taxonomy/term/' . $term->tid, array('term' => $term));
 }
 
 /**
@@ -1494,4 +1477,3 @@ function taxonomy_taxonomy_term_delete($
 /**
  * @} End of "defgroup taxonomy indexing"
  */
-
Index: modules/taxonomy/taxonomy.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.pages.inc,v
retrieving revision 1.39
diff -u -p -r1.39 taxonomy.pages.inc
--- modules/taxonomy/taxonomy.pages.inc	15 Oct 2009 12:13:45 -0000	1.39
+++ modules/taxonomy/taxonomy.pages.inc	16 Oct 2009 01:13:36 -0000
@@ -22,7 +22,7 @@ function taxonomy_term_page($term) {
   $breadcrumb = array();
   while ($parents = taxonomy_get_parents($current->tid)) {
     $current = array_shift($parents);
-    $breadcrumb[] = l($current->name, taxonomy_term_path($current));
+    $breadcrumb[] = l($current->name, 'taxonomy/term/' . $current->tid);
   }
   $breadcrumb[] = l(t('Home'), NULL);
   $breadcrumb = array_reverse($breadcrumb);
Index: modules/taxonomy/taxonomy.tokens.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.tokens.inc,v
retrieving revision 1.2
diff -u -p -r1.2 taxonomy.tokens.inc
--- modules/taxonomy/taxonomy.tokens.inc	18 Sep 2009 00:04:23 -0000	1.2
+++ modules/taxonomy/taxonomy.tokens.inc	16 Oct 2009 01:13:36 -0000
@@ -119,7 +119,7 @@ function taxonomy_tokens($type, $tokens,
           break;
 
         case 'url':
-          $replacements[$original] = url(taxonomy_term_path($term), array('absolute' => TRUE));
+          $replacements[$original] = url('taxonomy/term/' . $term, array('absolute' => TRUE));
           break;
 
         case 'node-count':
