diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 70c837cdb9a9e344d4b9b78bfbcf5f966f7fa94e..1b38308808ecb11c4efaed51fd20d4ba2aa3fed1 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,5 +1,26 @@
 
-Drupal 7.0, xxxx-xx-xx (development version)
+Drupal 7.3-dev, xxxx-xx-xx (development version)
+----------------------
+
+Drupal 7.2, 2011-05-25
+----------------------
+- Added a default .gitignore file.
+- Improved PostgreSQL and SQLite support.
+- Numerous critical performance improvements.
+- Numerous critical fixes to the upgrade path.
+- Numerous fixes to language and translation systems.
+- Numerous fixes to AJAX and #states systems.
+- Improvements to the locking system.
+- Numerous documentation fixes.
+- Numerous styling and theme system fixes.
+- Numerous fixes for schema mis-matches between Drupal 6 and 7.
+- Minor internal API clean-ups.
+
+Drupal 7.1, 2011-05-25
+----------------------
+- Fixed security issues (Cross site scripting, File access bypass), see SA-CORE-2011-001.
+
+Drupal 7.0, 2011-01-05 
 ----------------------
 - Database:
     * Fully rewritten database layer utilizing PHP 5's PDO abstraction layer.
@@ -218,6 +239,159 @@ Drupal 7.0, xxxx-xx-xx (development version)
     * Added a locking framework to coordinate long-running operations across
       requests.
 
+Drupal 6.23-dev, xxxx-xx-xx (development release)
+-----------------------
+
+Drupal 6.22, 2011-05-25
+-----------------------
+- Made Drupal 6 work better with IIS and Internet Explorer.
+- Fixed .po file imports to work better with custom textgroups.
+- Improved code documentation at various places.
+- Fixed a variety of other bugs.
+
+Drupal 6.21, 2011-05-25
+----------------------
+- Fixed security issues (Cross site scripting), see SA-CORE-2011-001.
+
+Drupal 6.20, 2010-12-15
+----------------------
+- Fixed a variety of small bugs, improved code documentation.
+
+Drupal 6.19, 2010-08-11
+----------------------
+- Fixed a variety of small bugs, improved code documentation.
+
+Drupal 6.18, 2010-08-11
+----------------------
+- Fixed security issues (OpenID authentication bypass, File download access
+  bypass, Comment unpublishing bypass, Actions cross site scripting),
+  see SA-CORE-2010-002.
+
+Drupal 6.17, 2010-06-02
+----------------------
+- Improved PostgreSQL compatibility
+- Better PHP 5.3 and PHP 4 compatibility
+- Better browser compatibility of CSS and JS aggregation
+- Improved logging for login failures
+- Fixed an incompatibility with some contributed modules and the locking system
+- Fixed a variety of other bugs.
+
+Drupal 6.16, 2010-03-03
+----------------------
+- Fixed security issues (Installation cross site scripting, Open redirection,
+  Locale module cross site scripting, Blocked user session regeneration),
+  see SA-CORE-2010-001.
+- Better support for updated jQuery versions.
+- Reduced resource usage of update.module.
+- Fixed several issues relating to support of install profiles and
+  distributions.
+- Added a locking framework to avoid data corruption on long operations.
+- Fixed a variety of other bugs.
+
+Drupal 6.15, 2009-12-16
+----------------------
+- Fixed security issues (Cross site scripting), see SA-CORE-2009-009.
+- Fixed a variety of other bugs.
+
+Drupal 6.14, 2009-09-16
+----------------------
+- Fixed security issues (OpenID association cross site request forgeries,
+  OpenID impersonation and File upload), see SA-CORE-2009-008.
+- Changed the system modules page to not run all cache rebuilds; use the
+  button on the performance settings page to achieve the same effect.
+- Added support for PHP 5.3.0 out of the box.
+- Fixed a variety of small bugs.
+
+Drupal 6.13, 2009-07-01
+----------------------
+- Fixed security issues (Cross site scripting, Input format access bypass and
+  Password leakage in URL), see SA-CORE-2009-007.
+- Fixed a variety of small bugs.
+
+Drupal 6.12, 2009-05-13
+----------------------
+- Fixed security issues (Cross site scripting), see SA-CORE-2009-006.
+- Fixed a variety of small bugs.
+
+Drupal 6.11, 2009-04-29
+----------------------
+- Fixed security issues (Cross site scripting and limited information
+  disclosure), see SA-CORE-2009-005
+- Fixed performance issues with the menu router cache, the update
+  status cache and improved cache invalidation
+- Fixed a variety of small bugs.
+
+Drupal 6.10, 2009-02-25
+----------------------
+- Fixed a security issue, (Local file inclusion on Windows),
+  see SA-CORE-2009-003
+- Fixed node_feed() so custom fields can show up in RSS feeds.
+- Improved PostgreSQL compatibility.
+- Fixed a variety of small bugs.
+
+Drupal 6.9, 2009-01-14
+----------------------
+- Fixed security issues, (Access Bypass, Validation Bypass and Hardening
+  against SQL injection), see SA-CORE-2009-001
+- Made HTTP request checking more robust and informative.
+- Fixed HTTP_HOST checking to work again with HTTP 1.0 clients and
+  basic shell scripts.
+- Removed t() calls from all schema documentation. Suggested best practice
+  changed for contributed modules, see http://drupal.org/node/322731.
+- Fixed a variety of small bugs.
+
+Drupal 6.8, 2008-12-11
+----------------------
+- Removed a previous change incompatible with PHP 5.1.x and lower.
+
+Drupal 6.7, 2008-12-10
+----------------------
+- Fixed security issues, (Cross site request forgery and Cross site scripting), see SA-2008-073
+- Updated robots.txt and .htaccess to match current file use.
+- Fixed a variety of small bugs.
+
+Drupal 6.6, 2008-10-22
+----------------------
+- Fixed security issues, (File inclusion, Cross site scripting), see SA-2008-067
+- Fixed a variety of small bugs.
+
+Drupal 6.5, 2008-10-08
+----------------------
+- Fixed security issues, (File upload access bypass, Access rules bypass,
+  BlogAPI access bypass), see SA-2008-060.
+- Fixed a variety of small bugs.
+
+Drupal 6.4, 2008-08-13
+----------------------
+- Fixed a security issue (Cross site scripting, Arbitrary file uploads via
+  BlogAPI, Cross site request forgeries and Various Upload module
+  vulnerabilities), see SA-2008-047.
+- Improved error messages during installation.
+- Fixed a bug that prevented AHAH handlers to be attached to radios widgets.
+- Fixed a variety of small bugs.
+
+Drupal 6.3, 2008-07-09
+----------------------
+- Fixed security issues, (Cross site scripting, cross site request forgery,
+  session fixation and SQL injection), see SA-2008-044.
+- Slightly modified installation process to prevent file ownership issues on
+  shared hosts.
+- Improved PostgreSQL compatibility (rewritten queries; custom blocks).
+- Upgraded to jQuery 1.2.6.
+- Performance improvements to search, menu handling and form API caches.
+- Fixed Views compatibility issues (Views for Drupal 6 requires Drupal 6.3+).
+- Fixed a variety of small bugs.
+
+Drupal 6.2, 2008-04-09
+----------------------
+- Fixed a variety of small bugs.
+- Fixed a security issue (Access bypasses), see SA-2008-026.
+
+Drupal 6.1, 2008-02-27
+----------------------
+- Fixed a variety of small bugs.
+- Fixed a security issue (Cross site scripting), see SA-2008-018.
+
 Drupal 6.0, 2008-02-13
 ----------------------
 - New, faster and better menu system.
