Problem/Motivation
TokenTokenInfoHooks::tokenInfoAlter() automatically registers a language chained token ([entity_type:language:*]) for every content entity token type that doesn't already define its own.
This registration does not check whether the entity type actually has a langcode field. When the token is resolved, TokenTokensHooks::tokens() reads the field directly instead of using the entity's \Drupal\Core\Entity\EntityInterface::language() method.
Not every content entity is required to declare a langcode entity key / base field - it's entirely valid for a simple, non-translatable content entity to omit it. For such entities this throws:
php.ERROR: InvalidArgumentException: Field langcode is unknown. in Drupal\Core\Entity\ContentEntityBase->getTranslatedField() (line 630 of /var/www/html/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php).
Note that for the field tokens it is already using this method for getting a proper language instead of direct access: TokenTokensHooks::fieldTokens()
Steps to reproduce
- Define a content entity type that does not declare a
langcodeentity key - Save an instance of this entity.
- Resolve any token from its token tree that touches the auto-registered
languagesub-tree, e.g:
<?php use Drupal\module\Entity\MyEntity; use Drupal\Core\Render\BubbleableMetadata; $entity = MyEntity::load(1); $replacements = \Drupal::token()->generate( 'my_entity', ['language:langcode' => '[my_entity:language:langcode]'], ['my_entity' => $entity], [], new BubbleableMetadata(), );This also happens implicitly when eagerly resolving a full token tree with
'values' => TRUEviaTreeBuilder::buildTree()(e.g. any token browser/preview UI built on top of Token module). Field langcode is unknown.is thrown.
Proposed resolution
Replace the direct field access with the entity's own language method:
$language_options = array_merge($options, [
'langcode' => $entity->language()->getId(),
]);
Remaining tasks
User interface changes
API changes
Data model changes
Issue fork token-3611063
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
Comment #3
niklanComment #4
csakiistvanComment #5
csakiistvanEnvironment
Prerequisites
token_module_testtesting submodule, which provides a content entity type (token_test_no_langcode) that does not declare alangcodeentity key:Steps
language()method instead of reading thelangcodefield directly when resolving[entity:language:*]chained tokens.ddev drush cr[token_test_no_langcode:language:langcode]token against a saved instance of the entity (e.g. via\Drupal::token()->generate()).Expected results
und).Actual results
Before the fix, resolving the
[token_test_no_langcode:language:langcode]token threwInvalidArgumentException: Field langcode is unknown., since the code read thelangcodefield directly on an entity type that doesn't declare one. After applying the fix, the token resolved correctly toundwith no exception.Testing produced with the assistance of an LLM.