Index: includes/path.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/path.inc,v
retrieving revision 1.71
diff -u -p -r1.71 path.inc
--- includes/path.inc	9 Aug 2010 00:13:06 -0000	1.71
+++ includes/path.inc	17 Nov 2010 10:50:39 -0000
@@ -96,11 +96,12 @@ function drupal_lookup_path($action, $pa
           // Now fetch the aliases corresponding to these system paths.
           // We order by ASC and overwrite array keys to ensure the correct
           // alias is used when there are multiple aliases per path.
-          $cache['map'][$path_language] = db_query("SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language ASC, pid ASC", array(
+          $result = db_query("SELECT source, alias, language FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language ASC, pid ASC", array(
             ':system' => $cache['system_paths'],
             ':language' => $path_language,
             ':language_none' => LANGUAGE_NONE,
-          ))->fetchAllKeyed();
+          ));
+          $cache['map'][$path_language] = drupal_process_path_query($result);
           // Keep a record of paths with no alias to avoid querying twice.
           $cache['no_aliases'][$path_language] = array_flip(array_diff_key($cache['system_paths'], array_keys($cache['map'][$path_language])));
         }
@@ -118,11 +119,12 @@ function drupal_lookup_path($action, $pa
       // For system paths which were not cached, query aliases individually.
       elseif (!isset($cache['no_aliases'][$path_language][$path])) {
         // Get the most fitting result falling back with alias without language
-        $alias = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", array(
+        $result = db_query("SELECT source, alias, language FROM {url_alias} WHERE source = :source AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", array(
           ':source' => $path,
           ':language' => $path_language,
           ':language_none' => LANGUAGE_NONE,
-        ))->fetchField();
+        ));
+        $alias = array_shift(drupal_process_path_query($result));
         $cache['map'][$path_language][$path] = $alias;
         return $alias;
       }
@@ -134,11 +136,13 @@ function drupal_lookup_path($action, $pa
       $source = FALSE;
       if (!isset($cache['map'][$path_language]) || !($source = array_search($path, $cache['map'][$path_language]))) {
         // Get the most fitting result falling back with alias without language
-        if ($source = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", array(
-                     ':alias' => $path,
-                     ':language' => $path_language,
-                     ':language_none' => LANGUAGE_NONE))
-            ->fetchField()) {
+        $result = db_query("SELECT source, alias, language FROM {url_alias} WHERE alias = :alias AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", array(
+          ':alias' => $path,
+          ':language' => $path_language,
+          ':language_none' => LANGUAGE_NONE));
+        $sources = drupal_process_path_query($result);
+        if (!empty($sources)) {
+          $source = key($sources);
           $cache['map'][$path_language][$source] = $path;
         }
         else {
@@ -156,6 +160,43 @@ function drupal_lookup_path($action, $pa
 }
 
 /**
+ * Process a path query result and return a source-alias map.
+ *
+ * Path queries must take into account language priorities when the same alias
+ * is available for different languages: sorting on the language column works
+ * only for "regular" languages, LANGUAGE_NONE must always have the lowest
+ * priority.
+ *
+ * @param DatabaseStatementInterface $result
+ *   A prepared statement object, already executed. A result row must have the
+ *   source, alias and language fields.
+ *
+ * @return
+ *   An indexed array keyed by source path and having path aliases as values.
+ */
+function drupal_process_path_query($result) {
+  $no_language = FALSE;
+  $map = array();
+
+  foreach ($result as $row) {
+    // Keep the query sorting for regular languages.
+    if ($row->language != LANGUAGE_NONE) {
+      $map[$row->source] = $row->alias;
+    }
+    else {
+      $no_language = $row;
+    }
+  }
+
+  // An alias with no language is inserted as the last one.
+  if ($no_language) {
+    $map[$no_language->source] = $no_language->alias;
+  }
+
+  return $map;
+}
+
+/**
  * Cache system paths for a page.
  *
  * Cache an array of the system paths available on each page. We assume
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.524
diff -u -p -r1.524 system.install
--- modules/system/system.install	13 Nov 2010 17:40:09 -0000	1.524
+++ modules/system/system.install	17 Nov 2010 10:33:19 -0000
@@ -1617,7 +1617,7 @@ function system_schema() {
         'default' => '',
       ),
       'language' => array(
-        'description' => 'The language this alias is for; if blank, the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.',
+        'description' => "The language this alias is for; if 'und', the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.",
         'type' => 'varchar',
         'length' => 12,
         'not null' => TRUE,