@@ -320,6 +494,95 @@ Drupal 6.0, 2008-02-13
 - Removed old system updates. Updates from Drupal versions prior to 5.x will
   require upgrading to 5.x before upgrading to 6.x.
 
+Drupal 5.23, 2010-08-11
+-----------------------
+- Fixed security issues (File download access bypass, Comment unpublishing
+  bypass), see SA-CORE-2010-002.
+
+Drupal 5.22, 2010-03-03
+-----------------------
+- Fixed security issues (Open redirection, Locale module cross site scripting,
+  Blocked user session regeneration), see SA-CORE-2010-001.
+
+Drupal 5.21, 2009-12-16
+-----------------------
+- Fixed a security issue (Cross site scripting), see SA-CORE-2009-009.
+- Fixed a variety of small bugs.
+
+Drupal 5.20, 2009-09-16
+-----------------------
+- Avoid security problems resulting from writing Drupal 6-style menu
+  declarations.
+- Fixed security issues (session fixation), see SA-CORE-2009-008.
+- Fixed a variety of small bugs.
+
+Drupal 5.19, 2009-07-01
+-----------------------
+- Fixed security issues (Cross site scripting and Password leakage in URL), see
+  SA-CORE-2009-007.          
+- Fixed a variety of small bugs.
+
+Drupal 5.18, 2009-05-13
+-----------------------
+- Fixed security issues (Cross site scripting), see SA-CORE-2009-006.
+- Fixed a variety of small bugs.
+
+Drupal 5.17, 2009-04-29
+-----------------------
+- Fixed security issues (Cross site scripting and limited information
+  disclosure) see SA-CORE-2009-005.
+- Fixed a variety of small bugs.
+
+Drupal 5.16, 2009-02-25
+-----------------------
+- Fixed a security issue, (Local file inclusion on Windows), see SA-CORE-2009-004.
+- Fixed a variety of small bugs.
+
+Drupal 5.15, 2009-01-14
+-----------------------
+- Fixed security issues, (Hardening against SQL injection), see
+  SA-CORE-2009-001
+- Fixed HTTP_HOST checking to work again with HTTP 1.0 clients and basic shell
+  scripts.
+- Fixed a variety of small bugs.
+
+Drupal 5.14, 2008-12-11
+-----------------------
+- removed a previous change incompatible with PHP 5.1.x and lower.
+
+Drupal 5.13, 2008-12-10
+-----------------------
+- fixed a variety of small bugs.
+- fixed security issues, (Cross site request forgery and Cross site scripting), see SA-2008-073
+- updated robots.txt and .htaccess to match current file use.
+
+Drupal 5.12, 2008-10-22
+-----------------------
+- fixed security issues, (File inclusion), see SA-2008-067
+
+Drupal 5.11, 2008-10-08
+-----------------------
+- fixed a variety of small bugs.
+- fixed security issues, (File upload access bypass, Access rules bypass,
+  BlogAPI access bypass, Node validation bypass), see SA-2008-060
+
+Drupal 5.10, 2008-08-13
+-----------------------
+- fixed a variety of small bugs.
+- fixed security issues, (Cross site scripting, Arbitrary file uploads via
+  BlogAPI and Cross site request forgery), see SA-2008-047
+
+Drupal 5.9, 2008-07-23
+----------------------
+- fixed a variety of small bugs.
+- fixed security issues, (Session fixation), see SA-2008-046
+
+Drupal 5.8, 2008-07-09
+----------------------
+- fixed a variety of small bugs.
+- fixed security issues, (Cross site scripting, cross site request forgery, and
+  session fixation), see SA-2008-044
+
 Drupal 5.7, 2008-01-28
 ----------------------
 - fixed the input format configuration page.
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index bbddde2a7649fed5774b7b57f2a47b23d5ead74c..a5dec6997138aa94b7f96155d21b6235a3ace708 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -8,7 +8,7 @@
 /**
  * The current system version.
  */
