Add multilingual support for caching basefield definitions

Created on 20 February 2020, almost 5 years ago
Updated 23 May 2023, over 1 year ago

Problem/Motivation

When a new node is created BaseField definitions are statically cached in ONE language.
There are however use cases where you'd want more than one language for an entity type (E.g. Dutch & English node).

Some more context how I ran into this:

Our default language is English (we don't want to export Dutch config) and we have a language negotiator with a fallback to Dutch (/nl, /fr, /en, /de).

The first time we run this Behat test all is green, the second time it's failing because "Title" appears (instead of "Titel"):

  Scenario: Webmaster can create a promopage
    Given I am logged in as a "webmaster"
    And group content:
      | title      | moderation_state  | langcode |
      | Test group | published         | nl       |
    When I go to "/nl/node/add/promopage"
    Then I should see the text "Titel"

Strangely, the following test is always green:

  Scenario: Webmaster can create a promopage
    Given I am logged in as a "webmaster"
    When I go to "/nl/node/add/promopage" # <= added this
    Then I should see the text "Titel" # <= added this
    And group content:
      | title      | moderation_state  | langcode |
      | Test group | published         | nl       |
    When I go to "/nl/node/add/promopage"
    Then I should see the text "Titel"

When using another role or a specific test user or change a permission the test succeeds (only the first time). Something is caching wrong config translations.

The error only seems to apply only for basefield overrides. EntityFieldManager::getFieldDefinitions() somehow contains their translations in the wrong language.

We can workaround the issue with drush -y config-set language.negotiation url.prefixes.nl ''

Proposed resolution

After some investigation I discovered that EntityFieldManager::getBaseFieldDefinitions caches the definitions in a class property with labels and their translations) only once (for all languages):

  /**
   * {@inheritdoc}
   */
  public function getBaseFieldDefinitions($entity_type_id) {
    // Check the static cache.
    if (!isset($this->baseFieldDefinitions[$entity_type_id])) {
      // Not prepared, try to load from cache.
      $cid = 'entity_base_field_definitions:' . $entity_type_id . ':' . $this->languageManager->getCurrentLanguage()->getId();
      if ($cache = $this->cacheGet($cid)) {
        $this->baseFieldDefinitions[$entity_type_id] = $cache->data;
      }
      else {
        // Rebuild the definitions and put it into the cache.
        $this->baseFieldDefinitions[$entity_type_id] = $this->buildBaseFieldDefinitions($entity_type_id);
        $this->cacheSet($cid, $this->baseFieldDefinitions[$entity_type_id], Cache::PERMANENT, ['entity_types', 'entity_field_info']);
      }
    }
    return $this->baseFieldDefinitions[$entity_type_id];
  }

We should make this language aware.

🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component
Base 

Last updated 1 day ago

Created by

🇧🇪Belgium mpp

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024