SDC ComponentElement: Transform slots TranslatableMarkup values to #markup instead of throwing an exception

Created on 5 February 2025, 5 months ago

Problem/Motivation

This can be seen as a follow-up for #3391702 πŸ› SDC ComponentElement: Transform slots scalar values to #plain_text instead of throwing an exception Fixed

On that issue, it was proposed that #slots were made more resilient and forgiving by accepting non-scalar values.

Another common Drupalism we might be facing on slots are translated strings, which

  1. Can include simple inline HTML tags, like <br> or <em>
  2. Will take the shape of a TranslatableMarkup, which will fail both the is_scalar and Element::isRenderArray checks and, as such, will be rejected witj an exception

Steps to reproduce

Try to feed a translated string (with or without HTML) to a slot:

      return [
        '#type' => 'component',
        '#component' => 'theme:icon_message',
        '#props' => [
          'icon' => $this->options['icon'],
        ],
        '#slots' => [
          'message' => $this->t('No @type were found.<br> Please try again later.', ['@type' => $this->options['content_type']]),
        ]
      ];

A 'Unable to render component "%s". A render array or a scalar is expected for the slot "%s" when using the render element with the "#slots" property', will be thrown.

Proposed resolution

As we did with scalars, wrap the translatable markup in order to make it pass the checks and render.

Remaining tasks

Propose a MR

User interface changes

None

Introduced terminology

None

API changes

None

Data model changes

None

Release notes snippet

✨ Feature request
Status

Active

Version

11.0 πŸ”₯

Component

single-directory components

Created by

πŸ‡ͺπŸ‡ΈSpain idiaz.roncero Madrid

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @idiaz.roncero
  • πŸ‡ͺπŸ‡ΈSpain idiaz.roncero Madrid
  • πŸ‡ͺπŸ‡ΈSpain idiaz.roncero Madrid
  • πŸ‡ͺπŸ‡ΈSpain idiaz.roncero Madrid

    Submitted MR that I have tested locally and works.

  • Pipeline finished with Failed
    5 months ago
    Total: 399s
    #415549
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Thank you for opening.

    Lets add some test coverage for the proposed change.

  • Pipeline finished with Failed
    5 months ago
    Total: 436s
    #416587
  • Pipeline finished with Failed
    5 months ago
    Total: 98s
    #416616
  • Pipeline finished with Success
    5 months ago
    #416640
  • πŸ‡ͺπŸ‡ΈSpain idiaz.roncero Madrid

    Added test, executed pipeline and it passed.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Removing tests tag as the test-only run shows the coverage

    1) Drupal\KernelTests\Components\ComponentRenderTest::testRender
    Drupal\Core\Render\Component\Exception\InvalidComponentDataException: Unable to render component "sdc_test:my-banner". A render array or a scalar is expected for the slot "banner_body" when using the render element with the "#slots" property
    

    Summary seems clear with clear proposal that lines up with the code change.

    Code change seems pretty straightforward and see no objection.

    LGTM

  • πŸ‡¨πŸ‡­Switzerland berdir Switzerland

    Can confirm that this fixes an issue I see with navigation:title the entity returns a TranslatableMarkup object.

    Left one comment on the MR whether this should be expanded to MarkupInterface or even Stringable.

  • πŸ‡¬πŸ‡§United Kingdom catch

    I think we should use MarkupInterface here.

  • πŸ‡¨πŸ‡­Switzerland berdir Switzerland

    Updated, also shortened the test method description, it was already over 80 characters and that made it even longer.

  • Pipeline finished with Success
    4 months ago
    Total: 457s
    #459229
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave
    1) Drupal\KernelTests\Components\ComponentRenderTest::testRender
    Drupal\Core\Render\Component\Exception\InvalidComponentDataException: Unable to render component "sdc_test:my-banner". A render array or a scalar is expected for the slot "banner_body" when using the render element with the "#slots" property
    /builds/issue/drupal-3504477/core/lib/Drupal/Core/Render/Element/ComponentElement.php:118
    /builds/issue/drupal-3504477/core/lib/Drupal/Core/Render/Element/ComponentElement.php:65
    /builds/issue/drupal-3504477/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php:107
    /builds/issue/drupal-3504477/core/lib/Drupal/Core/Render/Renderer.php:830
    /builds/issue/drupal-3504477/core/lib/Drupal/Core/Render/Renderer.php:387
    /builds/issue/drupal-3504477/core/lib/Drupal/Core/Render/Renderer.php:459
    /builds/issue/drupal-3504477/core/lib/Drupal/Core/Render/Renderer.php:203
    /builds/issue/drupal-3504477/core/tests/Drupal/KernelTests/Components/ComponentKernelTestBase.php:95
    /builds/issue/drupal-3504477/core/lib/Drupal/Core/Render/Renderer.php:593
    /builds/issue/drupal-3504477/core/tests/Drupal/KernelTests/Components/ComponentKernelTestBase.php:95
    /builds/issue/drupal-3504477/core/tests/Drupal/KernelTests/Components/ComponentRenderTest.php:313
    /builds/issue/drupal-3504477/core/tests/Drupal/KernelTests/Components/ComponentRenderTest.php:45
    ERRORS!
    

    Shows the test coverage

    Believe this would solve a problem I see on my patterns theme were I have to pass #markup => content, in the twig file.

    Change makes sense.

  • Status changed to RTBC 3 months ago
  • πŸ‡³πŸ‡ΏNew Zealand quietone

    I didn't find any problems with this and all questions are answered.

  • πŸ‡³πŸ‡ΏNew Zealand quietone

    Trying to improve the title

  • πŸ‡«πŸ‡·France pdureau Paris

    Hello,

    Thanks for the work.

    The current (11.x) logic is:

          if (\is_scalar($slot_value)) {
            $slot_value = [
              "#plain_text" => (string) $slot_value,
            ];
          }

    Obviously, it was not enough.

    So, this MR is adding

          if ($slot_value instanceof MarkupInterface) {
            $slot_value = [
              "#markup" => $slot_value,
            ];
          }
    

    On UI Patterns 2, they have added something a bit different:

        if (($value instanceof TwigMarkup) ||  ($value instanceof MarkupInterface)) {
          return ['#children' => $value];
        }
        if ($value instanceof \Stringable) {
          return [
            '#plain_text' => (string) $value,
          ];
        }
    

    I don't know which one is better, maybe we a mix of both would be great. I will check with them.

  • πŸ‡«πŸ‡·France pdureau Paris

    I keep the issue assigned to me until I have an answer ;)

  • The Needs Review Queue Bot β†’ tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

    This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

    Consult the Drupal Contributor Guide β†’ to find step-by-step guides for working with issues.

Production build 0.71.5 2024