diff --git a/token.tokens.inc b/token.tokens.inc
index 88f02a2..66e546f 100644
--- a/token.tokens.inc
+++ b/token.tokens.inc
@@ -23,6 +23,7 @@ use Drupal\Core\TypedData\PrimitiveInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\image\Entity\ImageStyle;
+use Drupal\Core\Language\LanguageInterface;
 
 /**
  * Implements hook_token_info_alter().
@@ -169,6 +170,11 @@ function token_token_info() {
 
   // Taxonomy term and vocabulary tokens.
   if (\Drupal::moduleHandler()->moduleExists('taxonomy')) {
+    $info['tokens']['term']['source'] = array(
+      'name' => t('Translation source term'),
+      'description' => t("The source term for this current term's translation set."),
+      'type' => 'term',
+    );
     $info['tokens']['term']['edit-url'] = array(
       'name' => t('Edit URL'),
       'description' => t("The URL of the taxonomy term's edit page."),
@@ -185,6 +191,11 @@ function token_token_info() {
       'type' => 'term',
     );
 
+    $info['tokens']['vocabulary']['source'] = array(
+      'name' => t('Translation source vocabulary'),
+      'description' => t("The source vocabulary for this current vocabulary's translation set."),
+      'type' => 'vocabulary',
+    );
     $info['tokens']['vocabulary']['machine-name'] = array(
       'name' => t('Machine-readable name'),
       'description' => t('The unique machine-readable name of the vocabulary.'),
@@ -558,6 +569,11 @@ function token_tokens($type, array $tokens, array $data = array(), array $option
     }
 
     // Chained token relationships.
+    if (($parent_tokens = \Drupal::token()->findWithPrefix($tokens, 'source')) && $source_term = \Drupal::service('entity.repository')->getTranslationFromContext($term, LanguageInterface::LANGCODE_DEFAULT)) {
+      $replacements += \Drupal::token()->generate('term', $parent_tokens, array(
+        'term' => $source_term), $options,
+        $bubbleable_metadata);
+    }
     if (($url_tokens = \Drupal::token()->findWithPrefix($tokens, 'url'))) {
       $replacements += \Drupal::token()->generate('url', $url_tokens, array('url' => $term->urlInfo()), $options, $bubbleable_metadata);
     }
@@ -590,6 +606,13 @@ function token_tokens($type, array $tokens, array $data = array(), array $option
           break;
       }
     }
+
+    // Chained token relationships.
+    if (($parent_tokens = \Drupal::token()->findWithPrefix($tokens, 'source')) && $source_vocabulary = \Drupal::service('entity.repository')->getTranslationFromContext($vocabulary, LanguageInterface::LANGCODE_DEFAULT)) {
+      $replacements += \Drupal::token()->generate('vocabulary', $parent_tokens, array(
+        'vocabulary' => $source_vocabulary),
+        $options, $bubbleable_metadata);
+    }
   }
 
   // File tokens.
