Resolve "Regression: Layout Builder content is no longer translated"

Description

Closes #3585553.

TextExtractor::shouldExtract() checks access('view') on every field, and core's LayoutSectionItemList::defaultAccess() returns AccessResult::forbidden() for every account, including user 1. So layout_builder__layout never passes that check, the layout field is dropped before LbFieldExtractor is reached, and Layout Builder inline blocks are never translated. The translation still saves and reports success, so the failure is silent. Affects 1.3.2 and 1.4.1, with both layout_builder_at and layout_builder_st.

The fix adds ContainerFieldTextExtractorInterface, a marker for extractors whose field holds no text of its own but recurses into contained entities. shouldExtract() skips the field access check for those plugins; the contained entities' own fields still go through shouldExtract() individually, so nothing unviewable is sent to a provider. LbFieldExtractor implements it. ReferenceFieldExtractor recurses too but deliberately does not opt in — view access on an entity reference field is a real permission decision.

No breaking changes: the interface is additive, and existing plugins are unaffected.

Also adds layout_builder_at and layout_builder_st to require-dev so the tests can run, and documents the interface in docs/developers/field-text-extractors.md.

Testing instructions

  1. Install dev dependencies with Composer
  2. Run the 2 new test files via phpunit
  3. Optionally, manually: on a site with layout_builder + layout_builder_at, enable translation for the layout field under Configuration > Regional > Content Language, give a node a layout override containing a content block with body text, and translate it from the Translate tab. Before this change the translation's layout is empty; after it, the translation has its own cloned block with translated text.

Checklist

  • I have linked the related issue in the MR title or description
  • I have performed a self-review of my own code
  • I have added or updated tests, or explained in the description why this change is not covered by tests
  • I have updated documentation for any new or changed functionality
  • I have written testing instructions and verified them locally
  • I have noted any required post-merge steps (config imports, cache rebuilds, manual changes)
  • This MR contains no breaking API or hook changes, or they are explicitly documented in the description

No post-merge steps: no config or schema changes.

AI Compliance

AI Assisted Issue: this issue was generated with AI assistance, but was reviewed and refined by the creator.

Note

Check the one that best describes your usage, or leave all unchecked if AI was not significantly used.

  • AI Assisted Code
    Mainly written by a human; AI used for autocomplete or partial generation under full human supervision.

  • AI Generated Code
    Mainly generated by AI, reviewed and approved by a human before this MR was created.

  • Vibe Coded
    Generated by AI and only functionally reviewed before this MR was created.

Merge request reports

Loading