diff --git a/core/modules/layout_builder/layout_builder.links.contextual.yml b/core/modules/layout_builder/layout_builder.links.contextual.yml
index bcf2a9cf06..4cff0d197b 100644
--- a/core/modules/layout_builder/layout_builder.links.contextual.yml
+++ b/core/modules/layout_builder/layout_builder.links.contextual.yml
@@ -17,3 +17,14 @@ layout_builder_block_remove:
       class: ['use-ajax']
       data-dialog-type: dialog
       data-dialog-renderer: off_canvas
+
+layout_builder_block_translate:
+  title: 'Translate block'
+  route_name: 'layout_builder.translate_block'
+  group: 'layout_builder_block_translation'
+  options:
+    attributes:
+      class: ['use-ajax']
+      data-dialog-type: dialog
+      data-dialog-renderer: off_canvas
+
diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module
index 8d19c35bad..e3f2e13199 100644
--- a/core/modules/layout_builder/layout_builder.module
+++ b/core/modules/layout_builder/layout_builder.module
@@ -25,6 +25,7 @@
 use Drupal\layout_builder\InlineBlockEntityOperations;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Access\AccessResult;
+use Drupal\layout_builder\Form\BlockPluginTranslationForm;
 use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
 
 /**
@@ -313,3 +314,34 @@ function layout_builder_system_breadcrumb_alter(Breadcrumb &$breadcrumb, RouteMa
     $breadcrumb->addCacheableDependency($cacheability);
   }
 }
+
+/**
+ * Implements hook_entity_translation_create().
+ */
+function layout_builder_entity_translation_create(EntityInterface $translation) {
+  /** @var \Drupal\Core\Entity\FieldableEntityInterface $translation */
+  if ($translation->hasField(OverridesSectionStorage::FIELD_NAME)) {
+    $translatable_fields = $translation->getTranslatableFields();
+    if (array_key_exists(OverridesSectionStorage::FIELD_NAME, $translatable_fields)) {
+      // When creating a new translation do not copy untranslated sections.
+      // Currently totally independent overrides per language are not supported.
+      $translation->set(OverridesSectionStorage::FIELD_NAME, []);
+    }
+  }
+}
+
+/**
+ * Implements hook_block_alter().
+ *
+ * Ensures every block plugin definition has an 'layout_builder_translation'
+ * form specified.
+ */
+function layout_builder_block_alter(&$definitions) {
+  foreach ($definitions as &$definition) {
+    // If a block plugin does not define its own 'layout_builder_translation'
+    // form use the one provided by this module.
+    if (!isset($definition['forms']['layout_builder_translation'])) {
+      $definition['forms']['layout_builder_translation'] = BlockPluginTranslationForm::class;
+    }
+  }
+}
diff --git a/core/modules/layout_builder/layout_builder.routing.yml b/core/modules/layout_builder/layout_builder.routing.yml
index b436055378..1cfb25e3fd 100644
--- a/core/modules/layout_builder/layout_builder.routing.yml
+++ b/core/modules/layout_builder/layout_builder.routing.yml
@@ -6,6 +6,7 @@ layout_builder.choose_section:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
@@ -19,6 +20,7 @@ layout_builder.add_section:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
@@ -36,6 +38,7 @@ layout_builder.configure_section:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
@@ -49,6 +52,7 @@ layout_builder.remove_section:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
@@ -63,6 +67,7 @@ layout_builder.choose_block:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
@@ -77,6 +82,7 @@ layout_builder.add_block:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
@@ -90,6 +96,7 @@ layout_builder.choose_inline_block:
     _title: 'Add a new Inline Block'
   requirements:
     _permission: 'configure any layout'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
@@ -104,6 +111,22 @@ layout_builder.update_block:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
+  options:
+    _admin_route: TRUE
+    parameters:
+      section_storage:
+        layout_builder_tempstore: TRUE
+
+layout_builder.translate_block:
+  path: '/layout_builder/translate/block/{section_storage_type}/{section_storage}/{delta}/{region}/{uuid}'
+  defaults:
+    _form: '\Drupal\layout_builder\Form\TranslateBlockForm'
+    _title: 'Translate block'
+  requirements:
+    _permission: 'configure any layout'
+    _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'translated'
   options:
     _admin_route: TRUE
     parameters:
@@ -117,6 +140,7 @@ layout_builder.remove_block:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
@@ -136,6 +160,7 @@ layout_builder.move_block:
   requirements:
     _permission: 'configure any layout'
     _layout_builder_access: 'view'
+    _layout_builder_translation_access: 'untranslated'
   options:
     _admin_route: TRUE
     parameters:
diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml
index 65fb66a895..6f1f87571f 100644
--- a/core/modules/layout_builder/layout_builder.services.yml
+++ b/core/modules/layout_builder/layout_builder.services.yml
@@ -6,6 +6,10 @@ services:
     class: Drupal\layout_builder\Access\LayoutBuilderAccessCheck
     tags:
       - { name: access_check, applies_to: _layout_builder_access }
+  access_check.entity.layout_builder_translation_access:
+    class: Drupal\layout_builder\Access\LayoutBuilderTranslationAccessCheck
+    tags:
+      - { name: access_check, applies_to: _layout_builder_translation_access }
   access_check.entity.layout:
     class: Drupal\layout_builder\Access\LayoutSectionAccessCheck
     tags:
@@ -37,6 +41,10 @@ services:
     arguments: ['@current_user']
     tags:
       - { name: event_subscriber }
+  layout_builder.translate_block_component_subscriber:
+    class: Drupal\layout_builder\EventSubscriber\ComponentPluginLabelTranslate
+    tags:
+      - { name: event_subscriber }
   logger.channel.layout_builder:
     parent: logger.channel_base
     arguments: ['layout_builder']
