diff --git a/core/modules/settings_tray/settings_tray.module b/core/modules/settings_tray/settings_tray.module
index 7017439..14200cc 100644
--- a/core/modules/settings_tray/settings_tray.module
+++ b/core/modules/settings_tray/settings_tray.module
@@ -5,6 +5,7 @@
  * Allows configuring blocks and other configuration from the site front-end.
  */
 
+use Drupal\block\Entity\Block;
 use Drupal\Core\Asset\AttachedAssetsInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\settings_tray\Block\BlockEntityOffCanvasForm;
@@ -44,6 +45,17 @@ function settings_tray_contextual_links_view_alter(&$element, $items) {
       $element['#links']['settings-trayblock-configure']['title'] = t('Quick edit settings');
     }
 
+    $block_id = $element['#contextual_links']['block']['route_parameters']['block'];
+    $block = Block::load($block_id);
+    $lang = $block->language();
+    $current_lang = Drupal::languageManager()->getCurrentLanguage();
+    /** @var \Drupal\Core\Url $url */
+    $url = $element['#links']['settings-trayblock-configure']['url'];
+    $query = $url->getOption('query');
+    $query['config_lang'] = $current_lang->getId();
+    $url->setOption('query', $query);
+    $element['#links']['settings-trayblock-configure']['options']['query']['config_lang'] = $current_lang->getId();
+
     $element['#attached']['library'][] = 'settings_tray/drupal.off_canvas';
   }
 }
diff --git a/core/modules/settings_tray/src/Block/BlockEntityOffCanvasForm.php b/core/modules/settings_tray/src/Block/BlockEntityOffCanvasForm.php
index 2c6f80d..831b568 100644
--- a/core/modules/settings_tray/src/Block/BlockEntityOffCanvasForm.php
+++ b/core/modules/settings_tray/src/Block/BlockEntityOffCanvasForm.php
@@ -5,12 +5,14 @@
 use Drupal\block\BlockForm;
 use Drupal\block\BlockInterface;
 use Drupal\Component\Utility\Html;
