diff --git a/core/modules/user/lib/Drupal/user/Tests/UserTokenReplaceTest.php b/core/modules/user/lib/Drupal/user/Tests/UserTokenReplaceTest.php
index 974d92e..9683ee9 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserTokenReplaceTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserTokenReplaceTest.php
@@ -13,6 +13,14 @@ use Drupal\simpletest\WebTestBase;
  * Test user token replacement in strings.
  */
 class UserTokenReplaceTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('language');
+
   public static function getInfo() {
     return array(
       'name' => 'User token replacement',
@@ -21,6 +29,14 @@ class UserTokenReplaceTest extends WebTestBase {
     );
   }
 
+  public function setUp() {
+    parent::setUp();
+    $language = (object) array(
+      'langcode' => 'de',
+    );
+    language_save($language);
+  }
+
   /**
    * Creates a user, then tests the tokens generated from it.
    */
@@ -71,5 +87,35 @@ class UserTokenReplaceTest extends WebTestBase {
       $output = token_replace($input, array('user' => $account), array('language' => $language_interface, 'sanitize' => FALSE));
       $this->assertEqual($output, $expected, t('Unsanitized user token %token replaced.', array('%token' => $input)));
     }
+
+    // Generate login and cancel link.
+    $tests = array();
+    $tests['[user:one-time-login-url]'] = user_pass_reset_url($account);
+    $tests['[user:cancel-url]'] = user_cancel_url($account);
+
+    // Generate tokens with interface language.
+    $link = url('user', array('absolute' => TRUE));
+    foreach ($tests as $input => $expected) {
+      $output = token_replace($input, array('user' => $account), array('langcode' => $language_interface->langcode, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
+      $this->assertTrue(strpos($output, $link) === 0, 'Generated URL is in interface language.');
+    }
+
+    // Generate tokens with the users preferred language.
+    $account->preferred_langcode = 'de';
+    $account->save();
+    $link = url('user', array('language' => language_load($account->preferred_langcode), 'absolute' => TRUE));
+    foreach ($tests as $input => $expected) {
+      $output = token_replace($input, array('user' => $account), array('callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
+      $this->assertTrue(strpos($output, $link) === 0, 'Generated URL the users preferred language.');
+    }
+
+    // Generate tokens with one specific language.
+    $link = url('user', array('language' => language_load('de'), 'absolute' => TRUE));
+    foreach ($tests as $input => $expected) {
+      foreach (array($user1, $user2) as $account) {
+        $output = token_replace($input, array('user' => $account), array('langcode' => 'de', 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
+        $this->assertTrue(strpos($output, $link) === 0, 'Generated URL the requested language.');
+      }
+    }
   }
 }
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 44cb266..0b3edd0 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1817,14 +1817,25 @@ function user_external_login_register($name, $module) {
  *
  * @param object $account
  *   An object containing the user account.
+ * @param array $options
+ *   (optional) A keyed array of settings. Supported options are:
+ *   - langcode: A language code to be used when generating locale-sensitive
+ *    urls. If langcode is NULL the users preferred language is used.
  *
  * @return
  *   A unique URL that provides a one-time log in for the user, from which
  *   they can change their password.
  */
-function user_pass_reset_url($account) {
+function user_pass_reset_url($account, $options = array()) {
   $timestamp = REQUEST_TIME;
-  return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
+  $url_options = array('absolute' => TRUE);
+  if (isset($options['langcode'])) {
+    $url_options['language'] = language_load($options['langcode']);
+  }
+  else {
+    $url_options['language'] = user_preferred_language($account);
+  }
+  return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), $url_options);
 }
 
 /**
@@ -1836,6 +1847,10 @@ function user_pass_reset_url($account) {
  *   - uid: The user uid number.
  *   - pass: The hashed user password string.
  *   - login: The user login name.
+ * @param array $options
+ *   (optional) A keyed array of settings. Supported options are:
+ *   - langcode: A language code to be used when generating locale-sensitive
+  *    urls. If langcode is NULL the users preferred language is used.
  *
  * @return
  *   A unique URL that may be used to confirm the cancellation of the user
@@ -1844,9 +1859,16 @@ function user_pass_reset_url($account) {
  * @see user_mail_tokens()
  * @see user_cancel_confirm()
  */
-function user_cancel_url($account) {
+function user_cancel_url($account, $options = array()) {
   $timestamp = REQUEST_TIME;
-  return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
+  $url_options = array('absolute' => TRUE);
+  if (isset($options['langcode'])) {
+    $url_options['language'] = language_load($options['langcode']);
+  }
+  else {
+    $url_options['language'] = user_preferred_language($account);
+  }
+  return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), $url_options);
 }
 
 /**
@@ -2297,7 +2319,7 @@ Your account on [site:name] has been canceled.
   if ($replace) {
     // We do not sanitize the token replacement, since the output of this
     // replacement is intended for an e-mail message, not a web browser.
-    return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
+    return token_replace($text, $variables, array('langcode' => $langcode, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
   }
 
   return $text;
@@ -2324,8 +2346,8 @@ Your account on [site:name] has been canceled.
  */
 function user_mail_tokens(&$replacements, $data, $options) {
   if (isset($data['user'])) {
-    $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user']);
-    $replacements['[user:cancel-url]'] = user_cancel_url($data['user']);
+    $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user'], $options);
+    $replacements['[user:cancel-url]'] = user_cancel_url($data['user'], $options);
   }
 }
 