diff --git a/core/modules/layout_builder/src/Access/LayoutBuilderTranslationAccessCheck.php b/core/modules/layout_builder/src/Access/LayoutBuilderTranslationAccessCheck.php
new file mode 100644
index 0000000000..f668220e73
--- /dev/null
+++ b/core/modules/layout_builder/src/Access/LayoutBuilderTranslationAccessCheck.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Drupal\layout_builder\Access;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
+use Drupal\Core\Routing\Access\AccessInterface;
+use Drupal\layout_builder\SectionStorageInterface;
+use Drupal\layout_builder\TranslatableSectionStorageInterface;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Provides an access check for the Layout Builder translations.
+ *
+ * When accessing the layout builder for a translation only translating labels
+ * and inline blocks are supported.
+ *
+ * @internal
+ */
+class LayoutBuilderTranslationAccessCheck implements AccessInterface {
+
+  /**
+   * Checks routing access to the default translation only layout.
+   *
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
+   * @param \Symfony\Component\Routing\Route $route
+   *   The route to check against.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  public function access(SectionStorageInterface $section_storage, Route $route) {
+    $translation_type = $route->getRequirement('_layout_builder_translation_access');
+    if ($translation_type === 'untranslated') {
+      $access = AccessResult::allowedIf(!$section_storage instanceof TranslatableSectionStorageInterface || $section_storage->isDefaultTranslation());
+    }
+    elseif ($translation_type === 'translated') {
+      $access = AccessResult::allowedIf($section_storage instanceof TranslatableSectionStorageInterface && !$section_storage->isDefaultTranslation());
+    }
+    else {
+      throw new \UnexpectedValueException("Unexpected _layout_builder_translation_access route requirement: $translation_type");
+    }
+    if ($access instanceof RefinableCacheableDependencyInterface) {
+      $access->addCacheableDependency($section_storage);
+    }
+    return $access;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Element/LayoutBuilder.php b/core/modules/layout_builder/src/Element/LayoutBuilder.php
index c806bc47fa..2e3b021f62 100644
--- a/core/modules/layout_builder/src/Element/LayoutBuilder.php
+++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\layout_builder\Element;
 
+use Drupal\Component\Plugin\ConfigurableInterface;
 use Drupal\Core\Ajax\AjaxHelperTrait;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
@@ -12,7 +13,9 @@
 use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\OverridesSectionStorageInterface;
+use Drupal\layout_builder\SectionComponent;
 use Drupal\layout_builder\SectionStorageInterface;
+use Drupal\layout_builder\TranslatableSectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -105,6 +108,7 @@ public function preRender($element) {
    */
   protected function layout(SectionStorageInterface $section_storage) {
     $this->prepareLayout($section_storage);
+    $sections_editable = !($section_storage instanceof TranslatableSectionStorageInterface && !$section_storage->isDefaultTranslation());
 
     $output = [];
     if ($this->isAjax()) {
@@ -114,17 +118,27 @@ protected function layout(SectionStorageInterface $section_storage) {
     }
     $count = 0;
     for ($i = 0; $i < $section_storage->count(); $i++) {
-      $output[] = $this->buildAddSectionLink($section_storage, $count);
+      if ($sections_editable) {
+        $output[] = $this->buildAddSectionLink($section_storage, $count);
+      }
+
       $output[] = $this->buildAdministrativeSection($section_storage, $count);
       $count++;
     }
-    $output[] = $this->buildAddSectionLink($section_storage, $count);
+    if ($sections_editable) {
+      $output[] = $this->buildAddSectionLink($section_storage, $count);
+    }
+
     $output['#attached']['library'][] = 'layout_builder/drupal.layout_builder';
     $output['#type'] = 'container';
     $output['#attributes']['id'] = 'layout-builder';
     $output['#attributes']['class'][] = 'layout-builder';
     // Mark this UI as uncacheable.
     $output['#cache']['max-age'] = 0;
+
+    // @todo Add message if not components have translate links!
+    //    "There are no settings to translate"
+
     return $output;
   }
 
@@ -138,6 +152,14 @@ protected function prepareLayout(SectionStorageInterface $section_storage) {
     // If the layout has pending changes, add a warning.
     if ($this->layoutTempstoreRepository->has($section_storage)) {
       $this->messenger->addWarning($this->t('You have unsaved changes.'));
+      if ($section_storage instanceof TranslatableSectionStorageInterface && !$section_storage->isDefaultTranslation()) {
+        // @todo Copy in any change from the default translation and then
+        //   reapply any translated labels where the original labels has not
+        //   changed. This should avoid data loss if the layout has been
+        //   updated since this layout override has started. This probably also
+        //   needs to be done on save to avoid overriding the layout if it was
+        //   saved since the last time this page was opened.
+      }
     }
     // If the layout is an override that has not yet been overridden, copy the
     // sections from the corresponding default.
@@ -231,7 +253,7 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
     $storage_type = $section_storage->getStorageType();
     $storage_id = $section_storage->getStorageId();
     $section = $section_storage->getSection($delta);
-
+    $sections_editable = !($section_storage instanceof TranslatableSectionStorageInterface && !$section_storage->isDefaultTranslation());
     $layout = $section->getLayout();
     $build = $section->toRenderArray($this->getAvailableContexts($section_storage), TRUE);
     $layout_definition = $layout->getPluginDefinition();
@@ -240,24 +262,36 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
     foreach ($layout_definition->getRegions() as $region => $info) {
       if (!empty($build[$region])) {
         foreach (Element::children($build[$region]) as $uuid) {
-          $build[$region][$uuid]['#attributes']['class'][] = 'draggable';
+          if ($sections_editable) {
+            $build[$region][$uuid]['#attributes']['class'][] = 'draggable';
+          }
+
           $build[$region][$uuid]['#attributes']['data-layout-block-uuid'] = $uuid;
-          $build[$region][$uuid]['#contextual_links'] = [
-            'layout_builder_block' => [
-              'route_parameters' => [
-                'section_storage_type' => $storage_type,
-                'section_storage' => $storage_id,
-                'delta' => $delta,
-                'region' => $region,
-                'uuid' => $uuid,
-              ],
+          $contextual_link_settings = [
+            'route_parameters' => [
+              'section_storage_type' => $storage_type,
+              'section_storage' => $storage_id,
+              'delta' => $delta,
+              'region' => $region,
+              'uuid' => $uuid,
             ],
           ];
+          if ($sections_editable) {
+            $build[$region][$uuid]['#contextual_links'] = [
+              'layout_builder_block' => $contextual_link_settings,
+            ];
+          }
+          elseif ($this->defaultComponentHasTranslatableSettings($section_storage, $component = $section->getComponent($uuid))) {
+            $build[$region][$uuid]['#contextual_links'] = [
+              'layout_builder_block_translation' => $contextual_link_settings,
+            ];
+          }
         }
       }
 
       $build[$region]['layout_builder_add_block']['link'] = [
         '#type' => 'link',
+        '#access' => $sections_editable,
         // Add one to the current delta since it is zero-indexed.
         '#title' => $this->t('Add Block <span class="visually-hidden">in section @section, @region region</span>', ['@section' => $delta + 1, '@region' => $region_labels[$region]]),
         '#url' => Url::fromRoute('layout_builder.choose_block',
@@ -301,6 +335,7 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
       ],
       'remove' => [
         '#type' => 'link',
+        '#access' => $sections_editable,
         '#title' => $this->t('Remove section <span class="visually-hidden">@section</span>', ['@section' => $delta + 1]),
         '#url' => Url::fromRoute('layout_builder.remove_section', [
           'section_storage_type' => $storage_type,
@@ -320,7 +355,7 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
       'configure' => [
         '#type' => 'link',
         '#title' => $this->t('Configure section'),
-        '#access' => $layout instanceof PluginFormInterface,
+        '#access' => $layout instanceof PluginFormInterface && $sections_editable,
         '#url' => Url::fromRoute('layout_builder.configure_section', [
           'section_storage_type' => $storage_type,
           'section_storage' => $storage_id,
@@ -340,4 +375,33 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s
     ];
   }
 
+  /**
+   * Determines if the component in the default translation is translatable.
+   *
+   * @todo determine how handle other settings that need to be translated
+   *    such as the inline blocks use case.
+   *
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
+   * @param \Drupal\layout_builder\SectionComponent $component
+   *   The component to check.
+   *
+   * @return bool
+   *   TRUE if the default component has translatable settings, otherwise FALSE.
+   */
+  protected function defaultComponentHasTranslatableSettings(SectionStorageInterface $section_storage, SectionComponent $component) {
+    if ($section_storage instanceof TranslatableSectionStorageInterface && !$section_storage->isDefaultTranslation()) {
+      foreach ($section_storage->getDefaultTranslationSections() as $default_translation_section) {
+        if ($default_component = $default_translation_section->getComponent($component->getUuid())) {
+          $plugin = $default_component->getPlugin();
+          if ($plugin instanceof ConfigurableInterface) {
+            $configuration = $plugin->getConfiguration();
+            return !empty($configuration['label_display']) && !empty($configuration['label']);
+          }
+        }
+      }
+    }
+    return FALSE;
+  }
+
 }
diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
index 8843f8fe57..c7ecf6d844 100644
--- a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
+++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
@@ -201,6 +201,7 @@ protected function addSectionField($entity_type_id, $bundle, $field_name) {
           'type' => 'layout_section',
           'locked' => TRUE,
         ]);
+        $field_storage->setTranslatable(FALSE);
         $field_storage->save();
       }
 
diff --git a/core/modules/layout_builder/src/EventSubscriber/ComponentPluginLabelTranslate.php b/core/modules/layout_builder/src/EventSubscriber/ComponentPluginLabelTranslate.php
new file mode 100644
index 0000000000..fd489458ef
--- /dev/null
+++ b/core/modules/layout_builder/src/EventSubscriber/ComponentPluginLabelTranslate.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Drupal\layout_builder\EventSubscriber;
+
+use Drupal\Component\Plugin\ConfigurableInterface;
+use Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent;
+use Drupal\layout_builder\LayoutBuilderEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Translates the plugin label if set in the plugin configuration.
+ */
+class ComponentPluginLabelTranslate implements EventSubscriberInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[LayoutBuilderEvents::SECTION_COMPONENT_BUILD_RENDER_ARRAY] = ['onBuildRender', 200];
+    return $events;
+  }
+
+  /**
+   * Translates the plugin label if set.
+   *
+   * @param \Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent $event
+   *   The section component render event.
+   */
+  public function onBuildRender(SectionComponentBuildRenderArrayEvent $event) {
+    $plugin = $event->getPlugin();
+    $contexts = $event->getContexts();
+    if (!$plugin instanceof ConfigurableInterface && !isset($contexts['layout_builder.entity'])) {
+      return;
+    }
+
+    /** @var \Drupal\Core\Entity\EntityInterface $entity */
+    $entity = $contexts['layout_builder.entity']->getContextValue();
+    $langcode = $entity->language()->getId();
+    $configuration = $plugin->getConfiguration();
+    if (isset($configuration['label']) && isset($configuration['layout_builder_translations'][$langcode]['label'])) {
+      $configuration['label'] = $configuration['layout_builder_translations'][$langcode]['label'];
+      $plugin->setConfiguration($configuration);
+    }
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Form/BlockPluginTranslationForm.php b/core/modules/layout_builder/src/Form/BlockPluginTranslationForm.php
new file mode 100644
index 0000000000..63f1456fbb
--- /dev/null
+++ b/core/modules/layout_builder/src/Form/BlockPluginTranslationForm.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Drupal\layout_builder\Form;
+
+use Drupal\Component\Plugin\ConfigurableInterface;
+use Drupal\Component\Plugin\ContextAwarePluginInterface;
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
+use Drupal\Core\Plugin\PluginFormBase;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a block plugin form for translatable settings in the Layout Builder.
+ */
+class BlockPluginTranslationForm extends PluginFormBase implements ContainerInjectionInterface {
+
+  use StringTranslationTrait;
+  use ContextAwarePluginAssignmentTrait;
+
+  /**
+   * The current language code.
+   *
+   * @var string
+   */
+  protected $currentLangcode;
+
+  /**
+   * BlockPluginTranslationForm constructor.
+   *
+   * @param string $current_langcode
+   *   The current language code.
+   */
+  public function __construct($current_langcode) {
+    $this->currentLangcode = $current_langcode;
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('language_manager')->getCurrentLanguage()->getId()
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    if ($this->plugin instanceof ConfigurableInterface) {
+      $configuration = $this->plugin->getConfiguration();
+      $form['translated_label'] = [
+        '#title' => $this->t('Label'),
+        '#type' => 'textfield',
+        '#default_value' => isset($configuration['layout_builder_translations'][$this->currentLangcode]['label']) ? $configuration['layout_builder_translations'][$this->currentLangcode]['label'] : $configuration['label'],
+        '#required' => TRUE,
+      ];
+      if ($this->plugin instanceof ContextAwarePluginInterface) {
+        $form['context_mapping'] = $this->addContextAssignmentElement($this->plugin, $this->plugin->getContexts());
+      }
+    }
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
+    if ($this->plugin instanceof ConfigurableInterface) {
+      $configuration = $this->plugin->getConfiguration();
+      $configuration['layout_builder_translations'][$this->currentLangcode]['label'] = $form_state->getValue('translated_label');
+      $this->plugin->setConfiguration($configuration);
+    }
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Form/TranslateBlockForm.php b/core/modules/layout_builder/src/Form/TranslateBlockForm.php
new file mode 100644
index 0000000000..7123f768b9
--- /dev/null
+++ b/core/modules/layout_builder/src/Form/TranslateBlockForm.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\layout_builder\Form;
+
+use Drupal\Core\Block\BlockPluginInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\SubformState;
+use Drupal\Core\Plugin\PluginWithFormsInterface;
+use Drupal\layout_builder\SectionStorageInterface;
+
+/**
+ * Provides a form to translate a block in the Layout Builder.
+ */
+class TranslateBlockForm extends ConfigureBlockFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function submitLabel() {
+    return $this->t('Translate');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'layout_builder_block_translation';
+  }
+
+  /**
+   * Builds the block form.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage being configured.
+   * @param int $delta
+   *   The delta of the section.
+   * @param string $region
+   *   The region of the block.
+   * @param string $uuid
+   *   The UUID of the block being updated.
+   *
+   * @return array
+   *   The form array.
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL, $delta = NULL, $region = NULL, $uuid = NULL) {
+    $component = $section_storage->getSection($delta)->getComponent($uuid);
+    return $this->doBuildForm($form, $form_state, $section_storage, $delta, $component);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getPluginForm(BlockPluginInterface $block) {
+    if ($block instanceof PluginWithFormsInterface) {
+      return $this->pluginFormFactory->createInstance($block, 'layout_builder_translation');
+    }
+    return $block;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    parent::validateForm($form, $form_state);
+    $subform_state = SubformState::createForSubform($form['settings'], $form, $form_state);
+    if ($subform_state->hasValue('context_mapping')) {
+      $mapping = $subform_state->getValue('context_mapping');
+      // @todo(in this issue) Should really have to switch the context mapping here?
+      if (isset($mapping['entity']) && $mapping['entity'] === 'entity') {
+        $mapping['entity'] = 'layout_builder.entity';
+      }
+      $subform_state->setValue('context_mapping', $mapping);
+    }
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
index fa440b300d..e8520bf968 100644
--- a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
@@ -19,6 +19,7 @@
 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
 use Drupal\layout_builder\OverridesSectionStorageInterface;
 use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
+use Drupal\layout_builder\TranslatableSectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -47,7 +48,7 @@
  *   experimental modules and development releases of contributed modules.
  *   See https://www.drupal.org/core/experimental for more information.
  */
-class OverridesSectionStorage extends SectionStorageBase implements ContainerFactoryPluginInterface, OverridesSectionStorageInterface, SectionStorageLocalTaskProviderInterface {
+class OverridesSectionStorage extends SectionStorageBase implements ContainerFactoryPluginInterface, OverridesSectionStorageInterface, TranslatableSectionStorageInterface, SectionStorageLocalTaskProviderInterface {
 
   /**
    * The field name used by this storage.
@@ -174,7 +175,7 @@ public function extractIdFromRoute($value, $definition, $name, array $defaults)
   public function getSectionListFromId($id) {
     @trigger_error('\Drupal\layout_builder\SectionStorageInterface::getSectionListFromId() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. The section list should be derived from context. See https://www.drupal.org/node/3016262.', E_USER_DEPRECATED);
     if (strpos($id, '.') !== FALSE) {
-      list($entity_type_id, $entity_id) = explode('.', $id, 2);
+      list($entity_type_id, $entity_id) = explode('.', $id);
       $entity = $this->entityRepository->getActive($entity_type_id, $entity_id);
       if ($entity instanceof FieldableEntityInterface && $entity->hasField(static::FIELD_NAME)) {
         return $entity->get(static::FIELD_NAME);
@@ -218,7 +219,7 @@ public function deriveContextsFromRoute($value, $definition, $name, array $defau
    */
   private function extractEntityFromRoute($value, array $defaults) {
     if (strpos($value, '.') !== FALSE) {
-      list($entity_type_id, $entity_id) = explode('.', $value, 2);
+      list($entity_type_id, $entity_id) = explode('.', $value);
     }
     elseif (isset($defaults['entity_type_id']) && !empty($defaults[$defaults['entity_type_id']])) {
       $entity_type_id = $defaults['entity_type_id'];
@@ -362,6 +363,7 @@ public function save() {
   public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
     $default_section_storage = $this->getDefaultSectionStorage();
     $result = AccessResult::allowedIf($default_section_storage->isLayoutBuilderEnabled())->addCacheableDependency($default_section_storage);
+    $result = $result->andIf(AccessResult::allowedIf($this->isDefaultTranslation() || $this->isOverridden()))->addCacheableDependency($this);
     return $return_as_object ? $result : $result->isAllowed();
   }
 
@@ -385,4 +387,42 @@ public function isOverridden() {
     return !empty($this->getSections());
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function isTranslatable() {
+    $entity = $this->getEntity();
+    if ($entity instanceof TranslatableInterface) {
+      return $entity->isTranslatable();
+      /*$translatable_fields = $entity->getTranslatableFields(FALSE);
+      return array_key_exists(static::FIELD_NAME, $translatable_fields) && $entity->isTranslatable();*/
+    }
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isDefaultTranslation() {
+    if ($this->isTranslatable()) {
+      /** @var \Drupal\Core\Entity\TranslatableInterface $entity */
+      $entity = $this->getEntity();
+      return $entity->isDefaultTranslation();
+    }
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultTranslationSections() {
+    if ($this->isTranslatable()) {
+      /** @var \Drupal\Core\Entity\TranslatableInterface $entity */
+      $entity = $this->getEntity();
+      $untranslated_entity = $entity->getUntranslated();
+      return $untranslated_entity->get(static::FIELD_NAME)->getSections();
+    }
+    return [];
+  }
+
 }
diff --git a/core/modules/layout_builder/src/TranslatableSectionStorageInterface.php b/core/modules/layout_builder/src/TranslatableSectionStorageInterface.php
new file mode 100644
index 0000000000..d9326afe53
--- /dev/null
+++ b/core/modules/layout_builder/src/TranslatableSectionStorageInterface.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\layout_builder;
+
+/**
+ * Defines an interface for translatable section overrides.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+interface TranslatableSectionStorageInterface {
+
+  /**
+   * Indicates if the layout is translatable.
+   *
+   * @return bool
+   *   TRUE if the layout is translatable, otherwise FALSE.
+   */
+  public function isTranslatable();
+
+  /**
+   * Indicates if the layout is default translation layout.
+   *
+   * @return bool
+   *   TRUE if the layout is the default translation layout, otherwise FALSE.
+   */
+  public function isDefaultTranslation();
+
+  /**
+   * Gets the layout default translation sections.
+   *
+   * @return \Drupal\layout_builder\Section[]
+   *   A sequentially and numerically keyed array of section objects.
+   */
+  public function getDefaultTranslationSections();
+
+}
diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderMultilingualTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderMultilingualTest.php
index 683d6012df..211e082fa4 100644
--- a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderMultilingualTest.php
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderMultilingualTest.php
@@ -21,7 +21,7 @@ class LayoutBuilderMultilingualTest extends BrowserTestBase {
     'layout_builder',
     'node',
     'block_content',
-    'content_translation',
+    'language',
     'locale',
   ];
 
@@ -50,7 +50,7 @@ protected function setUp() {
     $this->createContentType([
       'type' => 'bundle_with_section_field',
     ]);
-    $this->container->get('content_translation.manager')->setEnabled('node', 'bundle_with_section_field', TRUE);
+
     LayoutBuilderEntityViewDisplay::load('node.bundle_with_section_field.default')
       ->enableLayoutBuilder()
       ->setOverridable()
@@ -60,14 +60,21 @@ protected function setUp() {
     ConfigurableLanguage::createFromLangcode('es')->save();
 
     // Create a node and translate it.
-    $node = $this->createNode([
+    $en_node = $this->createNode([
       'type' => 'bundle_with_section_field',
       'title' => 'The untranslated node title',
     ]);
-    $node->addTranslation('es', [
-      'title' => 'The translated node title',
+    $en_node->save();
+
+    // Create a second node in Spanish to confirm the UI works in another
+    // language. We cannot use a translation for this because layout
+    // translations do not have the full UI.
+    $es_node = $this->createNode([
+      'type' => 'bundle_with_section_field',
+      'title' => 'The untranslated node title',
+      'langcode' => 'es',
     ]);
-    $node->save();
+    $es_node->save();
 
     $this->drupalLogin($this->createUser([
       'configure any layout',
@@ -81,7 +88,7 @@ protected function setUp() {
   public function testCustomBlocks() {
     // Check translated and untranslated entities before translating the string.
     $this->assertCustomBlocks('node/1');
-    $this->assertCustomBlocks('es/node/1');
+    $this->assertCustomBlocks('es/node/2');
 
     // Translate the 'Inline blocks' string used as a category in
     // \Drupal\layout_builder\Controller\ChooseBlockController::inlineBlockList().
@@ -90,7 +97,7 @@ public function testCustomBlocks() {
 
     // Check translated and untranslated entities after translating the string.
     $this->assertCustomBlocks('node/1');
-    $this->assertCustomBlocks('es/node/1');
+    $this->assertCustomBlocks('es/node/2');
   }
 
   /**
diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTranslationTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTranslationTest.php
new file mode 100644
index 0000000000..3d9a18279e
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTranslationTest.php
@@ -0,0 +1,218 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Functional;
+
+use Drupal\Tests\content_translation\Functional\ContentTranslationTestBase;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\Core\Url;
+
+/**
+ * Tests that the Layout Builder UI works with translated content.
+ *
+ * @group layout_builder
+ */
+class LayoutBuilderTranslationTest extends ContentTranslationTestBase {
+
+  use TranslationTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'content_translation',
+    'contextual',
+    'entity_test',
+    'layout_builder',
+    'block',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->setUpViewDisplay();
+    $this->setUpEntities();
+  }
+
+  /**
+   * Tests that the Layout Builder UI works with translated content.
+   */
+  public function testLayoutPerTranslation() {
+    $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
+
+    $entity_url = $this->entity->toUrl('canonical')->toString();
+    $language = \Drupal::languageManager()->getLanguage($this->langcodes[2]);
+    $translated_entity_url = $this->entity->toUrl('canonical', ['language' => $language])->toString();
+    $layout_url = $entity_url . '/layout';
+    $translated_layout_url = $translated_entity_url . '/layout';
+
+    $this->drupalGet($entity_url);
+    $assert_session->pageTextNotContains('The translated field value');
+    $assert_session->pageTextContains('The untranslated field value');
+
+    $this->drupalGet($translated_entity_url);
+    $assert_session->pageTextNotContains('The untranslated field value');
+    $assert_session->pageTextContains('The translated field value');
+
+    $this->drupalGet($layout_url);
+    $assert_session->pageTextNotContains('The translated field value');
+    $assert_session->pageTextContains('The untranslated field value');
+
+    // If there is not a layout override the layout translation is not
+    // accessible.
+    $this->drupalGet($translated_layout_url);
+    $assert_session->pageTextContains('Access denied');
+
+    // Ensure that the tempstore varies per-translation.
+    $this->drupalGet($layout_url);
+    $assert_session->pageTextNotContains('The translated field value');
+    $assert_session->pageTextContains('The untranslated field value');
+
+    // Adjust the layout of the original entity.
+    $assert_session->linkExists('Add Block');
+    $this->clickLink('Add Block');
+    $assert_session->linkExists('Powered by Drupal');
+    $this->clickLink('Powered by Drupal');
+    $page->pressButton('Add Block');
+
+    $assert_session->pageTextContains('Powered by Drupal');
+
+    // Confirm the tempstore for the translated layout is not affected.
+    $this->drupalGet($translated_layout_url);
+    $assert_session->pageTextContains('Access denied');
+
+    $this->drupalGet($layout_url);
+    $assert_session->pageTextContains('Powered by Drupal');
+    $assert_session->buttonExists('Save layout');
+    $page->pressButton('Save layout');
+
+    $this->drupalGet($entity_url);
+    $assert_session->pageTextNotContains('The translated field value');
+    $assert_session->pageTextContains('The untranslated field value');
+    $assert_session->pageTextContains('Powered by Drupal');
+
+    // Ensure that the layout change propagates to the translated entity.
+    $this->drupalGet($translated_entity_url);
+    $assert_session->pageTextNotContains('The untranslated field value');
+    $assert_session->pageTextContains('The translated field value');
+    $assert_session->pageTextContains('Powered by Drupal');
+
+    // Confirm that layout translation page is accessible once the untranslated
+    // entity has a override.
+    $this->drupalGet($translated_layout_url);
+    $assert_session->pageTextNotContains('Access denied');
+    $assert_session->pageTextNotContains('The untranslated field value');
+    $assert_session->pageTextContains('The translated field value');
+    $assert_session->pageTextContains('Powered by Drupal');
+    $assert_session->buttonExists('Save layout');
+
+    $this->assertNonTranslationActionsRemoved();
+
+  }
+
+
+  /**
+   * Tests that access is denied to a layout translation if there is override.
+   */
+  public function testLayoutTranslationNoOverride() {
+    $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
+
+    $entity_url = $this->entity->toUrl('canonical')->toString();
+    $language = \Drupal::languageManager()->getLanguage($this->langcodes[2]);
+    $translated_entity_url = $this->entity->toUrl('canonical', ['language' => $language])->toString();
+    $layout_url = $entity_url . '/layout';
+    $translated_layout_url = $translated_entity_url . '/layout';
+
+    $this->drupalGet($entity_url);
+    $assert_session->pageTextNotContains('The translated field value');
+    $assert_session->pageTextContains('The untranslated field value');
+
+    $this->drupalGet($translated_entity_url);
+    $assert_session->pageTextNotContains('The untranslated field value');
+    $assert_session->pageTextContains('The translated field value');
+
+    // If there is not a layout override the layout translation is not
+    // accessible.
+    $this->drupalGet($translated_layout_url);
+    $assert_session->pageTextContains('Access denied');
+  }
+
+  /**
+   * The entity used for testing.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface
+   */
+  protected $entity;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getAdministratorPermissions() {
+    $permissions = parent::getAdministratorPermissions();
+    $permissions[] = 'administer entity_test_mul display';
+    return $permissions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getTranslatorPermissions() {
+    $permissions = parent::getTranslatorPermissions();
+    $permissions[] = 'view test entity translations';
+    $permissions[] = 'view test entity';
+    $permissions[] = 'configure any layout';
+    return $permissions;
+  }
+
+  /**
+   * Setup translated entity with layouts.
+   */
+  protected function setUpEntities() {
+    $this->drupalLogin($this->administrator);
+
+    $field_ui_prefix = 'entity_test_mul/structure/entity_test_mul';
+    // Allow overrides for the layout.
+    $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[enabled]' => TRUE], 'Save');
+    $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => TRUE], 'Save');
+
+    // @todo The Layout Builder UI relies on local tasks; fix in
+    //   https://www.drupal.org/project/drupal/issues/2917777.
+    $this->drupalPlaceBlock('local_tasks_block');
+
+    // Create a test entity.
+    $id = $this->createEntity([
+      $this->fieldName => [['value' => 'The untranslated field value']],
+    ], $this->langcodes[0]);
+    $storage = $this->container->get('entity_type.manager')
+      ->getStorage($this->entityTypeId);
+    $storage->resetCache([$id]);
+    $this->entity = $storage->load($id);
+
+    // Create a translation.
+    $this->drupalLogin($this->translator);
+    $add_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_add", [
+      $this->entityTypeId => $this->entity->id(),
+      'source' => $this->langcodes[0],
+      'target' => $this->langcodes[2],
+    ]);
+    $this->drupalPostForm($add_translation_url, [
+      "{$this->fieldName}[0][value]" => 'The translated field value',
+    ], 'Save');
+  }
+
+  /**
+   * Set up the View Display.
+   */
+  protected function setUpViewDisplay() {
+    EntityViewDisplay::create([
+      'targetEntityType' => $this->entityTypeId,
+      'bundle' => $this->bundle,
+      'mode' => 'default',
+      'status' => TRUE,
+    ])->setComponent($this->fieldName, ['type' => 'string'])->save();
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
index 1041dd813e..e5b70c0b3f 100644
--- a/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
@@ -203,13 +203,12 @@ public function testLayoutSectionFormatterAccess() {
    * Tests the multilingual support of the section formatter.
    */
   public function testMultilingualLayoutSectionFormatter() {
-    $this->container->get('module_installer')->install(['content_translation']);
+    $this->container->get('module_installer')->install(['language']);
     $this->rebuildContainer();
 
     ConfigurableLanguage::createFromLangcode('es')->save();
-    $this->container->get('content_translation.manager')->setEnabled('node', 'bundle_with_section_field', TRUE);
 
-    $entity = $this->createSectionNode([
+    $en_entity = $this->createSectionNode([
       [
         'section' => new Section('layout_onecol', [], [
           'baz' => new SectionComponent('baz', 'content', [
@@ -218,28 +217,27 @@ public function testMultilingualLayoutSectionFormatter() {
         ]),
       ],
     ]);
-    $entity->addTranslation('es', [
-      'title' => 'Translated node title',
-      OverridesSectionStorage::FIELD_NAME => [
-        [
-          'section' => new Section('layout_twocol', [], [
-            'foo' => new SectionComponent('foo', 'first', [
-              'id' => 'test_block_instantiation',
-              'display_message' => 'foo text',
-            ]),
-            'bar' => new SectionComponent('bar', 'second', [
-              'id' => 'test_block_instantiation',
-              'display_message' => 'bar text',
-            ]),
+
+    $es_entity = $this->createSectionNode([
+      [
+        'section' => new Section('layout_twocol', [], [
+          'foo' => new SectionComponent('foo', 'first', [
+            'id' => 'test_block_instantiation',
+            'display_message' => 'foo text',
           ]),
-        ],
+          'bar' => new SectionComponent('bar', 'second', [
+            'id' => 'test_block_instantiation',
+            'display_message' => 'bar text',
+          ]),
+        ]),
       ],
     ]);
-    $entity->save();
+    $es_entity->set('langcode', 'es');
+    $es_entity->save();
 
-    $this->drupalGet($entity->toUrl('canonical'));
+    $this->drupalGet($en_entity->toUrl('canonical'));
     $this->assertLayoutSection('.layout--onecol', 'Powered by');
-    $this->drupalGet($entity->toUrl('canonical')->setOption('prefix', 'es/'));
+    $this->drupalGet($es_entity->toUrl('canonical'));
     $this->assertLayoutSection('.layout--twocol', ['foo text', 'bar text']);
   }
 
diff --git a/core/modules/layout_builder/tests/src/Functional/TranslationTestTrait.php b/core/modules/layout_builder/tests/src/Functional/TranslationTestTrait.php
new file mode 100644
index 0000000000..dec7e6a2b0
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Functional/TranslationTestTrait.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Functional;
+
+/**
+ * Common functions for testing Layout Builder with translations.
+ */
+trait TranslationTestTrait {
+
+  /**
+   * @param \Drupal\Tests\WebAssert $assert_session
+   *
+   * @throws \Behat\Mink\Exception\ExpectationException
+   */
+  protected function assertNonTranslationActionsRemoved() {
+    $assert_session = $this->assertSession();
+    // Confirm that links do not exist to change the layout.
+    $assert_session->linkNotExists('Add Section');
+    $assert_session->linkNotExists('Add Block');
+    $assert_session->linkNotExists('Remove section');
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderDisableInteractionsTest.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderDisableInteractionsTest.php
index e4b342ba86..1b55d8af7e 100644
--- a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderDisableInteractionsTest.php
+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderDisableInteractionsTest.php
@@ -18,6 +18,7 @@
 class LayoutBuilderDisableInteractionsTest extends WebDriverTestBase {
 
   use ContextualLinkClickTrait;
+  use LayoutBuilderTestTrait;
 
   /**
    * {@inheritdoc}
@@ -133,36 +134,6 @@ public function testFormsLinksDisabled() {
     $this->assertContextualLinksClickable();
   }
 
-  /**
-   * Adds a block in the Layout Builder.
-   *
-   * @param string $block_link_text
-   *   The link text to add the block.
-   * @param string $rendered_locator
-   *   The CSS locator to confirm the block was rendered.
-   */
-  protected function addBlock($block_link_text, $rendered_locator) {
-    $assert_session = $this->assertSession();
-    $page = $this->getSession()->getPage();
-
-    // Add a new block.
-    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#layout-builder a:contains(\'Add Block\')'));
-    $this->clickLink('Add Block');
-    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas'));
-    $assert_session->assertWaitOnAjaxRequest();
-
-    $assert_session->linkExists($block_link_text);
-    $this->clickLink($block_link_text);
-
-    // Wait for off-canvas dialog to reopen with block form.
-    $this->assertNotEmpty($assert_session->waitForElementVisible('css', ".layout-builder-add-block"));
-    $assert_session->assertWaitOnAjaxRequest();
-    $page->pressButton('Add Block');
-
-    // Wait for block form to be rendered in the Layout Builder.
-    $this->assertNotEmpty($assert_session->waitForElement('css', $rendered_locator));
-  }
-
   /**
    * Checks if element is unclickable.
    *
@@ -275,26 +246,4 @@ protected function movePointerTo($selector) {
     $driver_session->moveto(['element' => $element->getID()]);
   }
 
-  /**
-   * Waits for an element to be removed from the page.
-   *
-   * @param string $selector
-   *   CSS selector.
-   * @param int $timeout
-   *   (optional) Timeout in milliseconds, defaults to 10000.
-   * @param string $message
-   *   (optional) Custom message to display with the assertion.
-   *
-   * @todo: Remove after https://www.drupal.org/project/drupal/issues/2892440
-   */
-  public function assertNoElementAfterWait($selector, $timeout = 10000, $message = '') {
-    $page = $this->getSession()->getPage();
-    if ($message === '') {
-      $message = "Element '$selector' was not on the page after wait.";
-    }
-    $this->assertTrue($page->waitFor($timeout / 1000, function () use ($page, $selector) {
-      return empty($page->find('css', $selector));
-    }), $message);
-  }
-
 }
diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderTestTrait.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderTestTrait.php
new file mode 100644
index 0000000000..763d7b3ea8
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderTestTrait.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\FunctionalJavascript;
+
+/**
+ * Common functions for testing Layout Builder.
+ */
+trait LayoutBuilderTestTrait {
+
+  /**
+   * Adds a block in the Layout Builder.
+   *
+   * @param string $block_link_text
+   *   The link text to add the block.
+   * @param string $rendered_locator
+   *   The CSS locator to confirm the block was rendered.
+   * @param bool $label_display
+   *   Whether the label should be displayed.
+   * @param string|null $label
+   *   The label use.
+   */
+  protected function addBlock($block_link_text, $rendered_locator, $label_display = FALSE, $label = NULL) {
+    $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
+
+    // Add a new block.
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#layout-builder a:contains(\'Add Block\')'));
+    $this->clickLink('Add Block');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas'));
+    $assert_session->assertWaitOnAjaxRequest();
+
+    $assert_session->linkExists($block_link_text);
+    $this->clickLink($block_link_text);
+
+    // Wait for off-canvas dialog to reopen with block form.
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', ".layout-builder-add-block"));
+    $assert_session->assertWaitOnAjaxRequest();
+    if ($label_display) {
+      $page->checkField('settings[label_display]');
+    }
+    if ($label !== NULL) {
+      $page->fillField('settings[label]', $label);
+    }
+    $page->pressButton('Add Block');
+
+    // Wait for block form to be rendered in the Layout Builder.
+    $this->assertNotEmpty($assert_session->waitForElement('css', $rendered_locator));
+  }
+
+  /**
+   * Waits for an element to be removed from the page.
+   *
+   * @param string $selector
+   *   CSS selector.
+   * @param int $timeout
+   *   (optional) Timeout in milliseconds, defaults to 10000.
+   * @param string $message
+   *   (optional) Custom message to display with the assertion.
+   *
+   * @todo: Remove after https://www.drupal.org/project/drupal/issues/2892440
+   */
+  public function assertNoElementAfterWait($selector, $timeout = 10000, $message = '') {
+    $page = $this->getSession()->getPage();
+    if ($message === '') {
+      $message = "Element '$selector' was not on the page after wait.";
+    }
+    $this->assertTrue($page->waitFor($timeout / 1000, function () use ($page, $selector) {
+      return empty($page->find('css', $selector));
+    }), $message);
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/TranslationTest.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/TranslationTest.php
new file mode 100644
index 0000000000..e6af328005
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/TranslationTest.php
@@ -0,0 +1,164 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\FunctionalJavascript;
+
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\Core\Url;
+use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
+use Drupal\Tests\layout_builder\Functional\TranslationTestTrait;
+
+/**
+ * Tests that block settings can be translated.
+ *
+ * @group layout_builder
+ */
+class TranslationTest extends WebDriverTestBase {
+
+  use LayoutBuilderTestTrait;
+  use TranslationTestTrait;
+  use ContextualLinkClickTrait;
+
+  /**
+   * Path prefix for the field UI for the test bundle.
+   */
+  const FIELD_UI_PREFIX = 'admin/structure/types/manage/bundle_with_section_field';
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'content_translation',
+    'layout_builder',
+    'block',
+    'node',
+    'contextual',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // @todo The Layout Builder UI relies on local tasks; fix in
+    //   https://www.drupal.org/project/drupal/issues/2917777.
+    $this->drupalPlaceBlock('local_tasks_block');
+
+    $this->createContentType(['type' => 'bundle_with_section_field', 'new_revision' => TRUE]);
+    $this->createNode([
+      'type' => 'bundle_with_section_field',
+      'title' => 'The node title',
+      'body' => [
+        [
+          'value' => 'The node body',
+        ],
+      ],
+    ]);
+    // Adds a new language.
+    ConfigurableLanguage::createFromLangcode('it')->save();
+
+    // Enable translation for the node type 'bundle_with_section_field'.
+    \Drupal::service('content_translation.manager')->setEnabled('node', 'bundle_with_section_field', TRUE);
+  }
+
+  /**
+   * Tests that block labels can be translated.
+   */
+  public function testLabelTranslation() {
+    $page = $this->getSession()->getPage();
+    $assert_session = $this->assertSession();
+
+    $this->drupalLogin($this->drupalCreateUser([
+      'access contextual links',
+      'configure any layout',
+      'administer node display',
+      'administer node fields',
+      'translate bundle_with_section_field node',
+      'create content translations',
+    ]));
+
+    // Allow layout overrides.
+    $this->drupalPostForm(
+      static::FIELD_UI_PREFIX . '/display/default',
+      ['layout[enabled]' => TRUE],
+      'Save'
+    );
+    $this->drupalPostForm(
+      static::FIELD_UI_PREFIX . '/display/default',
+      ['layout[allow_custom]' => TRUE],
+      'Save'
+    );
+
+    // Add a new inline block to the original node.
+    $this->drupalGet('node/1/layout');
+
+    $this->clickContextualLink('.block-field-blocknodebundle-with-section-fieldbody', 'Configure');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas'));
+    $page->fillField('settings[label]', 'field label untranslated');
+    $page->checkField('settings[label_display]');
+    $page->pressButton('Update');
+    $assert_session->assertWaitOnAjaxRequest();
+    $this->assertNoElementAfterWait('#drupal-off-canvas');
+    $this->addBlock('Powered by Drupal', '.block-system-powered-by-block', TRUE, 'untranslated label');
+    $assert_session->pageTextContains('untranslated label');
+    $assert_session->buttonExists('Save layout');
+    $page->pressButton('Save layout');
+    $assert_session->addressEquals('node/1');
+
+    // Create a translation.
+    $add_translation_url = Url::fromRoute("entity.node.content_translation_add", [
+      'node' => 1,
+      'source' => 'en',
+      'target' => 'it',
+    ]);
+    $this->drupalPostForm($add_translation_url, [
+      'title[0][value]' => 'The translated node title',
+      'body[0][value]' => 'The translated node body',
+    ], 'Save');
+
+    // Update the translations block label.
+    $this->drupalGet('it/node/1/layout');
+    $this->assertNonTranslationActionsRemoved();
+    $this->updateBlockTranslation('.block-system-powered-by-block', 'untranslated label', 'label in translation');
+    // @todo this will fail until https://www.drupal.org/node/3039185
+    // $this->updateBlockTranslation('.block-field-blocknodebundle-with-section-fieldbody', 'field label untranslated', 'field label translated');
+    $assert_session->buttonExists('Save layout');
+    $page->pressButton('Save layout');
+    $assert_session->addressEquals('it/node/1');
+    $assert_session->pageTextContains('label in translation');
+    // @todo this will fail until https://www.drupal.org/node/3039185
+    // $assert_session->pageTextContains('field label translated');
+
+    // Confirm that untranslated label is still used on default translation.
+    $this->drupalGet('node/1');
+    $assert_session->pageTextContains('untranslated label');
+    $assert_session->pageTextNotContains('label in translation');
+    // @todo this will fail until https://www.drupal.org/node/3039185
+    // $assert_session->pageTextContains('field label translated');
+    // $assert_session->pageTextNotContains('field label untranslated');
+  }
+
+  /**
+   * Updates a block label translation.
+   *
+   * @param string $block_selector
+   *   The CSS selector for the block.
+   * @param string $expected_label
+   *   The label that is expected.
+   * @param string $new_label
+   *   The new label to set.
+   */
+  protected function updateBlockTranslation($block_selector, $expected_label, $new_label) {
+    $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
+    $this->clickContextualLink($block_selector, 'Translate block');
+    $label_input = $assert_session->waitForElementVisible('css', '#drupal-off-canvas [name="settings[translated_label]"]');
+    $this->assertNotEmpty($label_input);
+    $this->assertEquals($expected_label, $label_input->getValue());
+    $label_input->setValue($new_label);
+    $page->pressButton('Translate');
+    $this->assertNoElementAfterWait('#drupal-off-canvas');
+    $this->assertNotEmpty($assert_session->waitForElementVisible('css', "h2:contains(\"$new_label\")"));
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php b/core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php
index 94af274cbe..7658712dab 100644
--- a/core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php
+++ b/core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php
@@ -52,6 +52,7 @@ protected function setUp() {
     $this->setUpCurrentUser();
     $this->installSchema('system', ['key_value_expire']);
     $this->installEntitySchema('entity_test');
+    $this->installEntitySchema('user');
 
     $definition = $this->container->get('plugin.manager.layout_builder.section_storage')->getDefinition('overrides');
     $this->plugin = OverridesSectionStorage::create($this->container, [], 'overrides', $definition);
diff --git a/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
index 6f4b4783fd..4ff8a1a0a2 100644
--- a/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
@@ -171,6 +171,16 @@ public function providerTestGetSectionListFromId() {
       'my_entity_type',
       'my_entity_type.entity_without_layout',
     ];
+    $data['with value, with layout, fr'] = [
+      TRUE,
+      'my_entity_type',
+      'my_entity_type.entity_with_layout.fr',
+    ];
+    $data['with value, without layout, fr'] = [
+      FALSE,
+      'my_entity_type',
+      'my_entity_type.entity_without_layout.fr',
+    ];
     $data['empty value, empty defaults'] = [
       FALSE,
       NULL,
diff --git a/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php b/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php
index fcaf319368..1e995c58f7 100644
--- a/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php
+++ b/core/modules/system/tests/modules/twig_theme_test/src/TwigThemeTestController.php
@@ -104,11 +104,4 @@ public function renderable() {
     ];
   }
 
-  /**
-   * Renders for testing the embed tag in a Twig template.
-   */
-  public function embedTagRender() {
-    return ['#theme' => 'twig_theme_test_embed_tag'];
-  }
-
 }
diff --git a/core/modules/system/tests/modules/twig_theme_test/templates/twig-theme-test-embed-tag-embedded.html.twig b/core/modules/system/tests/modules/twig_theme_test/templates/twig-theme-test-embed-tag-embedded.html.twig
deleted file mode 100644
index 63d7f477cb..0000000000
--- a/core/modules/system/tests/modules/twig_theme_test/templates/twig-theme-test-embed-tag-embedded.html.twig
+++ /dev/null
@@ -1 +0,0 @@
-This line is from twig_theme_test/templates/twig-theme-test-embed-tag-embedded.html.twig
diff --git a/core/modules/system/tests/modules/twig_theme_test/templates/twig_theme_test.embed_tag.html.twig b/core/modules/system/tests/modules/twig_theme_test/templates/twig_theme_test.embed_tag.html.twig
deleted file mode 100644
index 035c3784e4..0000000000
--- a/core/modules/system/tests/modules/twig_theme_test/templates/twig_theme_test.embed_tag.html.twig
+++ /dev/null
@@ -1,3 +0,0 @@
-{% embed "@twig_theme_test/twig-theme-test-embed-tag-embedded.html.twig" %}
-
-{% endembed %}
diff --git a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module
index 31a1a46930..a8b4086203 100644
--- a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module
+++ b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.module
@@ -73,10 +73,6 @@ function twig_theme_test_theme($existing, $type, $theme, $path) {
     ],
     'template' => 'twig_theme_test.renderable',
   ];
-  $items['twig_theme_test_embed_tag'] = [
-    'variables' => [],
-    'template' => 'twig_theme_test.embed_tag',
-  ];
   return $items;
 }
 
diff --git a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.routing.yml b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.routing.yml
index e671d70fbb..df665c3464 100644
--- a/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.routing.yml
+++ b/core/modules/system/tests/modules/twig_theme_test/twig_theme_test.routing.yml
@@ -69,10 +69,3 @@ twig_theme_test_renderable:
     _controller: '\Drupal\twig_theme_test\TwigThemeTestController::renderable'
   requirements:
     _access: 'TRUE'
-
-twig_theme_test_embed_tag:
-  path: '/twig-theme-test/embed-tag'
-  defaults:
-    _controller: '\Drupal\twig_theme_test\TwigThemeTestController::embedTagRender'
-  requirements:
-    _access: 'TRUE'
diff --git a/core/modules/system/tests/src/Functional/Theme/TwigEnvironmentTest.php b/core/modules/system/tests/src/Functional/Theme/TwigEnvironmentTest.php
deleted file mode 100644
index 26f47e9068..0000000000
--- a/core/modules/system/tests/src/Functional/Theme/TwigEnvironmentTest.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-namespace Drupal\Tests\system\Functional\Theme;
-
-use Drupal\Tests\BrowserTestBase;
-
-/**
- * Tests Twig environment.
- *
- * @group Theme
- */
-class TwigEnvironmentTest extends BrowserTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected static $modules = ['twig_theme_test'];
-
-  /**
-   * Tests template class loading with Twig embed.
-   */
-  public function testTwigEmbed() {
-    $assert_session = $this->assertSession();
-    // Test the Twig embed tag.
-    $this->drupalGet('twig-theme-test/embed-tag');
-    $assert_session->statusCodeEquals(200);
-    $assert_session->responseContains('This line is from twig_theme_test/templates/twig-theme-test-embed-tag-embedded.html.twig');
-  }
-
-}
