Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.299
diff -u -p -r1.299 locale.module
--- modules/locale/locale.module	24 Sep 2010 00:37:43 -0000	1.299
+++ modules/locale/locale.module	1 Oct 2010 13:51:22 -0000
@@ -964,7 +964,11 @@ function locale_block_view($type) {
 function locale_url_outbound_alter(&$path, &$options, $original_path) {
   // Only modify internal URLs.
   if (!$options['external'] && drupal_multilingual()) {
-    static $callbacks;
+    static $drupal_static_fast;
+    if (!isset($drupal_static_fast)) {
+      $drupal_static_fast['callbacks'] = &drupal_static(__FUNCTION__);
+    }
+    $languages = &$drupal_static_fast['callbacks'];
 
     if (!isset($callbacks)) {
       $callbacks = array();
Index: modules/locale/locale.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.test,v
retrieving revision 1.79
diff -u -p -r1.79 locale.test
--- modules/locale/locale.test	1 Sep 2010 20:08:17 -0000	1.79
+++ modules/locale/locale.test	1 Oct 2010 13:51:53 -0000
@@ -1811,6 +1811,46 @@ class LocaleUILanguageNegotiationTest ex
     $this->drupalGet($test['path'], array(), $test['http_header']);
     $this->assertText($test['expect'], $test['message']);
   }
+
+  /**
+   * Test that URL rewriting works as expected with non-enabled languages.
+   */
+  function testUrlRewritingEdgeCases() {
+    // Check that disabled or non-installed languages are not considered for URL
+    // rewriting. To test this we need to enable URL language negotiation and
+    // have at least two languages enabled and one disabled.
+    require_once DRUPAL_ROOT . '/includes/language.inc';
+    require_once DRUPAL_ROOT . '/includes/locale.inc';
+    locale_add_language('fr');
+    locale_add_language('it', 'Italian', 'Italiano', LANGUAGE_LTR, '', 'it', 0);
+    language_negotiation_set(LANGUAGE_TYPE_INTERFACE, array(LOCALE_LANGUAGE_NEGOTIATION_URL => 0));
+    drupal_language_initialize();
+    drupal_static_reset('locale_url_outbound_alter');
+
+    // Check URL rewriting with a disabled language.
+    drupal_static_reset('language_list');
+    $languages = language_list();
+    $this->checkUrl($languages['it'], t('Path language is ignored if language is disabled.'), t('URL language negotiation does not work with disabled languages'));
+
+    // Check URL rewriting with a non-installed language.
+    $non_existing = language_default();
+    $non_existing->language = $this->randomName();
+    $non_existing->prefix = $this->randomName();
+    $this->checkUrl($non_existing, t('Path language is ignored if language is not installed.'), t('URL language negotiation does not work with non-installed languages'));
+  }
+
+  private function checkUrl($language, $message1, $message2) {
+    $options = array('language' => $language);
+    $rewritten_path = trim(str_replace('?q=', '', url('node', $options)), '/');
+    $segments = explode('/', $rewritten_path, 2);
+    $prefix = $segments[0];
+    $path = isset($segments[1]) ? $segments[1] : $prefix;
+    $prefixed = !$this->assertNotEqual($language->prefix, $prefix, $message1);
+    // If the rewritten URL has a language prefix we get the unprefixed system
+    // path to avoid having it prefixed two times.
+    $this->drupalGet($prefixed ? $path : "$prefix/$path", $options);
+    $this->assertResponse(404, $message2);
+  }
 }
 
 /**
