yml / yaml

SetValueIfEmptyCommand.php
<?php

declare(strict_types=1);

namespace Drupal\my_module\Ajax;

use Drupal\Core\Ajax\CommandInterface;

/**
 * Ajax command: fill empty form elements with a predefined value.
 *
 * This command targets one or more form elements via a CSS selector and sets
 * their value only if the current value is empty (after trimming).
 *
 * The command also triggers `input` and `change` events so Drupal behaviors and
 * other listeners react as if the user entered the value manually.
 */
final class SetValueIfEmptyCommand implements CommandInterface {

  /**
   * The Ajax command name used by Drupal.AjaxCommands.
   */
  public const COMMAND = 'setValueIfEmpty';

  /**
   * Default selector used when none is provided.
   */
  public const DEFAULT_SELECTOR = '[data-my-fill-target]';

  /**
   * Creates a command instance.
   *
   * @param string $fillValue
   *   The value to set when the target element is empty.
   * @param string|null $targetSelector
   *   CSS selector for the target elements. If omitted, DEFAULT_SELECTOR is used.
   */
  public function __construct(
    protected string $fillValue,
    protected ?string $targetSelector = null,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function render(): array {
    return [
      'command' => self::COMMAND,
      'selector' => $this->targetSelector ?? self::DEFAULT_SELECTOR,
      'value' => $this->fillValue,
    ];
  }

}
media_fill_if_empty.js
/**
 * @file Field empty check.
 */
(function (Drupal) {
  'use strict';

  Drupal.AjaxCommands.prototype.setValueIfEmpty = function (ajax, response) {
    const targetSelector = response && response.selector ? response.selector : '';
    const fillValue = response && typeof response.value === 'string' ? response.value : '';

    if (!targetSelector) {
      return;
    }

    const elements = document.querySelectorAll(targetSelector);
    for (const element of elements) {
      let currentValue = '';

      if (typeof element.value === 'string') {
        currentValue = element.value.trim();
      }
      else if (element.isContentEditable) {
        currentValue = (element.textContent || '').trim();
      }

      if (currentValue !== '') {
        continue;
      }

      if (typeof element.value === 'string') {
        element.value = fillValue;
      }
      else if (element.isContentEditable) {
        element.textContent = fillValue;
      }
      else {
        continue;
      }

      element.dispatchEvent(new Event('input', { bubbles: true }));
      element.dispatchEvent(new Event('change', { bubbles: true }));
    }
  };

})(Drupal);
my_module.libraries.yml
set_value_if_empty:
  js:
    js/set_value_if_empty.js: {}
  dependencies:
    - core/drupal
    - core/drupal.ajax
MyResponse.php
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\my_module\Ajax\SetValueIfEmptyCommand;

$response = new AjaxResponse();

// Example: fill a media name field if it's empty.
$fill_value = 'foo-bar';

// Selector for a specific element in this use-case.
$target_selector = '[data-drupal-selector$="my_field"]';

$response->addAttachments([
  'library' => [
    'my_module/set_value_if_empty',
  ],
]);

$response->addCommand(new SetValueIfEmptyCommand($fill_value, $target_selector));

return $response;

config/sync/language/your_translation_language/ 

core.entity_view_display.node.my_content_type.full.yml
third_party_settings:
  layout_builder:
    sections:
      1:
        layout_settings:
          label: 'My second section translation, here'
        components:
          4a5d3bb1-32d3-4a3c-a69f-6ee702a868ff:
            configuration:
              # Original: 'My first block'
              label: 'My first block that is placed in layoutbuilder translation, here'
          c1bbc85f-bb8b-4e72-9e9e-a2ccdf190646:
            configuration:
              # Original: 'My second block'
              label: 'My second block that is placed in layoutbuilder translation, here'

Here is the original config file:

core.entity_view_display.node.my_content_type_original_language.full.yml
uuid: bedb3535-d6f2-4aae-b2cb-7f8f6e82bd5a
langcode: en
status: true
dependencies:
  config:
    - core.entity_view_mode.node.full
    - field.field.node.my_content_type.field_content
    - field.field.node.my_content_type.field_date
    - node.type.my_content_type
  module:
    - my_module
  theme:
    - my_theme
third_party_settings:
  layout_builder:
    enabled: true
    allow_custom: true
    sections:
      -
        layout_id: onecol
        layout_settings:
          label: 'My first section'
          context_mapping: {  }
        components:
          29a62ef3-00c8-40d5-8e9d-b6c3de187c10:
            uuid: 29a62ef3-00c8-40d5-8e9d-b6c3de187c10
            region: col1
            configuration:
              id: my_base_intro_block
              label: 'Intro block'
              label_display: '0'
              provider: my_base
              context_mapping:
                entity: layout_builder.entity
            weight: 0
        third_party_settings: {  }
      -
        layout_id: twocol
        layout_settings:
          label: 'My second section'
          context_mapping: {  }
        components:
          dc449aee-2be4-43d3-892e-ffd4cbe44fc0:
            uuid: dc449aee-2be4-43d3-892e-ffd4cbe44fc0
            region: col2
            configuration:
              id: 'entity_view:node'
              label: 'My first block'
              label_display: visible
              provider: ctools
              context_mapping:
                entity: layout_builder.entity
              view_mode: information
            weight: 0
          c1bbc85f-bb8b-4e72-9e9e-a2ccdf190646:
            uuid: c1bbc85f-bb8b-4e72-9e9e-a2ccdf190646
            region: col1
            configuration:
              id: 'field_block:node:my_content_type:field_content'
              label: 'My second block'
              label_display: visible
              provider: layout_builder
              context_mapping:
                entity: layout_builder.entity
                view_mode: view_mode
              formatter:
                type: text_default
                label: above
                settings: {  }
                third_party_settings: {  }
            weight: 0
        third_party_settings: {  }
26.09.2025 | Lothar Ferreira Neumann

How to translate default layout components

Example.php
<?php

declare(strict_types=1);

namespace Drupal\my_module;

use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

class Example {

  public function __construct(
    #[Autowire(service: 'current_user')]
    private readonly AccountInterface $currentUser,
  ) {
  }

  public function getCurrentUser(): AccountInterface {
    return $this->currentUser;
  }

}

my_module.services.yml
services:
  my_module.example:
    class: Drupal\my_module\Service\Example
    autowire: true
  Drupal\my_module\Service\Example: '@my_module.example'

my_module.links.task.yml
my_module.my_local_task_link:
  route_name: my_module.custom_route
  title: "Title"
  base_route: route_where.local_task.should_be_placed
13.11.2025 | Mathias Grab

How to create local task links