-define('VERSION', '7.0-dev');
+define('VERSION', '7.3-dev');
 
 /**
  * Core API compatibility.
diff --git a/includes/language.inc b/includes/language.inc
index eb13eacc3746a6a6d4f83067f5d0c841932f9f47..b7057f2a138cc69b64303d45b1ed245ed1f00aad 100644
--- a/includes/language.inc
+++ b/includes/language.inc
@@ -83,6 +83,44 @@ function language_types_disable($types) {
   variable_set('language_types', $enabled_types);
 }
 
+/**
+ * Updates the language type configuration.
+ */
+function language_types_set() {
+  // Ensure that we are getting the defined language negotiation information. An
+  // invocation of module_enable() or module_disable() could outdate the cached
+  // information.
+  drupal_static_reset('language_types_info');
+  drupal_static_reset('language_negotiation_info');
+
+  // Determine which language types are configurable and which not by checking
+  // whether the 'fixed' key is defined. Non-configurable (fixed) language types
+  // have their language negotiation settings stored there.
+  $defined_providers = language_negotiation_info();
+  foreach (language_types_info() as $type => $info) {
+    if (isset($info['fixed'])) {
+      $language_types[$type] = FALSE;
+      $negotiation = array();
+      foreach ($info['fixed'] as $weight => $id) {
+        if (isset($defined_providers[$id])) {
+          $negotiation[$id] = $weight;
+        }
+      }
+      language_negotiation_set($type, $negotiation);
+    }
+    else {
+      $language_types[$type] = TRUE;
+    }
+  }
+
+  // Save language types.
+  variable_set('language_types', $language_types);
+
+  // Ensure that subsequent calls of language_types_configurable() return the
+  // updated language type information.
+  drupal_static_reset('language_types_configurable');
+}
+
 /**
  * Check if a language provider is enabled.
  *
@@ -173,6 +211,28 @@ function language_negotiation_get_switch_links($type, $path) {
   return $links;
 }
 
+/**
+ * Updates language configuration to remove any language provider that is no longer defined.
+ */
+function language_negotiation_purge() {
+  // Ensure that we are getting the defined language negotiation information. An
+  // invocation of module_enable() or module_disable() could outdate the cached
+  // information.
+  drupal_static_reset('language_negotiation_info');
+  drupal_static_reset('language_types_info');
+
+  $defined_providers = language_negotiation_info();
+  foreach (language_types_info() as $type => $type_info) {
+    $weight = 0;
+    $negotiation = array();
+    foreach (variable_get("language_negotiation_$type", array()) as $id => $provider) {
+      if (isset($defined_providers[$id])) {
+        $negotiation[$id] = $weight++;
+      }
+    }
+    language_negotiation_set($type, $negotiation);
+  }
+}
 
 /**
  * Save a list of language providers.
@@ -180,7 +240,8 @@ function language_negotiation_get_switch_links($type, $path) {
  * @param $type
  *   The language negotiation type.
  * @param $language_providers
- *   An array of language provider ids.
+ *   An array of language provider weights keyed by id.
+ *   @see language_provider_weight()
  */
 function language_negotiation_set($type, $language_providers) {
   // Save only the necessary fields.
@@ -189,7 +250,7 @@ function language_negotiation_set($type, $language_providers) {
   $negotiation = array();
   $providers_weight = array();
   $defined_providers = language_negotiation_info();
-  $default_types = language_types_configurable();
+  $default_types = language_types_configurable(FALSE);
 
   // Initialize the providers weight list.
   foreach ($language_providers as $id => $provider) {
diff --git a/modules/block/block.module b/modules/block/block.module
index 2f7e372fe3379d4d2cac051a23b8f11485493e6c..73eba3311618f0cbb9d9d1731f5a00c4e568321c 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -943,7 +943,15 @@ function template_preprocess_block(&$variables) {
 
   $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->region;
   $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->module;
-  $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->module . '__' . $variables['block']->delta;
+  // Hyphens (-) and underscores (_) play a special role in theme suggestions.
+  // Theme suggestions should only contain underscores, because within
+  // drupal_find_theme_templates(), underscores are converted to hyphens to
+  // match template file names, and then converted back to underscores to match
+  // pre-processing and other function names. So if your theme suggestion
+  // contains a hyphen, it will end up as an underscore after this conversion,
+  // and your function names won't be recognized. So, we need to convert
+  // hyphens to underscores in block deltas for the theme suggestions.
+  $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->module . '__' . strtr($variables['block']->delta, '-', '_');
 
   // Create a valid HTML ID and make sure it is unique.
   $variables['block_html_id'] = drupal_html_id('block-' . $variables['block']->module . '-' . $variables['block']->delta);
diff --git a/modules/block/block.test b/modules/block/block.test
index af118a940d3bf4af96ef3837cca37e705fcb5f27..022bf383031d7556d491ae9b6e87e0767a2e54f1 100644
--- a/modules/block/block.test
+++ b/modules/block/block.test
@@ -666,3 +666,45 @@ class BlockHTMLIdTestCase extends DrupalWebTestCase {
     $this->assertRaw('block-block-test-test-html-id', t('HTML id for test block is valid.'));
   }
 }
+
+
+/**
+ * Unit tests for template_preprocess_block().
+ */
+class BlockTemplateSuggestionsUnitTest extends DrupalUnitTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Block template suggestions',
+      'description' => 'Test the template_preprocess_block() function.',
+      'group' => 'Block',
+    );
+  }
+
+  /**
+   * Test if template_preprocess_block() handles the suggestions right.
+   */
+  function testBlockThemeHookSuggestions() {
+    // Define block delta with underscore to be preprocessed
+    $block1 = new stdClass();
+    $block1->module = 'block';
+    $block1->delta = 'underscore_test';
+    $block1->region = 'footer';
+    $variables1 = array();
+    $variables1['elements']['#block'] = $block1;
+    $variables1['elements']['#children'] = '';
+    template_preprocess_block($variables1);
+    $this->assertEqual($variables1['theme_hook_suggestions'], array('block__footer', 'block__block', 'block__block__underscore_test'), t('Found expected block suggestions for delta with underscore'));
+
+    // Define block delta with hyphens to be preprocessed. Hyphens should be
+    // replaced with underscores.
+    $block2 = new stdClass();
+    $block2->module = 'block';
+    $block2->delta = 'hyphen-test';
+    $block2->region = 'footer';
+    $variables2 = array();
+    $variables2['elements']['#block'] = $block2;
+    $variables2['elements']['#children'] = '';
+    template_preprocess_block($variables2);
+    $this->assertEqual($variables2['theme_hook_suggestions'], array('block__footer', 'block__block', 'block__block__hyphen_test'), t('Hyphens (-) in block delta were replaced by underscore (_)'));
+  }
+}
diff --git a/modules/color/color.install b/modules/color/color.install
index 5705ade3f8b4c1d2955c07bac3ef179304ad01be..b0eb95ef6a57f47f2ce91289e7f01fc8201bbe5a 100644
--- a/modules/color/color.install
+++ b/modules/color/color.install
@@ -40,3 +40,18 @@ function color_requirements($phase) {
 
   return $requirements;
 }