+use Drupal\config_translation\Exception\ConfigMapperLanguageException;
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\RedirectCommand;
 use Drupal\Core\Ajax\ReplaceCommand;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginWithFormsInterface;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Url;
 
 /**
@@ -44,11 +46,10 @@ public function title(BlockInterface $block) {
   public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
+    $this->addTranslationElements($form, $form_state);
+
     // Create link to full block form.
-    $query = [];
-    if ($destination = $this->getRequest()->query->get('destination')) {
-      $query['destination'] = $destination;
-    }
+    $query = \Drupal::destination()->getAsArray();
     $form['advanced_link'] = [
       '#type' => 'link',
       '#title' => $this->t('Advanced block options'),
@@ -191,4 +192,185 @@ protected function getRedirectUrl() {
     }
   }
 
+  /**
+   * Add translation related elements if needed.
+   *
+   * @todo This code is mostly copied from
+   *   \Drupal\config_translation\Controller\ConfigTranslationController
+   *   clean up.
+   *
+   * @param $form
+   * @param $form_state
+   */
+  protected function addTranslationElements(&$form, $form_state) {
+    if (!\Drupal::moduleHandler()->moduleExists('config_translation')) {
+      return;
+    }
+
+    $lang_manager = \Drupal::languageManager();
+    $languages = $lang_manager->getLanguages();
+    if (count($languages) == 1) {
+      // No need to translate.
+      return;
+    }
+
+    $current_lang = \Drupal::request()->get('config_lang');
+    $mapper = $this->getConfigEntityMapper($current_lang);
+
+    try {
+      $original_langcode = $mapper->getLangcode();
+      $operations_access = TRUE;
+    }
+    catch (ConfigMapperLanguageException $exception) {
+      $items = [];
+      foreach ($mapper->getConfigNames() as $config_name) {
+        $langcode = $mapper->getLangcodeFromConfig($config_name);
+        $items[] = $this->t('@name: @langcode', [
+          '@name' => $config_name,
+          '@langcode'  => $langcode,
+        ]);
+      }
+      $message = [
+        'message' => ['#markup' => $this->t('The configuration objects have different language codes so they cannot be translated:')],
+        'items' => [
+          '#theme' => 'item_list',
+          '#items' => $items,
+        ],
+      ];
+      drupal_set_message($message, 'warning');
+
+      return;
+    }
+
+    // We create a fake request object to pass into
+    // ConfigMapperInterface::populateFromRouteMatch() for the different languages.
+    // Creating a separate request for each language and route is neither easily
+    // possible nor performant.
+    $fake_request = \Drupal::request()->duplicate();
+
+    $current_lang = $lang_manager->getLanguage($current_lang);
+
+    // This is needed because
+    // ConfigMapperInterface::getAddRouteParameters(), for example,
+    // needs to return the correct language code for each table row.
+    $fake_route_match = RouteMatch::createFromRequest($fake_request);
+
+    $viewing_translation = FALSE;
+    $query = \Drupal::destination()->getAsArray();
+    if ($mapper->hasTranslation($current_lang)) {
+      $viewing_translation = TRUE;
+
+
+      $form['translation_edit'] = [
+        '#type' => 'link',
+        '#title' => $this->t('This page is currently using the @lang translation.', ['@lang' => $current_lang->getName()]),
+        '#url' => Url::fromRoute($mapper->getEditRouteName(), $mapper->getEditRouteParameters(), ['query' => $query]),
+        '#attributes' => $this->getOffCanvasAttributes(),
+      ];
+      $form['translation_edit']['#weight'] = -1200;
+      $form['translation_form'] = \Drupal::formBuilder()->getForm('\Drupal\config_translation\Form\ConfigTranslationEditForm', $fake_route_match, $mapper->getPluginId(), $current_lang->getId());
+      $form['translation_form']['#weight'] = -1000;
+      unset($form['translation_form']['actions']);
+    }
+
+    $language_rows = [];
+    foreach ($languages as $language) {
+      $langcode = $language->getId();
+      if ($langcode == $current_lang->getId() && $viewing_translation) {
+        continue;
+      }
+
+
+      $mapper->populateFromRouteMatch($fake_route_match);
+      $mapper->setLangcode($langcode);
+
+      // Prepare the language name and the operations depending on whether this
+      // is the original language or not.
+      if ($langcode !== $original_langcode) {
+        $language_name = $language->getName();
+
+        $operations = [];
+        // If no translation exists for this language, link to add one.
+        if (!$mapper->hasTranslation($language)) {
+          $operations['add'] = [
+            'title' => $this->t('Add'),
+            'url' => Url::fromRoute($mapper->getAddRouteName(), $mapper->getAddRouteParameters(), ['query' => $query]),
+            'attributes' => $this->getOffCanvasAttributes(),
+          ];
+        }
+        else {
+          // Otherwise, link to edit the existing translation.
+          $operations['edit'] = [
+            'title' => $this->t('Edit'),
+            'url' => Url::fromRoute($mapper->getEditRouteName(), $mapper->getEditRouteParameters(), ['query' => $query]),
+            'attributes' => $this->getOffCanvasAttributes(),
+          ];
+
+          $operations['delete'] = [
+            'title' => $this->t('Delete'),
+            'url' => Url::fromRoute($mapper->getDeleteRouteName(), $mapper->getDeleteRouteParameters(), ['query' => $query]),
+            'attributes' => $this->getOffCanvasAttributes(),
+          ];
+        }
+        $language_rows[$langcode]['language'] = [
+          '#markup' => $language_name,
+        ];
+
+        $language_rows[$langcode]['operations'] = [
+          '#type' => 'operations',
+          '#links' => $operations,
+          // Even if the mapper contains multiple language codes, the source
+          // configuration can still be edited.
+          '#access' => ($langcode == $original_langcode) || $operations_access,
+        ];
+      }
+
+
+    }
+    if ($language_rows) {
+
+      $form['languages_details'] = [
+        '#type' => 'details',
+        '#title' => $viewing_translation ? $this->t('Other Translations'): $this->t('Translations'),
+        '#open' => FALSE    ,
+      ];
+
+      $form['languages_details']['languages'] = [
+        '#type' => 'table',
+        '#header' => [$this->t('Language'), $this->t('Operations')],
+      ] + $language_rows;
+    }
+  }
+
+  /**
+   * Get the translation config mapper for the block
+   *
+   * @param $current_lang
+   * @return \Drupal\config_translation\ConfigEntityMapper
+   */
+  protected function getConfigEntityMapper($current_lang) {
+    /** @var \Drupal\config_translation\ConfigEntityMapper $mapper */
+    $mapper = \Drupal::service('plugin.manager.config_translation.mapper')
+      ->createInstance('block');
+    $mapper->setLangcode($current_lang);
+    $mapper->setEntity($this->entity);
+    return $mapper;
+  }
+
+  /**
+   * Get attributes for off-canvas links.
+   *
+   * @todo Move this in a utility class so .module file can use it.
+   *
+   * @return array
+   *   The attributes.
+   */
+  protected function getOffCanvasAttributes() {
+    return [
+      'class' => ['use-ajax'],
+      'data-dialog-type' => 'dialog',
+      'data-dialog-renderer' => 'off_canvas',
+    ];
+  }
+
 }
