diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module
index 7214666c011bcf788e8982357ac18daada6497d9..433ffee5ed8740942dd58cd509fa0ab549dcc872 100644
--- a/core/modules/openid/openid.module
+++ b/core/modules/openid/openid.module
@@ -218,6 +218,58 @@ function openid_form_user_register_form_alter(&$form, &$form_state) {
       $form['account']['pass']['#value'] = user_password();
     }
 
+    $timezone = FALSE;
+    if (!empty($sreg_values['timezone'])) {
+      $timezone = $sreg_values['timezone'];
+    }
+    elseif ($ax_timezone_values = openid_extract_ax_values($ax_values, array('http://axschema.org/pref/timezone', 'http://openid.net/schema/timezone'))) {
+      $timezone = current($ax_timezone_values);
+    }
+    if (in_array($timezone, timezone_identifiers_list())) {
+      $form['#user']->timezone = $timezone;
+    }
+
+    $language = FALSE;
+    if (!empty($sreg_values['language'])) {
+      $language = $sreg_values['language'];
+    }
+    elseif ($ax_language_values = openid_extract_ax_values($ax_values, array('http://axschema.org/pref/language', 'http://openid.net/schema/language/pref'))) {
+      $language = current($ax_language_values);
+    }
+    if ($language) {
+      // The OpenID Simple Registration Extension specification is unclear about
+      // the format of openid.sreg.language. Codes like "EN" and "ZH_CN" have
+      // been observed.
+      // AX values are in RFC 4646 format, e.g. "de", "en-GB", "en-Latn-GB",
+      // "zh-Hans", or "zh-Hans-CN". The first part is the language, the second
+      // is the script, and the third is the region. Other parts are also
+      // defined, but we will not use them here. All parts except the first are
+      // optional.
+      // We generate a list of all permutations of the first three parts and
+      // match them against the list of enabled languages. E.g. if the user's
+      // preferred langugage is "en-GB", we look for "en-gb" (Drupal's language
+      // codes are lower-case) or fall back to "en".
+      $parts = preg_split('/[_-]/', strtolower($language));
+      $candidate_languages[] = $parts[0];
+      if (count($parts) > 1) {
+        $candidate_languages[] = $parts[0] . '-' . $parts[1];
+      }
+      if (count($parts) > 2) {
+        $candidate_languages[] = $parts[0] . '-' . $parts[2];
+        $candidate_languages[] = $parts[0] . '-' . $parts[1] . '-' . $parts[2];
+      }
+      $all_languages = language_list('enabled');
+      $enabled_languages = $all_languages[1];
+      // Iterate over the generated permutations starting with the longest (most
+      // specific) strings.
+      foreach (array_reverse($candidate_languages) as $candidate_language) {
+        if (isset($enabled_languages[$candidate_language])) {
+          $form['locale']['language']['#type'] = 'hidden';
+          $form['locale']['language']['#value'] = $candidate_language;
+        }
+      }
+    }
+
     $form['openid_claimed_id'] = array(
       '#type' => 'value',
       '#default_value' => $response['openid.claimed_id'],
@@ -754,6 +806,7 @@ function openid_authentication_request($claimed_id, $identity, $return_to = '',
   // that the Endpoint advertise OPENID_NS_SREG in the service description.
   $request['openid.ns.sreg'] = OPENID_NS_SREG;
   $request['openid.sreg.required'] = 'nickname,email';
+  $request['openid.sreg.optional'] = 'timezone,language';
 
   // Request Attribute Exchange, if available.
   // We only request the minimum attributes we need here, contributed modules
@@ -762,6 +815,7 @@ function openid_authentication_request($claimed_id, $identity, $return_to = '',
     $request['openid.ns.ax'] = OPENID_NS_AX;
     $request['openid.ax.mode'] = 'fetch_request';
     $request['openid.ax.required'] = 'mail_ao,name_ao,mail_son,name_son';
+    $request['openid.ax.if_available'] = 'timezone_ao,language_ao,timezone_son,language_son';
 
     // Implementors disagree on which URIs to use, even for simple
     // attributes like name and email (*sigh*). We ask for both axschema.org
@@ -771,10 +825,14 @@ function openid_authentication_request($claimed_id, $identity, $return_to = '',
     // Attributes as defined by axschema.org.
     $request['openid.ax.type.mail_ao'] = 'http://axschema.org/contact/email';
     $request['openid.ax.type.name_ao'] = 'http://axschema.org/namePerson/friendly';
+    $request['openid.ax.type.timezone_ao'] = 'http://axschema.org/pref/timezone';
+    $request['openid.ax.type.language_ao'] = 'http://axschema.org/pref/language';
 
     // Attributes as defined by schema.openid.net.
     $request['openid.ax.type.mail_son'] = 'http://schema.openid.net/contact/email';
     $request['openid.ax.type.name_son'] = 'http://schema.openid.net/namePerson/friendly';
+    $request['openid.ax.type.timezone_son'] = 'http://openid.net/schema/timezone';
+    $request['openid.ax.type.language_son'] = 'http://openid.net/schema/language/pref';
   }
 
   drupal_alter('openid_request', $request, $service);
diff --git a/core/modules/openid/openid.test b/core/modules/openid/openid.test
index b13fb0f388d10b01c1fb25f707faf2e3a1c895e7..93cbb6a1821c3bcb125b8502486f97d9a85b2ff6 100644
--- a/core/modules/openid/openid.test
+++ b/core/modules/openid/openid.test
@@ -399,9 +399,16 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
    */
   function testRegisterUserWithEmailVerification() {
     variable_set('user_email_verification', TRUE);
+    variable_get('configurable_timezones', 1);
+    variable_set('date_default_timezone', 'Europe/Brussels');
 
     // Tell openid_test.module to respond with these SREG fields.
-    variable_set('openid_test_response', array('openid.sreg.nickname' => 'john', 'openid.sreg.email' => 'john@example.com'));
+    variable_set('openid_test_response', array(
+      'openid.sreg.nickname' => 'john',
+      'openid.sreg.email' => 'john@example.com',
+      'openid.sreg.language' => 'en-GB',
+      'openid.sreg.timezone' => 'Europe/London',
+    ));
 
     // Use a User-supplied Identity that is the URL of an XRDS document.
     $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
@@ -413,6 +420,8 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
     $user = user_load_by_name('john');
     $this->assertTrue($user, t('User was registered with right username.'));
     $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
+    $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
+    $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
     $this->assertFalse($user->data, t('No additional user info was saved.'));
 
     $this->submitLoginForm($identity);
@@ -434,9 +443,16 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
    */
   function testRegisterUserWithoutEmailVerification() {
     variable_set('user_email_verification', FALSE);
+    variable_get('configurable_timezones', 1);
+    variable_set('date_default_timezone', 'Europe/Brussels');
 
     // Tell openid_test.module to respond with these SREG fields.
-    variable_set('openid_test_response', array('openid.sreg.nickname' => 'john', 'openid.sreg.email' => 'john@example.com'));
+    variable_set('openid_test_response', array(
+      'openid.sreg.nickname' => 'john',
+      'openid.sreg.email' => 'john@example.com',
+      'openid.sreg.language' => 'en-GB',
+      'openid.sreg.timezone' => 'Europe/London',
+    ));
 
     // Use a User-supplied Identity that is the URL of an XRDS document.
     $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
@@ -446,6 +462,8 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
     $user = user_load_by_name('john');
     $this->assertTrue($user, t('User was registered with right username.'));
     $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
+    $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
+    $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
     $this->assertFalse($user->data, t('No additional user info was saved.'));
 
     $this->drupalLogout();
@@ -459,9 +477,17 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
    * information (a username that is already taken, and no e-mail address).
    */
   function testRegisterUserWithInvalidSreg() {
+    variable_get('configurable_timezones', 1);
+    variable_set('date_default_timezone', 'Europe/Brussels');
+
     // Tell openid_test.module to respond with these SREG fields.
     $web_user = $this->drupalCreateUser(array());
-    variable_set('openid_test_response', array('openid.sreg.nickname' => $web_user->name, 'openid.sreg.email' => 'mail@invalid#'));
+    variable_set('openid_test_response', array(
+      'openid.sreg.nickname' => $web_user->name,
+      'openid.sreg.email' => 'mail@invalid#',
+      'openid.sreg.timezone' => 'Foo/Bar',
+      'openid.sreg.language' => 'foobar',
+    ));
 
     // Use a User-supplied Identity that is the URL of an XRDS document.
     $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
@@ -482,6 +508,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
 
     $user = user_load_by_name('john');
     $this->assertTrue($user, t('User was registered with right username.'));
+    $this->assertFalse($user->language, t('No user language was saved.'));
     $this->assertFalse($user->data, t('No additional user info was saved.'));
 
     // Follow the one-time login that was sent in the welcome e-mail.
@@ -501,6 +528,8 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
    * information (i.e. no username or e-mail address).
    */
   function testRegisterUserWithoutSreg() {
+    variable_get('configurable_timezones', 1);
+
     // Load the front page to get the user login block.
     $this->drupalGet('');
 
@@ -519,6 +548,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
 
     $user = user_load_by_name('john');
     $this->assertTrue($user, t('User was registered with right username.'));
+    $this->assertFalse($user->language, t('No user language was saved.'));
     $this->assertFalse($user->data, t('No additional user info was saved.'));
 
     // Follow the one-time login that was sent in the welcome e-mail.
@@ -538,6 +568,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
    */
   function testRegisterUserWithAXButNoSREG() {
     variable_set('user_email_verification', FALSE);
+    variable_set('date_default_timezone', 'Europe/Brussels');
 
     // Tell openid_test.module to respond with these AX fields.
     variable_set('openid_test_response', array(
@@ -547,6 +578,10 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
       'openid.ext123.type.name789' => 'http://schema.openid.net/namePerson/friendly',
       'openid.ext123.count.name789' => '1',
       'openid.ext123.value.name789.1' => 'john',
+      'openid.ext123.type.timezone' => 'http://axschema.org/pref/timezone',
+      'openid.ext123.value.timezone' => 'Europe/London',
+      'openid.ext123.type.language' => 'http://axschema.org/pref/language',
+      'openid.ext123.value.language' => 'en-GB',
     ));
 
     // Use a User-supplied Identity that is the URL of an XRDS document.
@@ -557,6 +592,8 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
     $user = user_load_by_name('john');
     $this->assertTrue($user, t('User was registered with right username.'));
     $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
+    $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
+    $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
   }
 }
 
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 625be0ac4527f92cdb4e61b23671f3ba2280246d..31e0de80aab87f428bda2d1ba62ef0f18d88c015 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1979,20 +1979,22 @@ function system_form_user_profile_form_alter(&$form, &$form_state) {
  * Implements hook_form_FORM_ID_alter().
  */
 function system_form_user_register_form_alter(&$form, &$form_state) {
-  if (variable_get('configurable_timezones', 1)) {
-    if (variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) == DRUPAL_USER_TIMEZONE_SELECT) {
-      system_user_timezone($form, $form_state);
-    }
-    else {
-      $form['account']['timezone'] = array(
-        '#type' => 'hidden',
-        '#value' => variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) ? '' : variable_get('date_default_timezone', ''),
-      );
-    }
+  if (variable_get('configurable_timezones', 1) && variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) == DRUPAL_USER_TIMEZONE_SELECT) {
+    system_user_timezone($form, $form_state);
     return $form;
   }
 }
 
+/**
+ * Implements hook_user_insert().
+ */
+function system_user_presave(&$edit, $account) {
+  if (variable_get('configurable_timezones', 1) && empty($account->timezone) && !variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT)) {
+    $account->timezone = variable_get('date_default_timezone', '');
+  }
+}
+
+
 /**
  * Implements hook_user_login().
  */