+
+/**
+ * Warn site administrator if unsafe CSS color codes are found in the database.
+ */
+function color_update_7001() {
+  $theme_palettes = db_query("SELECT name FROM {variable} WHERE name LIKE 'color_%_palette'")->fetchCol();
+  foreach ($theme_palettes as $name) {
+    $palette = variable_get($name, array());
+    foreach ($palette as $key => $color) {
+      if (!preg_match('/^#([a-f0-9]{3}){1,2}$/iD', $color)) {
+        drupal_set_message('Some of the custom CSS color codes specified via the color module are invalid. Please examine the themes which are making use of the color module at the <a href="'. url('admin/appearance/settings') .'">Appearance settings</a> page to verify their CSS color values.', 'warning');
+      }
+    }
+  }
+}
diff --git a/modules/color/color.module b/modules/color/color.module
index ff6c70e6cb7617f56ebc1c9674ab1575ac696b92..f3fafe7b7e6fbd876b6f1fc022bbf4f1bd515bed 100644
--- a/modules/color/color.module
+++ b/modules/color/color.module
@@ -42,6 +42,7 @@ function color_form_system_theme_settings_alter(&$form, &$form_state) {
       '#theme' => 'color_scheme_form',
     );
     $form['color'] += color_scheme_form($form, $form_state, $theme);
