diff --git a/token.tokens.inc b/token.tokens.inc
index f584bda..f383420 100644
--- a/token.tokens.inc
+++ b/token.tokens.inc
@@ -247,6 +247,76 @@ function token_token_info() {
     'type' => 'menu-link',
   );
 
+  // Language tokens.
+  $info['types']['language'] = array(
+    'name' => t('Language'),
+    'description' => t('Tokens related to site language.'),
+  );
+  $info['tokens']['language']['language-ui'] = array(
+    'name' => t('User Interface'),
+    'description' => t('Tokens related to the active user interface language.'),
+    'type' => 'language-ui',
+  );
+  $info['tokens']['language']['language-content'] = array(
+    'name' => t('Content'),
+    'description' => t('Tokens related to the active content language.'),
+    'type' => 'language-content',
+  );
+
+  // User interface language tokens.
+  $info['types']['language-ui'] = array(
+    'name' => t('Language UI'),
+    'description' => t('Tokens related to the active user interface language.'),
+    'needs-data' => 'language-ui',
+  );
+  $info['tokens']['language-ui']['language'] = array(
+    'name' => t('Code'),
+    'description' => t('The active user interface language code.'),
+  );
+  $info['tokens']['language-ui']['name'] = array(
+    'name' => t('Name'),
+    'description' => t('The active user interface language name.'),
+  );
+  $info['tokens']['language-ui']['native'] = array(
+    'name' => t('Native name'),
+    'description' => t('The active user interface native language name.'),
+  );
+  $info['tokens']['language-ui']['domain'] = array(
+    'name' => t('Domain'),
+    'description' => t('The domain name to use for the active user interface language.'),
+  );
+  $info['tokens']['language-ui']['prefix'] = array(
+    'name' => t('Path prefix'),
+    'description' => t('Path prefix for URLs in the active user interface language.'),
+  );
+
+  // Content language tokens.
+  $info['types']['language-content'] = array(
+    'name' => t('Language Content'),
+    'description' => t('Tokens related to the active content language.'),
+    'needs-data' => 'language-content',
+  );
+  $info['tokens']['language-content']['language'] = array(
+    'name' => t('Code'),
+    'description' => t('The active content language code.'),
+  );
+  $info['tokens']['language-content']['name'] = array(
+    'name' => t('Name'),
+    'description' => t('The active content language name.'),
+  );
+  $info['tokens']['language-content']['native'] = array(
+    'name' => t('Native name'),
+    'description' => t('The active content language native name.'),
+  );
+  $info['tokens']['language-ui']['domain'] = array(
+    'name' => t('Domain'),
+    'description' => t('The domain name to use for the active content language.'),
+  );
+  $info['tokens']['language-ui']['prefix'] = array(
+    'name' => t('Path prefix'),
+    'description' => t('Path prefix for URLs in the active content language.'),
+  );
+
   // Current page tokens.
   $info['types']['current-page'] = array(
     'name' => t('Current page'),
@@ -659,6 +729,68 @@ function token_tokens($type, $tokens, array $data = array(), array $options = ar
     }
   }
 
+  // Language tokens.
+  if ($type == 'language') {
+    global $language, $language_content;
+    // Handle the top-level language object output.
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'language-content':
+          $replacements[$original] = token_render_array((array) $language_content);
+          break;
+        case 'language-ui':
+          $replacements[$original] = token_render_array((array) $language);
+          break;
+      }
+    }
+
+    // Content language tokens.
+    if ($language_content_tokens = token_find_with_prefix($tokens, 'language-content')) {
+      foreach ($language_content_tokens as $name => $original) {
+        switch ($name) {
+          case 'language':
+            $replacements[$original] = $sanitize ? check_plain($language_content->language) : $language_content->language;
+            break;
+          case 'name':
+            $replacements[$original] = $sanitize ? check_plain($language_content->name) : $language_content->name;
+            break;
+          case 'native':
+            $replacements[$original] = $sanitize ? check_plain($language_content->native) : $language_content->native;
+            break;
+          case 'domain':
+            $replacements[$original] = $sanitize ? check_plain($language_content->domain) : $language_content->domain;
+            break;
+          case 'prefix':
+            $replacements[$original] = $sanitize ? check_plain($language_content->prefix) : $language_content->prefix;
+            break;
+        }
+      }
+    }
+
+    // UI language tokens.
+    if ($language_ui_tokens = token_find_with_prefix($tokens, 'language-ui')) {
+      foreach ($language_ui_tokens as $name => $original) {
+        switch ($name) {
+          case 'language':
+            $replacements[$original] = $sanitize ? check_plain($language->language) : $language->language;
+            break;
+          case 'name':
+            $replacements[$original] = $sanitize ? check_plain($language->name) : $language->name;
+            break;
+          case 'native':
+            $replacements[$original] = $sanitize ? check_plain($language->native) : $language->native;
+            break;
+          case 'domain':
+            $replacements[$original] = $sanitize ? check_plain($language->domain) : $language->domain;
+            break;
+          case 'prefix':
+            $replacements[$original] = $sanitize ? check_plain($language->prefix) : $language->prefix;
+            break;
+        }
+      }
+    }
+  }
+
   // Current page tokens.
   if ($type == 'current-page') {
     $current_path = current_path();
