diff --git a/core/modules/layout_builder/src/Element/LayoutBuilder.php b/core/modules/layout_builder/src/Element/LayoutBuilder.php index 2e3b021f62..a69a89ab5b 100644 --- a/core/modules/layout_builder/src/Element/LayoutBuilder.php +++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php @@ -11,6 +11,7 @@ use Drupal\Core\Render\Element\RenderElement; use Drupal\Core\Url; use Drupal\layout_builder\Context\LayoutBuilderContextTrait; +use Drupal\layout_builder\LayoutBuilderTranslatablePluginInterface; use Drupal\layout_builder\LayoutTempstoreRepositoryInterface; use Drupal\layout_builder\OverridesSectionStorageInterface; use Drupal\layout_builder\SectionComponent; @@ -281,7 +282,7 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s 'layout_builder_block' => $contextual_link_settings, ]; } - elseif ($this->defaultComponentHasTranslatableSettings($section_storage, $component = $section->getComponent($uuid))) { + elseif ($this->componentHasTranslatableConfiguration($section_storage, $section->getComponent($uuid))) { $build[$region][$uuid]['#contextual_links'] = [ 'layout_builder_block_translation' => $contextual_link_settings, ]; @@ -376,7 +377,7 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s } /** - * Determines if the component in the default translation is translatable. + * Determines if the component is translatable. * * @todo determine how handle other settings that need to be translated * such as the inline blocks use case. @@ -389,16 +390,16 @@ protected function buildAdministrativeSection(SectionStorageInterface $section_s * @return bool * TRUE if the default component has translatable settings, otherwise FALSE. */ - protected function defaultComponentHasTranslatableSettings(SectionStorageInterface $section_storage, SectionComponent $component) { + protected function componentHasTranslatableConfiguration(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']); - } - } + $plugin = $component->getPlugin(); + $contexts = $section_storage->getContexts(); + if ($plugin instanceof LayoutBuilderTranslatablePluginInterface) { + return $plugin->hasTranslatableConfiguration(); + } + elseif ($plugin instanceof ConfigurableInterface) { + $configuration = $plugin->getConfiguration(); + return !empty($configuration['label_display']) && !empty($configuration['label']); } } return FALSE; diff --git a/core/modules/layout_builder/src/LayoutBuilderTranslatablePluginInterface.php b/core/modules/layout_builder/src/LayoutBuilderTranslatablePluginInterface.php new file mode 100644 index 0000000000..d4181ce6d1 --- /dev/null +++ b/core/modules/layout_builder/src/LayoutBuilderTranslatablePluginInterface.php @@ -0,0 +1,20 @@ +buildForm($block, $element, $form_state); $element['revision_log']['#access'] = FALSE; $element['info']['#access'] = FALSE; + if (isset($element['langcode'])) { + $element['langcode'] = FALSE; + } return $element; } @@ -280,4 +287,12 @@ public function saveBlockContent($new_revision = FALSE, $duplicate_block = FALSE } } + /** + * {@inheritdoc} + */ + public function hasTranslatableConfiguration() { + $block_content = $this->getEntity(); + return $block_content->isTranslatable() || (!empty($this->configuration['label_display']) && !empty($this->configuration['label'])); + } + } diff --git a/core/modules/layout_builder/src/Plugin/Block/InlineBlockTranslationForm.php b/core/modules/layout_builder/src/Plugin/Block/InlineBlockTranslationForm.php new file mode 100644 index 0000000000..c8a331ce2c --- /dev/null +++ b/core/modules/layout_builder/src/Plugin/Block/InlineBlockTranslationForm.php @@ -0,0 +1,160 @@ +entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('language_manager')->getCurrentLanguage()->getId(), + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + protected function getEntity() { + $configuration = $this->plugin->getConfiguration(); + if (!empty($configuration['block_serialized'])) { + return unserialize($configuration['block_serialized']); + } + elseif (!empty($configuration['block_revision_id'])) { + /** @var \Drupal\block_content\BlockContentInterface $entity */ + $entity = $this->entityTypeManager->getStorage('block_content')->loadRevision($configuration['block_revision_id']); + if ($entity->hasTranslation($this->currentLangcode)) { + return $entity->getTranslation($this->currentLangcode); + } + else { + return $entity->addTranslation($this->currentLangcode, $entity->toArray()); + } + } + else { + throw new \LogicException("InlineBlockTranslationForm should never be invoked without an available block_content entity"); + } + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + $block = $this->getEntity(); + + // Add the entity form display in a process callback so that #parents can + // be successfully propagated to field widgets. + $form['block_form'] = [ + '#type' => 'container', + '#process' => [[static::class, 'processBlockForm']], + '#block' => $block, + ]; + + return $form; + } + + /** + * Process callback to insert a Custom Block form. + * + * @param array $element + * The containing element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return array + * The containing element, with the Custom Block form inserted. + */ + public static function processBlockForm(array $element, FormStateInterface $form_state) { + /** @var \Drupal\block_content\BlockContentInterface $block */ + $block = $element['#block']; + EntityFormDisplay::collectRenderDisplay($block, 'edit')->buildForm($block, $element, $form_state); + $element['revision_log']['#access'] = FALSE; + $element['info']['#access'] = FALSE; + $element['langcode']['#access'] = FALSE; + return $element; + } + + /** + * {@inheritdoc} + */ + public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { + parent::validateConfigurationForm($form, $form_state); + $block_form = $form['block_form']; + /** @var \Drupal\block_content\BlockContentInterface $block */ + $block = $block_form['#block']; + $form_display = EntityFormDisplay::collectRenderDisplay($block, 'edit'); + $complete_form_state = $form_state instanceof SubformStateInterface ? $form_state->getCompleteFormState() : $form_state; + $form_display->extractFormValues($block, $block_form, $complete_form_state); + $form_display->validateFormValues($block, $block_form, $complete_form_state); + // @todo Remove when https://www.drupal.org/project/drupal/issues/2948549 is closed. + $form_state->setTemporaryValue('block_form_parents', $block_form['#parents']); + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + parent::submitConfigurationForm($form, $form_state); + + $configuration = $this->plugin->getConfiguration(); + // @todo Remove when https://www.drupal.org/project/drupal/issues/2948549 is closed. + $block_form = NestedArray::getValue($form, $form_state->getTemporaryValue('block_form_parents')); + /** @var \Drupal\block_content\BlockContentInterface $block */ + $block = $block_form['#block']; + $form_display = EntityFormDisplay::collectRenderDisplay($block, 'edit'); + $complete_form_state = $form_state instanceof SubformStateInterface ? $form_state->getCompleteFormState() : $form_state; + $form_display->extractFormValues($block, $block_form, $complete_form_state); + + $configuration['block_serialized'] = serialize($block); + $this->plugin->setConfiguration($configuration); + } + +} diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php index e8520bf968..378b56ebc2 100644 --- a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php +++ b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php @@ -412,17 +412,4 @@ public function 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 index d9326afe53..b61d4fdc15 100644 --- a/core/modules/layout_builder/src/TranslatableSectionStorageInterface.php +++ b/core/modules/layout_builder/src/TranslatableSectionStorageInterface.php @@ -28,12 +28,4 @@ public function isTranslatable(); */ 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(); - }