+    $form['#validate'][] = 'color_scheme_form_validate';
     $form['#submit'][] = 'color_scheme_form_submit';
   }
 }
@@ -270,6 +271,18 @@ function theme_color_scheme_form($variables) {
   return $output;
 }
 
+/**
+ * Validation handler for color change form.
+ */
+function color_scheme_form_validate($form, &$form_state) {
+  // Only accept hexadecimal CSS color strings to avoid XSS upon use.
+  foreach ($form_state['values']['palette'] as $key => $color) {
+    if (!preg_match('/^#([a-f0-9]{3}){1,2}$/iD', $color)) {
+      form_set_error('palette][' . $key, t('%name must be a valid hexadecimal CSS color value.', array('%name' => $form['color']['palette'][$key]['#title'])));
+    }
+  }
+}
+
 /**
  * Submit handler for color change form.
  */
diff --git a/modules/file/file.module b/modules/file/file.module
index 400270178642487a8d02924b720c099c2ae8ad93..3e4525119611cf49c3ff46f864e6a0a72989cf13 100644
--- a/modules/file/file.module
+++ b/modules/file/file.module
@@ -976,7 +976,7 @@ function file_get_file_references($file, $field = NULL, $age = FIELD_LOAD_REVISI
     }
   }
 
-  return isset($field) ? $references[$field['field_name']] : $references;
+  return isset($field) ? $references[$field['field_name']] : array_filter($references);
 }
 
 /**
diff --git a/modules/locale/locale.admin.inc b/modules/locale/locale.admin.inc
index de16133fb5a9e7115a7434643dfcfa0384f21374..d8201dbf227bd7cb06799470c951402cf86e80f2 100644
--- a/modules/locale/locale.admin.inc
+++ b/modules/locale/locale.admin.inc
@@ -541,6 +541,12 @@ function _locale_languages_configure_form_language_table(&$form, $type) {
   asort($providers_weight);
 
   foreach ($providers_weight as $id => $weight) {
+    // A language provider might be no more available if the defining module has
+    // been disabled after the last configuration saving.
+    if (!isset($language_providers[$id])) {
+      continue;
+    }
+
     $enabled = isset($enabled_providers[$id]);
     $provider = $language_providers[$id];
 
@@ -658,7 +664,6 @@ function theme_locale_languages_configure_form($variables) {
  * Submit handler for language negotiation settings.
  */
 function locale_languages_configure_form_submit($form, &$form_state) {
-  $language_types = array();
   $configurable_types = $form['#language_types'];
 
   foreach ($configurable_types as $type) {
@@ -666,7 +671,6 @@ function locale_languages_configure_form_submit($form, &$form_state) {
     $enabled_providers = $form_state['values'][$type]['enabled'];
     $enabled_providers[LANGUAGE_NEGOTIATION_DEFAULT] = TRUE;
     $providers_weight = $form_state['values'][$type]['weight'];
-    $language_types[$type] = TRUE;
 
     foreach ($providers_weight as $id => $weight) {
       if ($enabled_providers[$id]) {
@@ -680,27 +684,11 @@ function locale_languages_configure_form_submit($form, &$form_state) {
     variable_set("locale_language_providers_weight_$type", $providers_weight);
   }
 
-  // Save non-configurable language types negotiation.
-  $language_types_info = language_types_info();
-  $defined_providers = $form['#language_providers'];
-  foreach ($language_types_info as $type => $info) {
-    if (isset($info['fixed'])) {
-      $language_types[$type] = FALSE;
-      $negotiation = array();
-      foreach ($info['fixed'] as $weight => $id) {
-        if (isset($defined_providers[$id])) {
-          $negotiation[$id] = $defined_providers[$id];
-          $negotiation[$id]['weight'] = $weight;
-        }
-      }
-      language_negotiation_set($type, $negotiation);
-    }
-  }
-
-  // Save language types.
-  variable_set('language_types', $language_types);
+  // Update non-configurable language types and the related language negotiation
+  // configuration.
+  language_types_set();
 
-  $form_state['redirect'] = 'admin/config/regional/language';
+  $form_state['redirect'] = 'admin/config/regional/language/configure';
   drupal_set_message(t('Language negotiation configuration saved.'));
 }
 
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index c1cdd434bd05fbe960dd26ae90ef6f035f71b624..07884614a51e6b2d84ae1c91b842bbb83df46200 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -513,6 +513,8 @@ function locale_language_types_info() {
       'description' => t('Order of language detection methods for user interface text. If a translation of user interface text is available in the detected language, it will be displayed.'),
     ),
     LANGUAGE_TYPE_CONTENT => array(
+      'name' => t('Content'),
+      'description' => t('Order of language detection methods for content. If a version of content is available in the detected language, it will be displayed.'),
       'fixed' => array(LOCALE_LANGUAGE_NEGOTIATION_INTERFACE),
     ),
     LANGUAGE_TYPE_URL => array(
@@ -593,6 +595,22 @@ function locale_language_negotiation_info() {
   return $providers;
 }
 
+/**
+ * Implements hook_modules_enabled().
+ */
+function locale_modules_enabled($modules) {
+  include_once DRUPAL_ROOT . '/includes/language.inc';
+  language_types_set();
+  language_negotiation_purge();
+}
+
+/**
+ * Implements hook_modules_disabled().
+ */
+function locale_modules_disabled($modules) {
+  locale_modules_enabled($modules);
+}
+
 // ---------------------------------------------------------------------------------
 // Locale core functionality
 
@@ -928,7 +946,7 @@ function locale_block_info() {
   include_once DRUPAL_ROOT . '/includes/language.inc';
   $block = array();
   $info = language_types_info();
-  foreach (language_types_configurable() as $type) {
+  foreach (language_types_configurable(FALSE) as $type) {
     $block[$type] = array(
       'info' => t('Language switcher (@type)', array('@type' => $info[$type]['name'])),
       // Not worth caching.
diff --git a/modules/locale/locale.test b/modules/locale/locale.test
index 5e9e8336cf427fc824606da7cc620093d7e6cf7d..42a6dbc48063e34adc90df51f88707e0e5d05df3 100644
--- a/modules/locale/locale.test
+++ b/modules/locale/locale.test
@@ -17,6 +17,7 @@
  *  - a functional test for multilingual support by content type and on nodes.
  *  - a functional test for multilingual fields.
  *  - a functional test for comment language.
+ *  - a functional test fot language types/negotiation info.
  */
 
 
@@ -2248,10 +2249,13 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
     variable_set('locale_test_content_language_type', TRUE);
 
     // Set interface language detection to user and content language detection
-    // to URL.
+    // to URL. Disable inheritance from interface language to ensure content
+    // language will fall back to the default language if no URL language can be
+    // detected.
     $edit = array(
       'language[enabled][locale-user]' => TRUE,
-      'language_content[enabled][locale-url]' => TRUE
+      'language_content[enabled][locale-url]' => TRUE,
+      'language_content[enabled][locale-interface]' => FALSE,
     );
     $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
 
@@ -2373,3 +2377,158 @@ class LocaleDateFormatsFunctionalTest extends DrupalWebTestCase {
     $this->assertText($french_date, t('French date format appears'));
   }
 }
+
+/**
+ * Functional test for language types/negotiation info.
+ */
+class LocaleLanguageNegotiationInfoFunctionalTest extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Language negotiation info',
+      'description' => 'Tests alterations to language types/negotiation info.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+    require_once DRUPAL_ROOT .'/includes/language.inc';
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'view the administration theme'));
+    $this->drupalLogin($admin_user);
+    $this->drupalPost('admin/config/regional/language/add', array('langcode' => 'it'), t('Add language'));
+  }
+
+  /**
+   * Tests alterations to language types/negotiation info.
+   */
+  function testInfoAlterations() {
+    // Enable language type/negotiation info alterations.
+    variable_set('locale_test_language_types', TRUE);
+    variable_set('locale_test_language_negotiation_info', TRUE);
+    $this->languageNegotiationUpdate();
+
+    // Check that fixed language types are properly configured without the need
+    // of saving the language negotiation settings.
+    $this->checkFixedLanguageTypes();
+
+    // Make the content language type configurable by updating the language
+    // negotiation settings with the proper flag enabled.
+    variable_set('locale_test_content_language_type', TRUE);
+    $this->languageNegotiationUpdate();
+    $type = LANGUAGE_TYPE_CONTENT;
+    $language_types = variable_get('language_types', drupal_language_types());
+    $this->assertTrue($language_types[$type], t('Content language type is configurable.'));
+
+    // Enable some core and custom language providers. The test language type is
+    // supposed to be configurable.
+    $test_type = 'test_language_type';
+    $provider = LOCALE_LANGUAGE_NEGOTIATION_INTERFACE;
+    $test_provider = 'test_language_provider';
+    $form_field = $type . '[enabled]['. $provider .']';
+    $edit = array(
+      $form_field => TRUE,
+      $type . '[enabled][' . $test_provider . ']' => TRUE,
+      $test_type . '[enabled][' . $test_provider . ']' => TRUE,
+    );
+    $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
+
+    // Remove the interface language provider by updating the language
+    // negotiation settings with the proper flag enabled.
+    variable_set('locale_test_language_negotiation_info_alter', TRUE);
+    $this->languageNegotiationUpdate();
+    $negotiation = variable_get("language_negotiation_$type", array());
+    $this->assertFalse(isset($negotiation[$provider]), t('Interface language provider removed from the stored settings.'));
+    $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Interface language provider unavailable.'));
+
+    // Check that type-specific language providers can be assigned only to the
+    // corresponding language types.
+    foreach (language_types_configurable() as $type) {
+      $form_field = $type . '[enabled][test_language_provider_ts]';
+      if ($type == $test_type) {
+        $this->assertFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language provider available for %type.', array('%type' => $type)));
+      }
+      else {
+        $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language provider unavailable for %type.', array('%type' => $type)));
+      }
+    }
+
+    // Check language negotiation results.
+    $this->drupalGet('');
+    $last = variable_get('locale_test_language_negotiation_last', array());
+    foreach (language_types() as $type) {
+      $langcode = $last[$type];
+      $value = $type == LANGUAGE_TYPE_CONTENT || strpos($type, 'test') !== FALSE ? 'it' : 'en';
+      $this->assertEqual($langcode, $value, t('The negotiated language for %type is %language', array('%type' => $type, '%language' => $langcode)));
+    }
+
+    // Disable locale_test and check that everything is set back to the original
+    // status.
+    $this->languageNegotiationUpdate('disable');
+
+    // Check that only the core language types are available.
+    foreach (language_types() as $type) {
+      $this->assertTrue(strpos($type, 'test') === FALSE, t('The %type language is still available', array('%type' => $type)));
+    }
+
+    // Check that fixed language types are properly configured, even those
+    // previously set to configurable.
+    $this->checkFixedLanguageTypes();
+
+    // Check that unavailable language providers are not present in the
+    // negotiation settings.
+    $negotiation = variable_get("language_negotiation_$type", array());
+    $this->assertFalse(isset($negotiation[$test_provider]), t('The disabled test language provider is not part of the content language negotiation settings.'));
+
+    // Check that configuration page presents the correct options and settings.
+    $this->assertNoRaw(t('Test language detection'), t('No test language type configuration available.'));
+    $this->assertNoRaw(t('This is a test language provider'), t('No test language provider available.'));
+  }
+
+  /**
+   * Update language types/negotiation information.
+   *
+   * Manually invoke locale_modules_enabled()/locale_modules_disabled() since
+   * they would not be invoked after enabling/disabling locale_test the first
+   * time.
+   */
+  private function languageNegotiationUpdate($op = 'enable') {
+    static $last_op = NULL;
+    $modules = array('locale_test');
+
+    // Enable/disable locale_test only if we did not already before.
+    if ($last_op != $op) {
+      $function = "module_{$op}";
+      $function($modules);
+      // Reset hook implementation cache.
+      module_implements(NULL, FALSE, TRUE);
+    }
+
+    drupal_static_reset('language_types_info');
+    drupal_static_reset('language_negotiation_info');
+    $function = "locale_modules_{$op}d";
+    if (function_exists($function)) {
+      $function($modules);
+    }
+
+    $this->drupalGet('admin/config/regional/language/configure');
+  }
+
+  /**
+   * Check that language negotiation for fixed types matches the stored one.
+   */
+  private function checkFixedLanguageTypes() {
+    drupal_static_reset('language_types_info');
+    foreach (language_types_info() as $type => $info) {
+      if (isset($info['fixed'])) {
+        $negotiation = variable_get("language_negotiation_$type", array());
+        $equal = count($info['fixed']) == count($negotiation);
+        while ($equal && list($id) = each($negotiation)) {
+          list(, $info_id) = each($info['fixed']);
+          $equal = $info_id == $id;
+        }
+        $this->assertTrue($equal, t('language negotiation for %type is properly set up', array('%type' => $type)));
+      }
+    }
+  }
+}
diff --git a/modules/locale/tests/locale_test.module b/modules/locale/tests/locale_test.module
index f256b5c8682fd6a4a20f77ce2aa734d2c4558cd5..14a2588dd739305d16c0f70b26558f7bae48d6ed 100644
--- a/modules/locale/tests/locale_test.module
+++ b/modules/locale/tests/locale_test.module
@@ -27,14 +27,89 @@ function locale_test_boot() {
   }
 }
 
+/**
+ * Implements hook_init().
+ */
+function locale_test_init() {
+  locale_test_store_language_negotiation();
+}
+
+/**
+ * Implements hook_language_types_info().
+ */
+function locale_test_language_types_info() {
+  if (variable_get('locale_test_language_types', FALSE)) {
+    return array(
+      'test_language_type' => array(
+        'name' => t('Test'),
+        'description' => t('A test language type.'),
+      ),
+      'fixed_test_language_type' => array(
+        'fixed' => array('test_language_provider'),
+      ),
+    );
+  }
+}
+
 /**
  * Implements hook_language_types_info_alter().
  */
 function locale_test_language_types_info_alter(array &$language_types) {
   if (variable_get('locale_test_content_language_type', FALSE)) {
-    $language_types[LANGUAGE_TYPE_CONTENT] = array(
-      'name' => t('Content'),
-      'description' => t('Order of language detection methods for content. If a version of content is available in the detected language, it will be displayed.'),
+    unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']);
+  }
+}
+
+/**
+ * Implements hook_language_negotiation_info().
+ */
+function locale_test_language_negotiation_info() {
+  if (variable_get('locale_test_language_negotiation_info', FALSE)) {
+    $info = array(
+      'callbacks' => array(
+        'language' => 'locale_test_language_provider',
+      ),
+      'file' => drupal_get_path('module', 'locale_test') .'/locale_test.module',
+      'weight' => -10,
+      'description' => t('This is a test language provider.'),
     );
+
+    return array(
+      'test_language_provider' => array(
+        'name' => t('Test'),
+        'types' => array(LANGUAGE_TYPE_CONTENT, 'test_language_type', 'fixed_test_language_type'),
+      ) + $info,
+      'test_language_provider_ts' => array(
+        'name' => t('Type-specific test'),
+        'types' => array('test_language_type'),
+      ) + $info,
+    );
+  }
+}
+
+/**
+ * Implements hook_language_negotiation_info_alter().
+ */
+function locale_test_language_negotiation_info_alter(array &$language_providers) {
+  if (variable_get('locale_test_language_negotiation_info_alter', FALSE)) {
+    unset($language_providers[LOCALE_LANGUAGE_NEGOTIATION_INTERFACE]);
   }
 }
+
+/**
+ * Store the last negotiated languages.
+ */
+function locale_test_store_language_negotiation() {
+  $last = array();
+  foreach (language_types() as $type) {
+    $last[$type] = $GLOBALS[$type]->language;
+  }
+  variable_set('locale_test_language_negotiation_last', $last);
+}
+
+/**
+ * Test language provider.
+ */
+function locale_test_language_provider($languages) {
+  return 'it';
+}
diff --git a/modules/translation/translation.pages.inc b/modules/translation/translation.pages.inc
index 102d1b8823096ecc3264a4331415c148345afe8e..7e4f0af266aedc22713b4e47211e322fb5155814 100644
--- a/modules/translation/translation.pages.inc
+++ b/modules/translation/translation.pages.inc
@@ -37,12 +37,12 @@ function translation_node_overview($node) {
       $translation_node = node_load($translations[$langcode]->nid);
       $path = 'node/' . $translation_node->nid;
       $links = language_negotiation_get_switch_links($type, $path);
-      $title = empty($links->links[$langcode]) ? l($translation_node->title, $path) : l($translation_node->title, $links->links[$langcode]['href'], $links->links[$langcode]);
+      $title = empty($links->links[$langcode]['href']) ? l($translation_node->title, $path) : l($translation_node->title, $links->links[$langcode]['href'], $links->links[$langcode]);
       if (node_access('update', $translation_node)) {
         $text = t('edit');
         $path = 'node/' . $translation_node->nid . '/edit';
         $links = language_negotiation_get_switch_links($type, $path);
-        $options[] = empty($links->links[$langcode]) ? l($text, $path) : l($text, $links->links[$langcode]['href'], $links->links[$langcode]);
+        $options[] = empty($links->links[$langcode]['href']) ? l($text, $path) : l($text, $links->links[$langcode]['href'], $links->links[$langcode]);
       }
       $status = $translation_node->status ? t('Published') : t('Not published');
       $status .= $translation_node->translate ? ' - <span class="marker">' . t('outdated') . '</span>' : '';
@@ -58,7 +58,7 @@ function translation_node_overview($node) {
         $path = 'node/add/' . str_replace('_', '-', $node->type);
         $links = language_negotiation_get_switch_links($type, $path);
         $query = array('query' => array('translation' => $node->nid, 'target' => $langcode));
-        $options[] = empty($links->links[$langcode]) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], array_merge_recursive($links->links[$langcode], $query));
+        $options[] = empty($links->links[$langcode]['href']) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], array_merge_recursive($links->links[$langcode], $query));
       }
       $status = t('Not translated');
     }
