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 15:49:10 -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 15:53:55 -0000
@@ -1814,6 +1814,78 @@ class LocaleUILanguageNegotiationTest ex
 }
 
 /**
+ * Test that URL rewriting works as expected.
+ */
+class LocaleUrlRewritingTest extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'URL rewriting',
+      'description' => 'Test that URL rewriting works as expected.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+
+    // Create and login user.
+    $this->web_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+    $this->drupalLogin($this->web_user);
+
+    // Install French language.
+    $edit = array();
+    $edit['langcode'] = 'fr';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Install Italian language.
+    $edit = array();
+    $edit['langcode'] = 'it';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Disable Italian language.
+    $edit = array('enabled[it]' => FALSE);
+    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
+
+    // Enable URL language detection and selection.
+    $edit = array('language[enabled][locale-url]' => 1);
+    $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
+
+    // Reset static caching.
+    drupal_static_reset('language_list');
+    drupal_static_reset('locale_url_outbound_alter');
+    drupal_static_reset('locale_language_url_rewrite_url');
+  }
+
+  /**
+   * Check that disabled or non-installed languages are not considered.
+   */
+  function testUrlRewritingEdgeCases() {
+    // Check URL rewriting with a disabled language.
+    $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);
+  }
+}
+
+/**
  * Functional test for multilingual fields.
  */
 class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
Index: modules/path/path.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.test,v
retrieving revision 1.40
diff -u -p -r1.40 path.test
--- modules/path/path.test	5 Aug 2010 23:53:38 -0000	1.40
+++ modules/path/path.test	1 Oct 2010 15:49:10 -0000
@@ -299,6 +299,8 @@ class PathLanguageTestCase extends Drupa
 
     // Confirm that the alias is returned by url().
     drupal_static_reset('language_list');
+    drupal_static_reset('locale_url_outbound_alter');
+    drupal_static_reset('locale_language_url_rewrite_url');
     $languages = language_list();
     $url = url('node/' . $french_node->nid, array('language' => $languages[$french_node->language]));
     $this->assertTrue(strpos($url, $edit['path[alias]']), t('URL contains the path alias.'));
