Problem/Motivation

Drupal\views_bulk_operations\Service\ViewsBulkOperationsActionManager extends core's ActionManager but registers its own plugin manager service (plugin.manager.views_bulk_operations_action) with its own discovery cache bin (views_bulk_operations_action_info). Neither the bin name nor the parent constructor call carries a language key.

Action plugin derivatives whose labels resolve from translatable entity data ? e.g. Drupal\ai_automators\Plugin\Action\RunAutomatorActionDeriver from drupal/ai which builds t('AI: @label', ['@label' => $automator->label()]) ? therefore bake whichever language warmed the cache first. Editors on a German interface continue to see initial cached version instead of per-language override in the VBO bulk-actions dropdown.

This is the same anti-pattern that d.o 3589007 (core ActionManager) and d.o 3038717 (BlockManager) address. Fixing core's plugin.manager.action alone does not propagate to VBO because VBO has a separate service instance and explicitly overrides the cache bin in its constructor.

Steps to reproduce

  1. Multilingual site (e.g. core language + content_translation + a non-default UI language).
  2. Define a VBO action with a label resolved from a translatable entity. Easiest reproduction: drupal/ai 1.3.x+ with an ai_automator whose worker_type is bulk and that has a config-language override on its label.
  3. Place a VBO views_bulk_operations bulk-form field on /admin/content.
  4. Hit /admin/content in English to warm the cache, then switch to /de/admin/content.
  5. Observed: VBO dropdown shows the entity-derived suffix in English. Expected: the suffix resolves in the current interface language.

Proposed resolution

Apply the same pattern d.o 3589007 applies to core ActionManager, directly on ViewsBulkOperationsActionManager so the fix lands independent of core. The patch is self-contained ? it does not require core 3589007 to be merged first:

  • Inject @language_manager as an additional autowired constructor argument.
  • Append :langcode to the cache key passed to setCacheBackend().
  • Override clearCachedDefinitions() to walk every installed language and clear all per-language buckets together (model: LocalActionManager::clearCachedDefinitions()).

When core 3589007 lands, this contribution can be simplified later (forward @language_manager to parent::__construct(), drop the local property), but no change here is blocked on core.

Remaining tasks

User interface changes

API changes

Data model changes

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

petar_basic created an issue. See original summary.

petar_basic’s picture

Issue summary: View changes

petar_basic’s picture

Assigned: petar_basic » Unassigned
Status: Needs work » Needs review
StatusFileSize
new2.84 KB

Approach is self-contained, doesn't depend on core d.o 3589007 (MR !15745):

- Adds @language_manager as an autowired constructor arg (defaulted to NULL for BC).
- Appends :langcode to the discovery cache bin so each interface language gets its own bucket.
- Overrides clearCachedDefinitions() to walk all installed languages and clear every per-language bucket together (mirrors LocalActionManager).

Adding a patch for use with composer patches.

graber’s picture

Status: Needs review » Needs work

Added a comment on the MR.

petar_basic’s picture

Status: Needs work » Needs review
StatusFileSize
new3.63 KB

Addressed review:

  • #1 promotion — done
  • #2 nullable kept — must mirror parent. The related core MR !15745 / d.o 3589007 adds
    protected
      ?LanguageManagerInterface $languageManager = NULL

    to the parent ActionManager for the standard core BC/deprecation cycle. Child's type must be invariant with
    parent's.

  • #3 ::class — done

Two phpstan-baseline entries added with explanatory links:

  • $this->definitions = NULL (same pattern core itself uses in DefaultPluginManager::clearCachedDefinitions()) trips assign.propertyType
    because the inherited DiscoveryCachedTrait::$definitions @var says array. Pending d.o
    3590805
    (docblock fix).
  • parent::__construct(..., $languageManager) is a 4-arg call against stock core's 3-arg ActionManager::__construct; the 4th arg is silently dropped at runtime on stock core and consumed by the new constructor signature once d.o 3589007 lands. Pending that MR.
fago’s picture

Status: Needs review » Needs work

> The related core MR !15745 / d.o 3589007 adds protected ?LanguageManagerInterface $languageManager = NULL to the parent ActionManager for the standard core BC/deprecation cycle.

I'd not see why are we doing that, the service is always available. Let's discuss and clarify there and take over the solution here then.