diff --git a/modules/translation/translation.test b/modules/translation/translation.test
index fa8c6b63fc5b1f769ac6823b9c475081a2b08c0c..54b53d9fdc4e6856820a5333e94503b66a425093 100644
--- a/modules/translation/translation.test
+++ b/modules/translation/translation.test
@@ -20,7 +20,7 @@ class TranslationTestCase extends DrupalWebTestCase {
     parent::setUp('locale', 'translation', 'translation_test');
 
     // Setup users.
-    $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages'));
+    $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages', 'translate content'));
     $this->translator = $this->drupalCreateUser(array('create page content', 'edit own page content', 'translate content'));
 
     $this->drupalLogin($this->admin_user);
@@ -67,6 +67,14 @@ class TranslationTestCase extends DrupalWebTestCase {
     $node_body =  $this->randomName();
     $node = $this->createPage($node_title, $node_body, 'en');
 
+    // Unpublish the original node to check that this has no impact on the
+    // translation overview page, publish it again afterwards.
+    $this->drupalLogin($this->admin_user);
+    $this->drupalPost('node/' . $node->nid . '/edit', array('status' => FALSE), t('Save'));
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $this->drupalPost('node/' . $node->nid . '/edit', array('status' => NODE_PUBLISHED), t('Save'));
+    $this->drupalLogin($this->translator);
+
     // Check that the "add translation" link uses a localized path.
     $languages = language_list();
     $this->drupalGet('node/' . $node->nid . '/translate');